SpringBoot整合Shiro

Posted laoash

tags:

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

SpringBoot整合Shiro

依赖:

<!-- 权限管理 -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.4.0</version>
</dependency>

如果使用redis来管理shiro时,需要添加依赖:

<!--redis管理shiro-->
<dependency>
    <groupId>org.crazycake</groupId>
    <artifactId>shiro-redis</artifactId>
    <version>2.8.24</version>
</dependency>

如果在thymeleaf中使用shiro,需要添加依赖:

<!--在thymeleaf使用shiro-->
<dependency>
    <groupId>com.github.theborakompanioni</groupId>
    <artifactId>thymeleaf-extras-shiro</artifactId>
    <version>2.0.0</version>
</dependency>

1、从数据库读取数据,实现登录认证、授权

创建类继承AuthorizingRealm,重写doGetAuthorizationInfo方法和doGetAuthenticationInfo方法

public class MyShiroRealm extends AuthorizingRealm {
    private final static Logger logger = LoggerFactory.getLogger(MyShiroRealm.class);

    @Resource
    private UserService userService;
    @Resource
    private RoleService roleService;

    /**
     * 授权
     *
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        logger.info("-------->从数据库获取角色权限");
        if (principals == null) {
            return null;
        }
        //获取用户名
        String userName = (String) principals.getPrimaryPrincipal();
        //根据用户名获取角色
        Role role = roleService.getRoleByUserName(userName);
        //创建授权信息
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        //获取角色拥有的权限
        List<Permission> permissions = roleService.getPermissionByRoleId(role.getRoleId());
        //授权
        simpleAuthorizationInfo.addRole(role.getRoleName());
        for (Permission permission : permissions) {
            simpleAuthorizationInfo.addStringPermission(permission.getPermissionName());
        }
        return simpleAuthorizationInfo;
    }

    /**
     * 登录认证
     * 1.登录错误超过5次被锁定一个小时
     * 2.一个小时之后次数恢复5次
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        logger.info("------>" + SecurityUtils.getSubject().getSession().getId());
        //获取用户名密码
        UsernamePasswordToken token1 = (UsernamePasswordToken) token;
        String userName = token1.getUsername();
        String password = String.valueOf(token1.getPassword());

        //根据用户名获取对应的用户信息
        User user = userService.getByUserName(userName);
        if (user != null) {
            if (user.getStatus() == 0) {
                //账户被锁定
                throw new LockedAccountException();
            }
            //用用户名当盐值
            ByteSource credentialsSalt = ByteSource.Util.bytes(userName);
            //加密
            Md5Hash md5Hash = new Md5Hash(password, credentialsSalt, 1024);
            Map<String, String> map = new HashMap<>(16);
            map.put("username", userName);
            map.put("password", md5Hash.toString());
            //用户名,密码校验
            User userInfo = userService.getByUserNameAndPassword(map);

            if (userInfo == null) {
                //密码错误
                throw new IncorrectCredentialsException();
            }
            //修改最后登录时间
            userInfo.setGmtModified(new Date());
            userService.updateLastTime(userInfo);
            return new SimpleAuthenticationInfo(userName, password, getName());
        } else {
            //未知账户
            throw new UnknownAccountException();
        }
    }
}

2、shiro配置

使用redis缓存session

@Configuration
public class ShiroConfig {

    private final static Logger logger = LoggerFactory.getLogger(ShiroConfig.class);

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private int port;

    @Value("${spring.redis.password}")
    private String password;


    /**
     * 配置shiro过滤器
     *
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //设置默认登录的url
        shiroFilterFactoryBean.setLoginUrl("/");
        //设置成功之后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("");
        //设置未授权界面,发现好像没用
        shiroFilterFactoryBean.setUnauthorizedUrl("");
        //自定义拦截器
        //Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>();
        //shiroFilterFactoryBean.setFilters(filtersMap);
        //权限控制
        Map<String, String> filterChainMap = new LinkedHashMap<String, String>();
        //静态资源
        filterChainMap.put("/css/**", "anon");
        filterChainMap.put("/js/**", "anon");
        filterChainMap.put("/images/**", "anon");
        filterChainMap.put("/img/**", "anon");

        filterChainMap.put("/**/*.do", "anon");
        filterChainMap.put("/manage/login.html", "anon");
        filterChainMap.put("/user/login", "anon");
        //退出拦截
        filterChainMap.put("/user/logout", "logout");

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

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);
        return shiroFilterFactoryBean;
    }

    /**
     * 自定义的Realm
     *
     * @return
     */
    @Bean(name = "shiroRealm")
    public MyShiroRealm shiroRealm() {
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        myShiroRealm.setAuthorizationCachingEnabled(true);
        return myShiroRealm;
    }

    /**
     * 配置安全管理器
     *
     * @return
     */
    @Bean
    public SecurityManager securityManager(MyShiroRealm shiroRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //设置realm
        securityManager.setRealm(shiroRealm);
        // 自定义缓存实现 使用redis
        securityManager.setCacheManager(cacheManager());
        // 自定义session管理 使用redis
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

    /**
     * 配置shiro redisManager
     * 使用的是shiro-redis开源插件
     *
     * @return
     */
    private RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(host);
        redisManager.setPort(port);
        // 配置缓存过期时间
        redisManager.setExpire(1800);
        redisManager.setTimeout(0);
        return redisManager;
    }

    /**
     * cacheManager 缓存 redis实现
     * 使用的是shiro-redis开源插件
     *
     * @return
     */
    private RedisCacheManager cacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        return redisCacheManager;
    }

    /**
     * Session Manager
     * 使用的是shiro-redis开源插件
     *
     * @return
     */
    @Bean
    public MySessionManager sessionManager() {
        MySessionManager sessionManager = new MySessionManager();
        sessionManager.setSessionDAO(redisSessionDAO());
        return sessionManager;
    }

    /**
     * RedisSessionDAO shiro sessionDao层的实现 通过redis
     * 使用的是shiro-redis开源插件
     *
     * @return
     */
    @Bean
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }

    /**
     * 开启Shiro的注解
     *
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * Shiro生命周期处理器
     */
    @Bean
    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 设置一个cookie的名称,防止session的id 重复
     */
    @Bean
    public SimpleCookie simpleCookie() {
        return new SimpleCookie("REDISSESSION");
    }

    /**
     * thymeleaf 使用 shiro
     *
     * @return
     */
    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }
}

3、解决每次访问创建session

创建类继承DefaultWebSessionManager,重写retrieveSession方法

public class MySessionManager extends DefaultWebSessionManager {
    @Override
    protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException {
        //获取sessionId
        Serializable sessionId = getSessionId(sessionKey);
        ServletRequest request = null;
        //判断类型
        if (sessionKey instanceof WebSessionKey) {
            //类型相同可以强转
            request = ((WebSessionKey) sessionKey).getServletRequest();
        }
        //如果request,sessionId都不为空,从request中获取session
        if (request != null && sessionId != null) {
            Session session = (Session) request.getAttribute(sessionId.toString());
            if (session != null) {
                return session;
            }
        }
        //检索会话
        Session session = super.retrieveSession(sessionKey);
        if (request != null && sessionId != null) {
            request.setAttribute(sessionId.toString(), session);
        }
        return session;
    }
}

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

SpringBoot整合Shiro实现权限控制

SpringBoot整合Shiro实现权限控制

SpringBoot学习- 8整合Shiro

Shiro整合Springboot缓存之Redis实现

Springboot整合Shiro

SpringBoot整合Shiro 四:认证+授权