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. JS传值中文乱码解决方案

    JS传值中文乱码解决方案 一.相关知识 1,Java相关类: (1)java.net.URLDecoder类 HTML格式解码的实用工具类,有一个静态方法:public static  String ...

  2. mysql/oracle jdbc大数据量插入优化

    10.10.6  大数据量插入优化 在很多涉及支付和金融相关的系统中,夜间会进行批处理,在批处理的一开始或最后一般需要将数据回库,因为应用和数据库通常部署在不同的服务器,而且应用所在的服务器一般也不会 ...

  3. API网关性能比较:NGINX vs. ZUUL vs. Spring Cloud Gateway vs. Linkerd(转)

    前几天拜读了 OpsGenie 公司(一家致力于 Dev & Ops 的公司)的资深工程师 Turgay Çelik 博士写的一篇文章(链接在文末),文中介绍了他们最初也是采用 Nginx 作 ...

  4. 关于__declspec(dllexport)

    windows下dll动态库函数的导入与导出. __declspec Microsoft Specific __declspec ( extended-attribute ) declarator l ...

  5. maven-shade-plugin插件

    maven-shade-plugin主要是maven-assembly-plugin的后继者,用来将一个自启动jar项目的依赖打包到一个大的jar中,比如dubbo就是这么做的.具体可参考http:/ ...

  6. (5keras自带的模型之间的关系)自己动手,编写神经网络程序,解决Mnist问题,并网络化部署

    ​ ​其中: 1.VGG 网络以及从 2012 年以来的 AlexNet 都遵循现在的基本卷积网络的原型布局:一系列卷积层.最大池化层和激活层,最后还有一些全连接的分类层. 2.ResNet 的作者将 ...

  7. VS2012创建ATL工程及使用MFC测试COM组件

    一.创建ATL工程 1.创建ATL项目,取名为ATLMyCom 2.在ATL项目向导中,勾选[支持MFC](利用MFC测试用).[支持 COM+ 1.0],其余的选项默认,点击完成. 3.右键工程名称 ...

  8. 使用Jenkins构建、部署spring boot项目

    一.环境搭建 本次实验的环境为Ubuntu 16.04,Jenkins 2.8.3 1.安装ssh sudo apt-get update # 更新软件源 sudo apt-get install o ...

  9. Python3 tkinter基础 Label pack 设置控件在窗体中的位置

             Python : 3.7.0          OS : Ubuntu 18.04.1 LTS         IDE : PyCharm 2018.2.4       Conda ...

  10. C# 基于任务的异步模式的创建与使用的简单示例

    对于窗体程序,使用基于任务的异步模式需要用到Task类,下面示例下非常简单的用法. 1.创建一个拥有异步方法的类 该类拥有一个异步方法DoSomthingAsync,根据微软建议的命名规则该方法要带A ...