修改记录-优化后(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 {@Autowiredprivate 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;}@Overridepublic V get(K key) throws CacheException {return (V) redisTemplate.opsForValue().get(PREFIX + key);}@Overridepublic V put(K key, V value) throws CacheException {redisTemplate.opsForValue().set(PREFIX + key, value, PropertityUtil.getPropertity("cache.timeout"), TimeUnit.MINUTES);return value;}@Overridepublic V remove(K key) throws CacheException {Object value = redisTemplate.opsForValue().get(PREFIX + key);redisTemplate.delete(PREFIX + key);return (V) value;}@Overridepublic void clear() throws CacheException {redisTemplate.delete(keys());}@Overridepublic int size() {return keys().size();}@Overridepublic Set<K> keys() {Set keys = redisTemplate.keys(PREFIX + "*");return keys != null ? keys : Collections.<K>emptySet();}@Overridepublic 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;}@Overridepublic <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);@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {......................}@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {........................}......................................@Overrideprotected Object getAuthorizationCacheKey(PrincipalCollection principals) {return principals.getPrimaryPrincipal() + ":authorization";}@Overrideprotected Object getAuthenticationCacheKey(PrincipalCollection principals) {return principals.getPrimaryPrincipal() + ":authentication";}@Overrideprotected 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)*/@Beanpublic 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*/@Beanpublic 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 simpleCookiereturn sessionManager;}/*** 实例化SecurityManager,该类是shiro的核心类** @return*/@Beanpublic 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*/@Beanpublic RedisSessionDao getRedisSessionDao(RedisTemplate redisTemplate) {RedisSessionDao sessionDAO = new RedisSessionDao();sessionDAO.setRedisTpl(redisTemplate);return sessionDAO;}/*** redisCacheManager* @auth 011336* @DATE 2018/10/15* @return*/@Beanpublic RedisCacheManager getRedisCacheManager(RedisTemplate redisTemplate) {RedisCacheManager redisCacheManager = new RedisCacheManager();redisCacheManager.setRedisTemplate(redisTemplate);return redisCacheManager;}/*** 配置Realm,由于我们使用的是CasRealm,所以已经集成了单点登录的功能** @param authorizationService* @return*/@Beanpublic 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的Filterpublic ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> singleSignOutHttpSessionListener() {ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> bean = new ServletListenerRegistrationBean<SingleSignOutHttpSessionListener>();bean.setListener(new SingleSignOutHttpSessionListener());bean.setEnabled(true);return bean;}/*** 注册单点登出filter** @return*/@Beanpublic 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";@Autowiredprivate 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 新增一处 改三处
@Autowiredprivate 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+suffixvar 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);
完事!
转载于:https://www.cnblogs.com/UncleWang001/p/10028350.html
修改记录-优化后(springboot+shiro+session+redis+ngnix共享)相关推荐
- 全程配图超清晰的Springboot权限控制后台管理项目实战第二期(Springboot+shiro+mybatis+redis)
全程配图超清晰的Springboot权限控制后台管理项目实战第二期(Springboot+shiro+mybatis+redis) 众所周知,作为一个后端新手学习者,通过项目来学习,增长项目经验,是一 ...
- json web token没有哪个成分_【分享项目】给你看看我们公司的登录认证是怎么做的?!(SpringBoot+Shiro+Token+Redis)...
背景交代 以前项目中权限认证没有使用安全框架,都是在自定义filter中判断是否登录以及用户是否有操作权限的.最近开了新项目,搭架子时,想到使用安全框架来解决认证问题,spring security太 ...
- springboot + shiro之登录人数限制、登录判断重定向、session时间设置
springboot + shiro之登录人数控制 项目 前篇:spring boot + mybatis + layui + shiro后台权限管理系统:https://blog.51cto.com ...
- SpringBoot+Shiro学习(一):主要模块介绍
这篇文章是我最近对SpringBoot+Shiro+mybatis+redis一个练手项目的记录. 我是按照慕课网的一篇课程+百度进行练手的 慕课课程 练手项目Github地址 跟着开涛学Shiro ...
- 基于springboot+shiro一套可落地实施安全认证框架整合
前言 俗话说,兵马未动,粮草先行,万丈高楼平地起,一套切实可用的微服务框架是整个项目小组进行后续高效开发的保障,在前期微服务框架构建过程中,大体来说,主要考虑3个点: 技术选项,如果公司业务规模能够提 ...
- SpringBoot整合mybatis、shiro、redis实现基于数据库的细粒度动态权限管理系统实例(转)...
SpringBoot整合mybatis.shiro.redis实现基于数据库的细粒度动态权限管理系统实例 shiro 目录(?)[+] 前言 表结构 maven配置 配置Druid 配置mybatis ...
- C#session共享+redis_Shiro权限管理框架(二):Shiro结合Redis实现分布式环境下的Session共享...
精品推荐 国内稀缺优秀Java全栈课程-Vue+SpringBoot通讯录系统全新发布! Docker快速手上视频教程(无废话版)[免费] 作者:夜月归途 转载自: https://www.cnblo ...
- springboot+shiro+redis项目整合
介绍: Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码学和会话管理.使用Shiro的易于理解的API,您可以快速.轻松地获得任何应用程序,从最小的移动应用程序到最 ...
- springboot+shiro+redis+jwt实现多端登录:PC端和移动端同时在线(不同终端可同时在线)
前言 之前写了篇 springboot+shiro+redis多端登录:单点登录+移动端和PC端同时在线 的文章,但是token用的不是 jwt 而是 sessionID,虽然已经实现了区分pc端和移 ...
- SpringBoot 基于Shiro + Jwt + Redis的用户权限管理 (三) 鉴权
项目Github地址: https://github.com/baiye21/ShiroDemo SpringBoot 基于Shiro + Jwt + Redis的用户权限管理 (一) 简介与配置 S ...
最新文章
- 在同一台电脑上同时使用IE6和IE7
- html 点击空白关闭浮层,js中点击空白区域时文本框与隐藏层的显示与影藏问题...
- 《深入理解java内存模型》学习整理1
- 服务器与客户端连接 聊天机器人
- 第二轮冲刺-Runner站立会议08
- 【猜画小歌】辅助插件FunnyDraw江湖召集令
- Oracle案例08——xx.xx.xx.xx,表空间 SYSAUX 使用率95%%
- 决定零售商生与死的12大关键指标
- SCCM部署前的IIS、WSUS等准备
- java servlet大学生旅游网站的设计与开发源码
- 检定规程JJG687- 2008《液态物料定量灌装机》解析
- vue.js安装步骤教程
- 越来越火的图数据库到底能做什么?
- Openwrt无线中继AP设置教程
- 为什么建议向你的同事屏蔽朋友圈?
- 用python给pdf批量添加水印,并给pdf加密
- 手机短信验证码开发流程
- 下一轮人工智能泡沫,或将由消费机器人引发
- linux单机游戏存放目录,Linux安装RocketMQ单机版教程
- 毕业设计 基于深度学习的人脸性别年龄识别 - 图像识别 opencv
热门文章
- 八千里路云和月 | 2021年最新从零到大数据专家学习路径指南
- Android之路——第一个上线 APP项目总结
- 中小企业OA系统视频教程(更新程度:完毕)送ppt源码
- VINS-MONO边缘化策略
- SQL控制权力(DNC)与日志
- aras innovator: 分类筛选如何做?
- Sublime Text 2 设置文件详解转
- sublime text2配置文件详解(转)
- Microsoft Office Word 2007 转换为 Microsoft Office Word 2003兼容方法
- Java并发 ReentrantLock(重入锁)之非公平锁源码解析 超详细!!