shiro

Posted xiongyungang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shiro相关的知识,希望对你有一定的参考价值。

Subject

  • 即当前的操作的“用户”,该用户是一个抽象概念,由 SecurityManager 管理,所有 Subject 都绑定到 SecurityManager

SecurityManager

  • 安全管理器,所以安全相关的交互都会经过 SecurityManager ,相当于springmvc中前端控制器DispatcherServlet;

Realm

  • 域,SecurityManager从Realm获取安全数据(如用户、角色、权限)进行校验,可以把 Realm 看成 DataSource,即安全数据源

过程

1.应用代码通过 Subject 来进行认证和授权,而 Subject 又委托给 SecurityManager;
2.我们需要给 Shiro 的 SecurityManager 注入 Realm,从而让 SecurityManager 能得到合法的用户及其权限进行判断。
技术图片


整合springboot

依赖

		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>1.3.2</version>
		</dependency>

配置

package com.hd.config;

import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;

@Configuration
public class ShiroConfig {
    /**
     * 配置Shiro的Web过滤器,拦截浏览器请求并交给SecurityManager处理
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);

		/*
		 * 添加shiro内置过滤器:
		 * 		anon:无需认证
		 * 		authc:必须认证才可以访问
		 * 		user:如果使用remember的功能才可以访问
		 * 		perms:该资源必须得到资源权限才可以访问
		 * 		roles:该资源必须得到角色权限才可以访问
		 */
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
        filterChainDefinitionMap.put("/", "anon");
        filterChainDefinitionMap.put("/css/**","anon");
        filterChainDefinitionMap.put("/js/**","anon");
        filterChainDefinitionMap.put("/img/**","anon");
        filterChainDefinitionMap.put("/register.html","anon");
        filterChainDefinitionMap.put("/public/login.html","anon");
        filterChainDefinitionMap.put("/userlogin","anon");
        filterChainDefinitionMap.put("/error/**","anon");
        filterChainDefinitionMap.put("/findOne","anon");

        //设置授权
        filterChainDefinitionMap.put("/user/**","roles[admin]");

        filterChainDefinitionMap.put("/**","authc");

        //修改跳转页面
        shiroFilterFactoryBean.setLoginUrl("/login.html");
        //自定义授权页面
        shiroFilterFactoryBean.setUnauthorizedUrl("/unAuth.html");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return shiroFilterFactoryBean;
    }

    /**
     * 创建DefaultWebSecurityManager
     * @param userRealm
     * @return
     */
    @Bean(name="securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联realm
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    /**
     * 创建realm
     * @return 用户realm
     */
    @Bean(name="userRealm")
    public UserRealm getRealm(){
        return new UserRealm();
    }
}

realm

package com.hd.config;

import com.hd.entity.Role;
import com.hd.entity.User;
import com.hd.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.HashSet;

public class UserRealm extends AuthorizingRealm {
    @Autowired
    UserService userService;

    /**
     * 授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("授权入口");
        User user = (User) SecurityUtils.getSubject().getPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        // 获取用户权限
        Role role = userService.findRoleByName(user.getName());
        //todo:role=null ??
        // 设置该用户拥有的权限
        HashSet<String> roles = new HashSet<>();
        roles.add(role.getRole_name());
        info.setRoles(roles);
        return info;
    }

    /**
     * 认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //  获取用户名
        String userName = (String)authenticationToken.getPrincipal();
        //  查询有无该用户
        User user = userService.findUserByName(userName);
        if (null == user)
        {
            // 没有该用户
            return null;
        }
        //  有该用户, 判断密码
        /**
         * 参数1: 从数据库获取的userduix
         * 参数2: 密码
         * 参数3: 当前realm名称
         */
        return new SimpleAuthenticationInfo(user,user.getPassword(),getName());
    }
}

应用

	/**
	 *	登录验证
	 *
	 * @param username	用户名
	 * @param password	密码
	 * @param model
	 * @return
	 */
	@PostMapping(value = "/userlogin")
	public String user_login(String username, String password, Model model){
		UsernamePasswordToken token = new UsernamePasswordToken(username,password);
		Subject currentUser = SecurityUtils.getSubject();

		try {
			//主体提交登录请求到SecurityManager
			currentUser.login(token);
		}catch (IncorrectCredentialsException ice){
			model.addAttribute("msg","密码不正确");
		}catch(UnknownAccountException uae){
			model.addAttribute("msg","账号不存在");
		}catch(AuthenticationException ae){
			model.addAttribute("msg","状态不正常");
		}
		if(currentUser.isAuthenticated()){
			System.out.println("认证成功");
			//model.addAttribute("currentUser", currentUser());
			return "/rpdtester"; //todo:返回json,保存用户登录信息
		}else{
			token.clear();
			return "/login.html";
		}
	}

以上是关于shiro的主要内容,如果未能解决你的问题,请参考以下文章

Shiro权限管理2.Shiro的HelloWorld程序

springboot配置shiro权限管理,网搜搜采集网站权限控制代码

Shiro原理流程,代码示例

Shiro原理流程,代码示例

如何更正 Shiro 注销代码(执行注销后用户仍然可以访问页面)?

debug代码解析shiro认证流程