spring boot 整合redis+shiro在自定义Realm不能使用@Autowired注解

版权声明:一家之言,看完就忘了吧 https://blog.csdn.net/leisure_life/article/details/82688279

刚开始spring boot 整合shiro缓存使用的是ehcache,自动注入userService如下,没有问题

@Autowired
@Lazy
private SysUserService userService;

当将缓存换成了redis后,该注解无效,一直空指针,大概是因为 Spring 加载顺序等原因
解决方案是在自定义Realm中不直接使用@Autowired,而是将userService定义成成员变量,再

     private SysUserService userService;
        @Autowired
        private void setSysUserService(SysUserService userService) {
            this.userService = userService;
        }

另外一个点就是SecurityManager的setRealm方法,不能直接new 自定义Realm,而是要以参数的形式传入

 @Bean
    public SecurityManager securityManager(@Qualifier("myShiroRealm")MyShiroRealm myShiroRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置realm.
        securityManager.setRealm(myShiroRealm);

        securityManager.setCacheManager(cacheManager());

        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

附完整ShiroConfig

package cn.com.suntree.cmp.config;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;

import lombok.extern.log4j.Log4j2;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

import cn.com.suntree.cmp.entity.Power;
import cn.com.suntree.cmp.entity.Role;
import cn.com.suntree.cmp.entity.SysUser;
import cn.com.suntree.cmp.service.SysUserService;

import javax.annotation.Resource;

@Log4j2
@Configuration
public class ShiroConfig {

/**
 @Autowired
 @Lazy private SysUserService userService;
 */

    /**
     * @param securityManager
     * @return 拦截工厂配置
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        HashMap<String, String> filterMap = new LinkedHashMap<>();
        filterMap.put("/api/city/page", "anon");
        filterMap.put("/api/**", "authc");
        //filterMap.put("/logout", "logout");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setUnauthorizedUrl("/error");
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        return shiroFilterFactoryBean;
    }

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

    /**
     * 身份认证realm; (这个需要自己写,账号密码校验;权限等)
     *
     * @return
     */
    @Bean
    public MyShiroRealm myShiroRealm() {
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        myShiroRealm.setCredentialsMatcher(credentialsMatcher());
        myShiroRealm.setCacheManager(cacheManager());//設置緩存
        return myShiroRealm;
    }

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

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

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

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

    /**
     * 限制同一账号登录同时登录人数控制
     *
     * @return
     */
    @Bean
    public KickoutSessionControlFilter kickoutSessionControlFilter() {
        KickoutSessionControlFilter kickoutSessionControlFilter = new KickoutSessionControlFilter();
        kickoutSessionControlFilter.setCacheManager(cacheManager());
        kickoutSessionControlFilter.setSessionManager(sessionManager());
        kickoutSessionControlFilter.setKickoutAfter(false);
        kickoutSessionControlFilter.setMaxSession(1);
        kickoutSessionControlFilter.setKickoutUrl("/auth/kickout");
        return kickoutSessionControlFilter;
    }

    /***
     * 授权所用配置
     *
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }

    /**
     * @param securityManager
     * @return 授权注解支持
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

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

    /**
     * @return 密码匹配器
     */
    @Bean
    public CredentialsMatcher credentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        return hashedCredentialsMatcher;
    }


    /**
     * 自定义 - 数据域
     */
    public class MyShiroRealm extends AuthorizingRealm {

        private SysUserService userService;

        @Autowired
        private void setSysUserService(SysUserService userService) {
            this.userService = userService;
        }

        /**
         * @param principalCollection
         * @return
         * @implNote 功能授权
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            SysUser user = (SysUser) principalCollection.getPrimaryPrincipal();
            SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
            user = userService.getUserInfoByUserId(user.getUserID());
            List<Role> roleList = user.getRoleList();
            for (Role role : roleList) {
                authorizationInfo.addRole(role.getRoleName());
                for (Power permission : role.getPowerList()) {
                    authorizationInfo.addStringPermission(permission.getUrl());
                }
            }
            return authorizationInfo;
        }

        /**
         * @param authenticationToken
         * @return
         * @throws AuthenticationException
         * @implNote 身份认证
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            String acc = (String) authenticationToken.getPrincipal();
            SysUser user = userService.getUserByAcc(acc);

            if (user == null) {
                throw new UnknownAccountException();
            } else if ("0".equals(user.getIsLock())) {
                throw new LockedAccountException(); // 帐号冻结,非正常
            } else {
                SimpleAuthenticationInfo simpleAuthenticationInfo =
                        new SimpleAuthenticationInfo(user, user.getPasswd(), this.getName());
                return simpleAuthenticationInfo;
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/leisure_life/article/details/82688279
今日推荐