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);
 

完事!

修改记录-优化后(springboot+shiro+session+redis+ngnix共享)的更多相关文章

  1. springboot+spring session+redis+nginx实现session共享和负载均衡

    环境 centos7. jdk1.8.nginx.redis.springboot 1.5.8.RELEASE session共享 添加spring session和redis依赖 <depen ...

  2. springboot shiro ehcache redis 简单使用

    引入相关pom <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...

  3. SpringBoot+Shiro+Redis共享Session入门小栗子

    在单机版的Springboot+Shiro的基础上,这次实现共享Session. 这里没有自己写RedisManager.SessionDAO.用的 crazycake 写的开源插件 pom.xml ...

  4. SpringBoot学习:整合shiro(rememberMe记住我后自动登录session失效解决办法)

    项目下载地址:http://download.csdn.NET/detail/aqsunkai/9805821 定义一个拦截器,判断用户是通过记住我登录时,查询数据库后台自动登录,同时把用户放入ses ...

  5. springboot+shiro+redis项目整合

    介绍: Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码学和会话管理.使用Shiro的易于理解的API,您可以快速.轻松地获得任何应用程序,从最小的移动应用程序到最 ...

  6. SpringBoot整合mybatis、shiro、redis实现基于数据库的细粒度动态权限管理系统实例

    1.前言 本文主要介绍使用SpringBoot与shiro实现基于数据库的细粒度动态权限管理系统实例. 使用技术:SpringBoot.mybatis.shiro.thymeleaf.pagehelp ...

  7. springboot+shiro 一个项目部署多个,session名冲突问题

    问题 前几天遇到一个比较奇怪的问题, 一个项目部署多个,端口不同.启动之后在同一浏览器中进行登录,后一个登录的会把前一个登录的挤掉,导致只能登录一个. 原因 是因为sessionid相同,然后修改了s ...

  8. springboot+shiro+redis(单机redis版)整合教程-续(添加动态角色权限控制)

    相关教程: 1. springboot+shiro整合教程 2. springboot+shiro+redis(单机redis版)整合教程 3. springboot+shiro+redis(集群re ...

  9. springboot+shiro+redis(集群redis版)整合教程

    相关教程: 1. springboot+shiro整合教程 2. springboot+shiro+redis(单机redis版)整合教程 3.springboot+shiro+redis(单机red ...

随机推荐

  1. Maven 工程读取resource下的文件

    1:方式1: public static List<String> userList; static { userList = new LinkedList<String>() ...

  2. Python 2、8、10、16进制间的转换

    进制转换一直是初学者所头疼的,下面就简单的列出各进制之间都是以什么方式转换的. # print('2-->8: ', oct(int('0b1010', 2))) # 2-10-8 # prin ...

  3. iframe跨域问题:Uncaught DOMException: Blocked a frame with origin解决方法

    在前后端分离的情况下,前台页面将后台页面加载在预留的iframe中:但是遇到了iframe和主窗口双滚动条的情况,由此引申出来了问题: 只保留单个滚动条,那么就要让iframe的高度自适应,而从主页面 ...

  4. jbpm 6 vs activities 5评估(持续更新、亲测实际项目评估)

    最近我们有个使用了jbpm 6.2(6.2是一个较大的里程碑)的批处理模块,因为大BOSS一直觉得太重了,希望有更加轻量级的解决方案,因为我们基本上没有真正意义上流程的概念,只有静态的流程图,因为一直 ...

  5. mongodb三种引擎测试(转)

    文章http://diyitui.com/content-1459560904.39084552.html亲测了根据证券行情存储的性能情况,我们目前使用load local infile,平均每秒更新 ...

  6. 【题解】Luogu P4979 矿洞:坍塌

    原题传送门:P4979 矿洞:坍塌 这是某场膜你赛的题,最后我一百零几分rank三十几滚粗 这是我唯一ac的一题 这题比较简单qaq 前置芝士:珂朵莉树 窝博客里对珂朵莉树的介绍 没什么好说的自己看看 ...

  7. Exp2_固件程序设计 20165226_20165310_20165315

    Exp2_固件程序设计 20165226_20165310_20165315 Exp2_1 MDK 实验内容 注意不经老师允许不准烧写自己修改的代码 两人(个别三人)一组 参考云班课资源中" ...

  8. Link Cut Tree学习笔记

    从这里开始 动态树问题和Link Cut Tree 一些定义 access操作 换根操作 link和cut操作 时间复杂度证明 Link Cut Tree维护链上信息 Link Cut Tree维护子 ...

  9. Linux服务器搭建Nexus-Maven私服(适合新手比较基础)

    背景 在使用maven构建项目的时候,几乎都会涉及到一个“私服”的概念,那么到底什么是私服?使用私服有能够带来哪些益处? 私服:私服是指私有服务器,是架设在局域网的一种特殊的远程仓库,目的是代理远程仓 ...

  10. 程序重启RocketMQ消息重复消费

    最近在调试RocketMQ消息发送与消费的Demo时,发现一个问题:只要重启程序,RocketMQ消息就会重复消费. 那么这是什么原因导致的,又该如何解决呢? 经过一番排查,发现程序使用的Rocket ...