zoukankan      html  css  js  c++  java
  • 修改记录-优化后(springboot+shiro+session+redis+ngnix共享)

    1.普通用户实现redis共享session

    1.配置

    #cache指定缓存类型
    spring.cache.type=REDIS
    
    #data-redis
    spring.redis.database=15  //单节点配置  可择库
    spring.redis.password=
    spring.redis.host=192.168.210.*** //单节点配置
    spring.redis.port=6379
    spring.redis.timeout=2000
    spring.redis.jedis.pool.max-active=8
    spring.redis.jedis.pool.max-idle=8
    spring.redis.jedis.pool.max-wait=-1
    spring.redis.jedis.pool.min-idle=0
    #集群配置 配置后单节点失效 #spring.redis.cluster.nodes=192.168.43.**:7000,192.168.43.**:7001,192.168.43.**:7000,192.168.43.**:7001,192.168.43.**:7000,192.168.43.**:7001 #spring.redis.cluster.max-redirects=3
    #主从节点配置 配置后单节点,集群配置都失效
    #spring.redis.sentinel.master=mymaster
    #spring.redis.sentinel.nodes=192.168.210.**:26379
     
    #session share unit MINUTES 指定session在redis中过期时间
    session.timeout
    =3
    #cacheTimeOut unit MINUTES 指定权限信息在redis中过期时间
    cache.timeout
    =12

    2.开启缓存

    @SpringBootApplication
    @EnableCaching //开启缓存
    public class OneserviceManagerApplication {
        public static void main(String[] args) {
            SpringApplication.run(OneserviceManagerApplication.class, args);
        }
    }

    3.编写RedisConfig.java配置类,主要作用是对象序列化

    package com.ch.evaluation.config.redis;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cache.annotation.CachingConfigurerSupport;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    
    @Configuration
    public class RedisConfig extends CachingConfigurerSupport {
    
        @Autowired
        private RedisConnectionFactory redisConnectionFactory;
    
        /**
         * 获取RedisTemplate对象,处理Redis数据,并且进行最佳序列化
         * @return
         */
        @Bean(name="redisTemplate")
        public RedisTemplate<String, Object> redisTemplate() {
            RedisTemplate<String, Object> template = new RedisTemplate<>();
            //手动序列化
            JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();
            StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
            template.setKeySerializer(stringRedisSerializer);
            template.setValueSerializer(jdkSerializationRedisSerializer);
            template.setHashKeySerializer(stringRedisSerializer);
            template.setHashValueSerializer(jdkSerializationRedisSerializer);
            //连接Redis
            template.setConnectionFactory(redisConnectionFactory);
            template.afterPropertiesSet();
            return template;
        }
    }

    4.RedisSessionDao的自定义实现(session的缓存处理)注意修改redis缓存的项目名

    
    
    package com.ch.evaluation.auth.shiro.cas;

    import com.ch.evaluation.common.util.PropertityUtil;
    import org.apache.shiro.session.Session;
    import org.apache.shiro.session.UnknownSessionException;
    import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.data.redis.core.RedisTemplate;

    import java.io.Serializable;
    import java.util.Collection;
    import java.util.HashSet;
    import java.util.Set;
    import java.util.concurrent.TimeUnit;

    /**
    * @description:SessionDao自定义实现
    * @author: wangwei
    * @date: 2018年11月27日
    */
    @SuppressWarnings("all")
    public class RedisSessionDao extends AbstractSessionDAO {
    private final static String PREFIX="evaluation:shiro_redis_session:";
    private static Logger logger = LoggerFactory.getLogger(RedisSessionDao.class);
    private RedisTemplate redisTpl;

    @Override
    public void update(Session session) throws UnknownSessionException {
    if (session==null || session.getId() == null){
    logger.error("redis update session error:session or session id is null");
    return;
    }

    try {
    redisTpl.opsForValue().set(PREFIX+session.getId().toString(), session, PropertityUtil.getPropertity("session.timeout"), TimeUnit.MINUTES);
    } catch (Exception e) {
    logger.error(e.getMessage(), e);
    throw new UnknownSessionException(e);
    }
    }

    @Override
    public void delete(Session session) {
    if (session==null || session.getId() == null){
    logger.error("redis delete session error:session or session id is null");
    return;
    }
    try {
    redisTpl.delete(PREFIX+session.getId().toString());
    } catch (Exception e) {
    logger.error(e.getMessage(), e);
    }
    }

    @Override
    public Collection<Session> getActiveSessions() {
    Set<Session> sessions = new HashSet<Session>();
    Set keys = redisTpl.keys(PREFIX+"*");

    for(Object key : keys){
    Session session=(Session) redisTpl.opsForValue().get(key);
    sessions.add(session);
    }
    return sessions;
    }

    @Override
    protected Serializable doCreate(Session session) {
    if (session==null){
    logger.error("redis create session error:session is null");
    return null;
    }
    Serializable sessionId = generateSessionId(session);
    assignSessionId(session, sessionId);
    redisTpl.opsForValue().set(PREFIX+sessionId.toString(), session, PropertityUtil.getPropertity("session.timeout"), TimeUnit.MINUTES);
    return sessionId;
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
    if (sessionId == null){
    logger.error("redis read session error:sessionId is null");
    return null;
    }
    Session session = null;
    try {
    session = (Session) redisTpl.opsForValue().get(PREFIX+sessionId);
    } catch (Exception e) {
    logger.error(e.getMessage(), e);
    }
    return session;
    }

    public void setRedisTpl(RedisTemplate redisTpl) {
    this.redisTpl = redisTpl;
    }
    }
     

    5.上面用到了一个工具类加载配置文件

    package com.ch.evaluation.common.util;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Properties;
    
    public class PropertityUtil {
    
        public static int getPropertity(String key){
            Properties properties = new Properties();
            ClassLoader load = PropertityUtil.class.getClassLoader();
            InputStream is = load.getResourceAsStream("application.properties");
            try {
                properties.load(is);
                String value = properties.getProperty(key);
                int val = 0;
                if(value!=null){
                   val = Integer.parseInt(value);
                }
                return val;
            } catch (IOException e) {
                e.printStackTrace();
            }
            return 0;
        }
    
    
    }

    7..RedisCache的自定义实现(对权限和认证信息的缓存处理)注意修改redis缓存的项目名

    package com.ch.evaluation.common.redis;
    
    import com.ch.evaluation.common.util.PropertityUtil;
    import org.apache.shiro.cache.Cache;
    import org.apache.shiro.cache.CacheException;
    import org.springframework.data.redis.core.RedisTemplate;
    
    import java.util.Collection;
    import java.util.Collections;
    import java.util.HashSet;
    import java.util.Set;
    import java.util.concurrent.TimeUnit;
    
    /**
     * Redis缓存类
     * Created by 005803 on 2017/10/12.
     */
    
    public class RedisCache<K, V> implements Cache<K, V> {
    
        private RedisTemplate redisTemplate;
        private final static long SUPER_AMDIN_TICKET_EXPARE_TIME =3;
        private static final String PREFIX = "evaluation:shiro_redis_cache:";
        private static final String SUPER_TICKET_KEY = "evaluation:super_ticket:";
    
        public RedisCache(RedisTemplate redisTemplate) {
            this.redisTemplate = redisTemplate;
        }
    
        @Override
        public V get(K key) throws CacheException {
            return (V) redisTemplate.opsForValue().get(PREFIX + key);
        }
    
        @Override
        public V put(K key, V value) throws CacheException {
            redisTemplate.opsForValue().set(PREFIX + key, value, PropertityUtil.getPropertity("cache.timeout"), TimeUnit.MINUTES);
            return value;
        }
    
        @Override
        public V remove(K key) throws CacheException {
            Object value = redisTemplate.opsForValue().get(PREFIX + key);
            redisTemplate.delete(PREFIX + key);
            return (V) value;
        }
    
        @Override
        public void clear() throws CacheException {
            redisTemplate.delete(keys());
        }
    
        @Override
        public int size() {
            return keys().size();
        }
    
        @Override
        public Set<K> keys() {
            Set keys = redisTemplate.keys(PREFIX + "*");
            return keys != null ? keys : Collections.<K>emptySet();
        }
    
        @Override
        public Collection<V> values() {
            Set<K> keys = keys();
            Collection<V> c = new HashSet<>();
            for (K key : keys) {
                c.add((V) redisTemplate.opsForValue().get(key));
            }
            return c;
        }
    
        public V putSuper(K key, V value) throws CacheException {
            redisTemplate.opsForHash().put(SUPER_TICKET_KEY,key,value);
            redisTemplate.expire(SUPER_TICKET_KEY,SUPER_AMDIN_TICKET_EXPARE_TIME,TimeUnit.MINUTES);
            return value;
        }
    
        public Set<V> getAllSuperKeys() throws CacheException {
            return redisTemplate.opsForHash().keys(SUPER_TICKET_KEY);
        }
    
        public V getSuper(K key) throws CacheException {
            return (V) redisTemplate.opsForHash().get(SUPER_TICKET_KEY,key);
        }
    
        public void deleteSuper(K key) throws CacheException {
            redisTemplate.opsForHash().delete(SUPER_TICKET_KEY,key);
        }
    
        public boolean hasKey(K key) throws CacheException {
            return redisTemplate.opsForHash().hasKey(SUPER_TICKET_KEY,key);
        }
    }

    8..Redis缓存管理器的配置RedisCacheManager.java

    package com.ch.evaluation.common.redis;
    
    import org.apache.shiro.cache.Cache;
    import org.apache.shiro.cache.CacheException;
    import org.apache.shiro.cache.CacheManager;
    import org.springframework.data.redis.core.RedisTemplate;
    
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.ConcurrentMap;
    
    /**
     * Redis缓存管理器
     * Created by wangwei on 2018/10/19.
     */
    public class RedisCacheManager implements CacheManager {
    
        private RedisTemplate redisTemplate;
        private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<>();
    
        public void setRedisTemplate(RedisTemplate redisTemplate) {
            this.redisTemplate = redisTemplate;
        }
    
        @Override
        public <K, V> Cache<K, V> getCache(String name) throws CacheException {
            Cache cache = caches.get(name);
            if (cache == null) {
                cache = new RedisCache(redisTemplate);
                caches.put(name, cache);
            }
            return cache;
        }
    
    }

    9.在你自定义的shiro的realm中重写key的策略

    public class ExtendCasRealm extends CasRealm {
        
        private static Logger LOGGER = LoggerFactory.getLogger(ExtendCasRealm.class);
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
             ......................
        }
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            ........................
        }
         ....................
         ..................
        @Override
        protected Object getAuthorizationCacheKey(PrincipalCollection principals) {
            return principals.getPrimaryPrincipal() + ":authorization";
        }
    
        @Override
        protected Object getAuthenticationCacheKey(PrincipalCollection principals) {
            return principals.getPrimaryPrincipal() + ":authentication";
        }
    
        @Override
        protected Object getAuthenticationCacheKey(AuthenticationToken token) {
            return token.getPrincipal() + ":authentication";
        }
    }

    10.基本上配置以上信息就可以用了,值得注意的是要在ShiroCasConfig中配置这些Bean的关联关系,记得session的获取方式有两种,一种是servlet的session一种是shiro默认的session管理器DefaultWebSessionManager ,我们要记得注入DefaultWebSessionManager 管理器,不然程序执行过程中可能会默认执行isServletContainerSessions方法导致抛出一个session类型的异常

    贴一下ShiroCasConfig配置

    package com.ch.evaluation.config.shirocas;
    
    import com.ch.evaluation.auth.shiro.cas.ExtendCasRealm;
    import com.ch.evaluation.auth.shiro.cas.RedisSessionDao;
    import com.ch.evaluation.auth.shiro.filter.ExtendAuthorizationFilter;
    import com.ch.evaluation.auth.shiro.filter.ExtendCasFilter;
    import com.ch.evaluation.auth.shiro.filter.ExtendLogoutFilter;
    import com.ch.evaluation.auth.shiro.service.IAuthorizationService;
    import com.ch.evaluation.common.constants.WebConstants;
    import com.ch.evaluation.common.redis.RedisCacheManager;
    import org.apache.shiro.cache.MemoryConstrainedCacheManager;
    import org.apache.shiro.cas.CasSubjectFactory;
    import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
    import org.jasig.cas.client.session.SingleSignOutFilter;
    import org.jasig.cas.client.session.SingleSignOutHttpSessionListener;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.web.servlet.FilterRegistrationBean;
    import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.Ordered;
    import org.springframework.core.annotation.Order;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.web.filter.DelegatingFilterProxy;
    
    import javax.servlet.Filter;
    import java.util.HashMap;
    import java.util.LinkedHashMap;
    import java.util.Map;
    
    
    /**
     * Created by sunyong - 20170906
     */
    @Configuration
    public class ShiroCasConfig {
    
        @Value("${cas.server.url}")
        private String casServerUrl;
    
        @Value("${shiro.cas-server}")
        private String casServerUrlPrefix;
    
        @Value("${shiro.server}")
        private String shiroServerUrlPrefix;
    
        private static final String CAS_FILTER_NAME = "casFilter";
        private static final String SHIRO_FILTER_NAME = "shiroFilter";
        private static final String AUTH_FILTER_NAME = "authFilter";
        private static final String LOGOUT_FILTER_NAME = "logoutFilter";
    
        /**
         * 注册DelegatingFilterProxy(Shiro)
         */
        @Bean
        public FilterRegistrationBean<DelegatingFilterProxy> filterRegistrationBean() {
            FilterRegistrationBean<DelegatingFilterProxy> filterRegistration = new FilterRegistrationBean<DelegatingFilterProxy>();
            filterRegistration.setFilter(new DelegatingFilterProxy(SHIRO_FILTER_NAME));
            filterRegistration.addInitParameter("targetFilterLifecycle", "true");
            filterRegistration.setEnabled(true);
            filterRegistration.addUrlPatterns("/*");
            return filterRegistration;
        }
    
        /**
         * @param securityManager
         * @return
         */
        @Bean
        public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(
                DefaultWebSecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
            authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
            return authorizationAttributeSourceAdvisor;
        }
    
        /**
         * 会话管理器
         * @auth 011336
         * @DATE 2018/10/15
         * @return
         */
        @Bean(name = "sessionManager")
        public DefaultWebSessionManager getDefaultWebSessionManager(RedisSessionDao sessionDAO, RedisCacheManager redisCacheManager) {
            DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
            //sessionManager.setGlobalSessionTimeout(sessionTimeout);
            sessionManager.setDeleteInvalidSessions(true);
            //sessionManager.setSessionValidationSchedulerEnabled(true);
            sessionManager.setSessionDAO(sessionDAO);
            sessionManager.setCacheManager(redisCacheManager);
            // TODO simpleCookie
            return sessionManager;
        }
    
        /**
         * 实例化SecurityManager,该类是shiro的核心类
         *
         * @return
         */
        @Bean
        public DefaultWebSecurityManager getDefaultWebSecurityManager(ExtendCasRealm extendCasRealm,
                        DefaultWebSessionManager sessionManager, RedisCacheManager redisCacheManager) {
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            securityManager.setRealm(extendCasRealm);
            securityManager.setCacheManager(redisCacheManager);
            securityManager.setSessionManager(sessionManager);
            securityManager.setSubjectFactory(new CasSubjectFactory());
            return securityManager;
        }
    
        /**
         * RedisSessionDao
         * @auth 011336
         * @DATE 2018/10/15
         * @return
         */
        @Bean
        public RedisSessionDao getRedisSessionDao(RedisTemplate redisTemplate) {
            RedisSessionDao sessionDAO = new RedisSessionDao();
            sessionDAO.setRedisTpl(redisTemplate);
            return sessionDAO;
        }
    
        /**
         * redisCacheManager
         * @auth 011336
         * @DATE 2018/10/15
         * @return
         */
        @Bean
        public RedisCacheManager getRedisCacheManager(RedisTemplate redisTemplate) {
            RedisCacheManager redisCacheManager = new RedisCacheManager();
            redisCacheManager.setRedisTemplate(redisTemplate);
            return redisCacheManager;
        }
    
        /**
         * 配置Realm,由于我们使用的是CasRealm,所以已经集成了单点登录的功能
         *
         * @param authorizationService
         * @return
         */
        @Bean
        public ExtendCasRealm getExtendCasRealm(IAuthorizationService authorizationService,
                                                RedisCacheManager redisCacheManager ){
            ExtendCasRealm extendCasRealm = new ExtendCasRealm();
            extendCasRealm.setAuthorizationService(authorizationService);
            // cas登录服务器地址前缀
            extendCasRealm.setCasServerUrlPrefix(casServerUrlPrefix);
            // 客户端回调地址,登录成功后的跳转地址(自己的服务地址)
            extendCasRealm.setCasService(shiroServerUrlPrefix + WebConstants.CAS_FILTER_URI);
            extendCasRealm.setCachingEnabled(true);
            extendCasRealm.setAuthenticationCachingEnabled(true);
            extendCasRealm.setAuthenticationCacheName("authenticationCache");
            extendCasRealm.setAuthorizationCachingEnabled(true);
            extendCasRealm.setAuthorizationCacheName("authorizationCache");
            extendCasRealm.setCacheManager(redisCacheManager);
            return extendCasRealm;
        }
    
        /**
         * 注册单点登出的listener
         *
         * @return
         */
        @Bean
        @Order(Ordered.HIGHEST_PRECEDENCE) // 优先级需要高于Cas的Filter
        public ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> singleSignOutHttpSessionListener() {
            ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> bean = new ServletListenerRegistrationBean<SingleSignOutHttpSessionListener>();
            bean.setListener(new SingleSignOutHttpSessionListener());
            bean.setEnabled(true);
            return bean;
        }
    
        /**
         * 注册单点登出filter
         *
         * @return
         */
        @Bean
        public FilterRegistrationBean<SingleSignOutFilter> singleSignOutFilter() {
            FilterRegistrationBean<SingleSignOutFilter> bean = new FilterRegistrationBean<SingleSignOutFilter>();
            bean.setName("singleSignOutFilter");
            bean.setFilter(new SingleSignOutFilter());
            bean.addUrlPatterns("/*");
            bean.setEnabled(true);
            return bean;
        }
    
        /**
         * CAS过滤器
         *
         * @return
         */
        //@Bean(name = CAS_FILTER_NAME)
        public ExtendCasFilter getExtendCasFilter() {
            ExtendCasFilter casFilter = new ExtendCasFilter();
            casFilter.setName(CAS_FILTER_NAME);
            casFilter.setEnabled(true);
            // String loginUrl = casServerUrl + "/login?service=" + shiroServerUrlPrefix + CAS_FILTER_URI;
            casFilter.setFailureUrl("/error/casfailure");
            casFilter.setExtendFailureUrl("/error/casfailure"); // 由于原failuserUrl为私有字段,在扩展类中不能获取到值
            return casFilter;
        }
    
        /**
         * extAuth Filter
         */
        //@Bean(name = AUTH_FILTER_NAME)
        public ExtendAuthorizationFilter getExtendAuthorizationFilter(
                IAuthorizationService authorizationService) {
            ExtendAuthorizationFilter extAuthFilter = new ExtendAuthorizationFilter();
            extAuthFilter.setName(AUTH_FILTER_NAME);
            extAuthFilter.setEnabled(true);
            extAuthFilter.setAuthorizationService(authorizationService);
            return extAuthFilter;
        }
    
        /**
         * extLogout Filter
         */
        //@Bean(name = LOGOUT_FILTER_NAME)
        public ExtendLogoutFilter getExtendLogoutFilter(IAuthorizationService authorizationService) {
            ExtendLogoutFilter extLogoutFilter = new ExtendLogoutFilter();
            extLogoutFilter.setName(LOGOUT_FILTER_NAME);
            extLogoutFilter.setEnabled(true);
            extLogoutFilter.setAuthorizationService(authorizationService);
            extLogoutFilter.setRedirectUrl(casServerUrl + "/logout?service=" + shiroServerUrlPrefix);
            return extLogoutFilter;
        }
    
        /**
         * 使用工厂模式,创建并初始化ShiroFilter
         *
         * @param securityManager
         * @param authorizationService
         * @return
         */
        @Bean(name = SHIRO_FILTER_NAME)
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager,
                                                                IAuthorizationService authorizationService) {
            ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
            shiroFilterFactoryBean.setSecurityManager(securityManager);
            String loginUrl = casServerUrl + "/login?service=" + shiroServerUrlPrefix + WebConstants.CAS_FILTER_URI;
            shiroFilterFactoryBean.setLoginUrl(loginUrl);
            shiroFilterFactoryBean.setSuccessUrl("/");
            shiroFilterFactoryBean.setUnauthorizedUrl("/error/unauthorized");
            Map<String, Filter> filters = new HashMap<>();
            filters.put(CAS_FILTER_NAME, getExtendCasFilter());
            filters.put(LOGOUT_FILTER_NAME, getExtendLogoutFilter(authorizationService));
            filters.put(AUTH_FILTER_NAME, getExtendAuthorizationFilter(authorizationService));
            shiroFilterFactoryBean.setFilters(filters);
    
            loadShiroFilterChain(shiroFilterFactoryBean);
            return shiroFilterFactoryBean;
        }
    
        private void loadShiroFilterChain(ShiroFilterFactoryBean shiroFilterFactoryBean) {
            Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
            filterChainDefinitionMap.put(WebConstants.CAS_FILTER_URI, CAS_FILTER_NAME);
            filterChainDefinitionMap.put("/logout", LOGOUT_FILTER_NAME);
            filterChainDefinitionMap.put("/static/**", "anon");
            filterChainDefinitionMap.put("/css/**", "anon");
            filterChainDefinitionMap.put("/front/**", "anon");
            filterChainDefinitionMap.put("/img/**", "anon");
            filterChainDefinitionMap.put("/js/**", "anon");
            filterChainDefinitionMap.put("/plugin/**", "anon");
            filterChainDefinitionMap.put("/home/**", "anon");
            filterChainDefinitionMap.put("/super", "anon");
            filterChainDefinitionMap.put("/interface/**", "anon");
            filterChainDefinitionMap.put("/super/login", "anon");
            filterChainDefinitionMap.put("/error/**", "anon");
            filterChainDefinitionMap.put("/**", AUTH_FILTER_NAME);
            shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        }
    }

    二:超管redis的session共享

    1..把原来的SuperAdminTickeUtils更名为SuperAdminTicketManager,或者删除替换也行。记得把其他用到这个类的地方改一下就行,不详细说改了啥了。

    package com.ch.evaluation.auth.shiro;
    
    import com.ch.evaluation.auth.shiro.entity.AuthorizationUser;
    import com.ch.evaluation.common.redis.RedisCache;
    import com.ch.evaluation.common.redis.RedisCacheManager;
    import org.jasig.cas.client.authentication.AttributePrincipalImpl;
    import org.jasig.cas.client.validation.Assertion;
    import org.jasig.cas.client.validation.AssertionImpl;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.util.*;
    
    @Component
    public class SuperAdminTicketManager {
        private static Logger LOGGER = LoggerFactory.getLogger(SuperAdminTicketManager.class);
        private final static  String SUPER_AMDIN_TICKET_SUFFIX = ".superadmin.com";
        private final static long SUPER_AMDIN_TICKET_TIME = 1000 * 60 * 3;
        private final static String SUPER_TICKET = "superTicket";
        @Autowired
        private RedisCacheManager redisCacheManager;
    
        public String putTicket(AuthorizationUser user) {
            RedisCache cache = (RedisCache)redisCacheManager.getCache(SUPER_TICKET);
            String ticket = getTicket();
            cache.putSuper(ticket,user);
            return ticket;
        }
    
        public boolean validTiket(String ticket) {
            RedisCache cache = (RedisCache)redisCacheManager.getCache(SUPER_TICKET);
            clearTicketMap(cache);
            return cache.hasKey(ticket);
        }
    
        public boolean endsWith(String ticket) {
            return ticket.endsWith(SUPER_AMDIN_TICKET_SUFFIX);
        }
    
        private static String getTicket() {
            return UUID.randomUUID() + SUPER_AMDIN_TICKET_SUFFIX;
        }
    
        private void clearTicketMap(RedisCache cache) {
            Long currentTime = new Date().getTime();
            Set<String> keys= cache.getAllSuperKeys();
            for (Object key:keys) {
                AuthorizationUser user = (AuthorizationUser)cache.getSuper(key);
                if((currentTime - user.getTime()) > SUPER_AMDIN_TICKET_TIME){
                    LOGGER.info("super.ticket has expired and delete from redis!");
                    cache.deleteSuper(key);
                }
            }
        }
    
        public final Assertion getSuperAdminAssertion(String ticket) {
            Assertion assertion = null;
            final Map<String, Object> attributes = new HashMap<String, Object>();
            RedisCache cache = (RedisCache)redisCacheManager.getCache(SUPER_TICKET);
            AuthorizationUser user = (AuthorizationUser)cache.getSuper(ticket);
            if (null != user) {
                attributes.put("user_id", user.getUserId());
                attributes.put("user_name", user.getUserName());
                attributes.put("password", user.getPassword());
                assertion = new AssertionImpl(new AttributePrincipalImpl(user.getUserAccount(), attributes));
            }
            cache.deleteSuper(ticket);
            return assertion;
        }
    }

    2.修改之前用到这个类的地方

    2.1 修改ExtendCasRealm  新增一处  改三处
    @Autowired
    private SuperAdminTicketManager superAdminTicketManager;

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    CasToken casToken = (CasToken) token;
    if (token == null) {
    return null;
    }
    String ticket = (String)casToken.getCredentials();
    if (!StringUtils.hasText(ticket)) {
    return null;
    }
    boolean superAdminFlag = superAdminTicketManager.endsWith(ticket);
        ...........
    private Assertion getSuperAdminAssertion(CasToken casToken, String ticket) 
    throws CasAuthenticationException {
    if (!superAdminTicketManager.validTiket(ticket)) {
    throw new CasAuthenticationException("Invalid super ticket [" + ticket + "]");
    }
    Assertion casAssertion = superAdminTicketManager.getSuperAdminAssertion(ticket);
    return casAssertion;
    }

    2.2SuperAdminServiceImpl 中新增一处  改一处

    @Autowired
    private SuperAdminTicketManager superAdminTicketManager;

    ....
        String ticket = superAdminTicketManager.putTicket(user);
    return ticket;
    }


    }

    3.序列化:实现接口后鼠标放在类上alt+Enter就可以生成uid

    public class AuthorizationUser implements Serializable {
    
        private static final long serialVersionUID = -5556165398740497973L;

    三:超管登录密码加密

    1.引入js文件夹到plugin

    2.layout-superlogin.html中引入JS

     <script class="custom-script" src="../../static/plugin/crypto-js/crypto-js.js" th:src="@{/plugin/crypto-js/crypto-js.js}"></script>
     <script class="custom-script" src="../../static/plugin/crypto-js/core.js" th:src="@{/plugin/crypto-js/core.js}"></script>
     <script class="custom-script" src="../../static/plugin/crypto-js/aes.js" th:src="@{/plugin/crypto-js/aes.js}"></script>

    3.编写superlogin.js文件

    复制代码
    var key = CryptoJS.enc.Utf8.parse("1234123412ABCDEF");  //十六位十六进制数作为密钥
    var iv = CryptoJS.enc.Utf8.parse('ABCDEF1234123412');   //十六位十六进制数作为密钥偏移量
    //解密方法
    function Decrypt(word) {
        var encryptedHexStr = CryptoJS.enc.Hex.parse(word);
        var srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr);
        var decrypt = CryptoJS.AES.decrypt(srcs, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
        var decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
        return decryptedStr.toString();
    }
    
    //加密方法
    function Encrypt(word) {
        var srcs = CryptoJS.enc.Utf8.parse(word);
        var encrypted = CryptoJS.AES.encrypt(srcs, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
        return encrypted.ciphertext.toString().toUpperCase();
    }
    function superLogin(){
        var passWord = $("#signin-superamdin-password").val();
        if(passWord==null || passWord==""){
            passWord ="";
        }else{
            passWord = passWord.trim();
        }
        var prefix = getTimeStr("prefix");
        var suffix = getTimeStr("suffix");
        passWord = prefix+passWord+suffix
        var aesPassWord = Encrypt(passWord);
        $("#submit-superamdin-password").val(aesPassWord);
        return true;
    }
    function getTimeStr(flag){
        var myDate = new Date();
    
        var year = myDate.getFullYear(); //获取完整的年份(4位,1970-????)
        var month = myDate.getMonth()+1; //获取当前月份(0-11,0代表1月)
        month = month > 9 ? month : "0"+month;
        var day =  myDate.getDate(); //获取当前日(1-31)
        day = day > 9 ? day : "0"+day;
        var hours =  myDate.getHours(); //获取当前小时数(0-23)
        hours = hours > 9 ? hours : "0"+hours;
        var minutes =  myDate.getMinutes(); //获取当前分钟数(0-59)
        minutes = minutes > 9 ? minutes : "0"+minutes;
        var seconds =  myDate.getSeconds(); //获取当前秒数(0-59)
        seconds = seconds > 9 ? seconds : "0"+seconds;
        if(flag=="prefix"){
            return ""+year+month+day
        }else{
            return ""+hours+minutes+seconds
        }
    }
    复制代码

    3.1:替换html部分的form部分

    4.可直接替换superloginController.java   详情如下

    4.1:校验是否超时,获取时间差

    复制代码
    public boolean checkLogionTime(String rangeTime){
            String strDate = rangeTime;
            //注意:SimpleDateFormat构造函数的样式与strDate的样式必须相符
            SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyyMMddHHmmss");
            SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //加上时间
            //必须捕获异常
            Date date= null;
            try {
                date = simpleDateFormat.parse(strDate);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            long min = getDatePoor(new Date(),date);
            if(min>=loginTimeOut) {
                return false;
            }else{
                return true;
            }
        }
        //计算时间差  差多少分钟   绝对值
        public static long getDatePoor(Date endDate, Date loginDate) {
            long nd = 1000 * 24 * 60 * 60;
            long nh = 1000 * 60 * 60;
            long nm = 1000 * 60;
            // long ns = 1000;
            // 获得两个时间的毫秒时间差异
            long diff = endDate.getTime() - loginDate.getTime();
            // 计算差多少分钟
            long min = diff % nd % nh / nm;
            return Math.abs(min);
        }
    复制代码

    4.2:验证之前解密   直接加在原来的步骤中就好

    复制代码
    public String login(ModelMap modal, String superAdminUsername, String superAdminPassword,
                            HttpServletRequest request, HttpServletResponse response) {
            if (StringUtils.isNotBlank(superAdminUsername) && StringUtils.isNotBlank(superAdminPassword)) {
                try {
                    String str = AesUtil.desEncrypt(superAdminPassword);
                    superAdminPassword = str.substring(8, str.length() - 6);
                    String rangeTime =  str.substring(0,8)+str.substring(str.length()-6);
                    boolean b = checkLogionTime(rangeTime);
                    if(!b) {
                        modal.put(ErrorConstants.ERROR_MESSAGE, ErrorConstants.ERROR_SUPERADMIN_003);
                        return "views/superLoginPage";
                    }
                } catch (Exception e) {
                    LOGGER.error("decrypt applicationMetadataId failed", e);
                }
                SuperAdmin superAdmin = new SuperAdmin();
                superAdmin.setUsername(superAdminUsername.trim());
    复制代码

    有个超时时间的设置在propertity中

    # unit minutes
    super.login.timeOut=5

    5.后台要引入一个解密的Java工具类,ErrorConstants中加一个错误提示信息

    public final static String ERROR_SUPERADMIN_003 = "登陆超时,不安全的请求!"; // 判断登录请求超过一定时间为不安全请求

    完事!

     

    四:单点登录ticket验证地址变更

    1.ShiroCasConfig中假如如下配置

      @Value("${cas.server.url}")
      private String casServerUrl;

    替换如下内容

    复制代码
      //@Bean(name = LOGOUT_FILTER_NAME)
        public ExtendLogoutFilter getExtendLogoutFilter(IAuthorizationService authorizationService) {
            ExtendLogoutFilter extLogoutFilter = new ExtendLogoutFilter();
            extLogoutFilter.setName(LOGOUT_FILTER_NAME);
            extLogoutFilter.setEnabled(true);
            extLogoutFilter.setAuthorizationService(authorizationService);
            extLogoutFilter.setRedirectUrl(casServerUrl + "/logout?service=" + shiroServerUrlPrefix);
            return extLogoutFilter;
        }
    @Bean(name = SHIRO_FILTER_NAME)
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager,
    IAuthorizationService authorizationService) {
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    shiroFilterFactoryBean.setSecurityManager(securityManager);
    String loginUrl = casServerUrl + "/login?service=" + shiroServerUrlPrefix + WebConstants.CAS_FILTER_URI;
    shiroFilterFactoryBean.setLoginUrl(loginUrl);
     
    复制代码

    完事!

  • 相关阅读:
    Linux的网络配置
    Linux进程
    我需要的电脑配置
    spring注解配置
    spring中集合的配置
    getProperty()方法的参数和用途
    树的遍历
    单词变换
    最短路径dijkstra算法
    文件路径
  • 原文地址:https://www.cnblogs.com/UncleWang001/p/10028350.html
Copyright © 2011-2022 走看看