Springboot統合shiro,redisキャッシュセッション
Spring Boot+RedisによるShiroクラスタの実現
Webアプリケーションの分散クラスタ配置を実現するためには,ログインセッションの統一を解決する.本稿ではshiroを権限制御,redisをsessionストレージとし,spring bootの高速構成と組み合わせてsession共有を実現する.
1、相関依存の導入
2、Redis関連
2.1.redis構成
2.2.redisキャッシュのオブジェクトはシーケンス化、汎用シーケンス化する必要があります
2.3 RedisTemplate構成
3.RedisはshiroのSessionDaoアクセスセッションを実現する
4.cache共有の実現
shiroを実現するCacheManager
5.構成
6、Realm
7、shiro配置(yml)
8、STShiroConf配置
何度もredisからsession問題を獲得してまだ解決していないで、各位の大神に解決策をあげることを求めます
コンポーネントプロジェクトのソースリンク:http://download.csdn.net/download/qq_16055765/10247345
Webアプリケーションの分散クラスタ配置を実現するためには,ログインセッションの統一を解決する.本稿ではshiroを権限制御,redisをsessionストレージとし,spring bootの高速構成と組み合わせてsession共有を実現する.
1、相関依存の導入
org.springframework.boot
spring-boot-starter-data-redis
org.apache.shiro
shiro-spring
1.3.2
2、Redis関連
2.1.redis構成
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
2.2.redisキャッシュのオブジェクトはシーケンス化、汎用シーケンス化する必要があります
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.serializer.support.DeserializingConverter;
import org.springframework.core.serializer.support.SerializingConverter;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
/**
* redis
*/
public class RedisObjectSerializer implements RedisSerializer
2.3 RedisTemplate構成
package com.st.redis.conf;
import java.lang.reflect.Method;
import org.springframework.cache.CacheManager;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
@Configuration
public class RedisConfig{
/**
* key
* @return
*/
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
/**
*
*/
@SuppressWarnings("rawtypes")
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
return rcm;
}
/**
* RedisTemplate
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@Bean
@Primary
public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
@Bean("redisTemplateObj")
public RedisTemplate redisTemplateObj(RedisConnectionFactory factory) {
RedisTemplate template = new RedisTemplate();
template.setConnectionFactory(factory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new RedisObjectSerializer());
return template;
}
}
3.RedisはshiroのSessionDaoアクセスセッションを実現する
package com.st.shiro.dao;
import java.io.Serializable;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import com.st.shiro.conf.STShiroConf;
import com.st.shiro.constant.RedisConstant;
@Component
public class RedisSessionDAO extends EnterpriseCacheSessionDAO {
private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class);
@Autowired
private STShiroConf sTShiroConf;
private static String prefix = RedisConstant.SHIRO_SESSION+":";
@Resource(name="redisTemplateObj")
private RedisTemplate redisTemplate;
// session,
@Override
protected Serializable doCreate(Session session) {
Serializable sessionId = super.doCreate(session);
logger.debug(" session:{}", session.getId());
redisTemplate.opsForValue().set(prefix + sessionId.toString(), session,sTShiroConf.getSessionTimeout(),TimeUnit.SECONDS);
return sessionId;
}
// session
@Override
protected Session doReadSession(Serializable sessionId) {
logger.debug(" session:{}", sessionId);
// session,
Session session = super.doReadSession(sessionId);
if (session == null) {
session = (Session) redisTemplate.opsForValue().get(prefix + sessionId.toString());
}
return session;
}
// session
@Override
protected void doUpdate(Session session) {
super.doUpdate(session);
logger.debug(" session:{}", session.getId());
String key = prefix + session.getId().toString();
if (!redisTemplate.hasKey(key)) {
redisTemplate.opsForValue().set(key, session);
}
redisTemplate.expire(key, sTShiroConf.getSessionTimeout(), TimeUnit.SECONDS);
}
// session
@Override
protected void doDelete(Session session) {
logger.debug(" session:{}", session.getId());
super.doDelete(session);
redisTemplate.delete(prefix + session.getId().toString());
}
}
4.cache共有の実現
package com.st.shiro.cache;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.data.redis.core.RedisTemplate;
import com.st.shiro.constant.RedisConstant;
public class ShiroCache implements Cache {
private static final String REDIS_SHIRO_CACHE =RedisConstant.SHIRO_CACHE;
private String cacheKey;
@Resource(name="redisTemplateObj")
private RedisTemplate redisTemplate;
private long globExpire = 1800;
@SuppressWarnings({ "rawtypes", "unchecked" })
public ShiroCache(String name, RedisTemplate redisTemplate) {
this.cacheKey = REDIS_SHIRO_CACHE+":"+ name + ":";
this.redisTemplate = redisTemplate;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public ShiroCache(String name, RedisTemplate redisTemplate,long globExpire) {
this.cacheKey = REDIS_SHIRO_CACHE+":"+ name + ":";
this.redisTemplate = redisTemplate;
this.globExpire=globExpire;
}
@Override
public V get(K key) throws CacheException {
redisTemplate.boundValueOps(getCacheKey(key)).expire(globExpire, TimeUnit.MINUTES);
return redisTemplate.boundValueOps(getCacheKey(key)).get();
}
@Override
public V put(K key, V value) throws CacheException {
V old = get(key);
redisTemplate.boundValueOps(getCacheKey(key)).set(value);
return old;
}
@Override
public V remove(K key) throws CacheException {
V old = get(key);
redisTemplate.delete(getCacheKey(key));
return old;
}
@Override
public void clear() throws CacheException {
redisTemplate.delete(keys());
}
@Override
public int size() {
return keys().size();
}
@Override
public Set keys() {
return redisTemplate.keys(getCacheKey("*"));
}
@Override
public Collection values() {
Set set = keys();
List list = new ArrayList();
for (K s : set) {
list.add(get(s));
}
return list;
}
@SuppressWarnings("unchecked")
private K getCacheKey(Object k) {
return (K) (this.cacheKey + k);
}
}
shiroを実現するCacheManager
package com.st.shiro.cache;
import javax.annotation.Resource;
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;
public class RedisCacheManager implements CacheManager {
private long globExpire=1800;
public RedisCacheManager(){
}
public RedisCacheManager(Long globExpire){
}
@Resource(name="redisTemplateObj")
private RedisTemplate redisTemplate;
@Override
public Cache getCache(String name) throws CacheException {
return new ShiroCache(name, redisTemplate,globExpire);
}
}
5.構成
package com.st.shiro.conf;
import java.util.HashMap;
import java.util.Map;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import com.st.common.util.AssertUtil;
import com.st.shiro.cache.RedisCacheManager;
import com.st.shiro.dao.RedisSessionDAO;
import com.st.shiro.realm.MyShiroRealm;
/**
* shiro
* @author ming
*
*/
@Configuration
@Order(2)
public class ShiroConfiguration {
private static final Logger logger = LoggerFactory.getLogger(ShiroConfiguration.class);
/*@Bean
public EhCacheManager getEhCacheManager() {
EhCacheManager em = new EhCacheManager();
em.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
return em;
} */
@Bean
public MyShiroRealm myShiroRealm() {
MyShiroRealm myShiroRealm=new MyShiroRealm();
//myShiroRealm.setCacheManager(getEhCacheManager());
return myShiroRealm;
}
@Bean
public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public RedisCacheManager redisCacheManager() {
return new RedisCacheManager();
}
@Bean
public RedisSessionDAO redisSessionDAO(){
return new RedisSessionDAO();
}
@Bean
public SessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionDAO(redisSessionDAO());
sessionManager.setGlobalSessionTimeout(getSTShiroConf().getSessionTimeout());
sessionManager.setCacheManager(redisCacheManager());
sessionManager.setDeleteInvalidSessions(true);// session
sessionManager.setSessionIdCookieEnabled(true);
sessionManager.setSessionIdCookie(sessionIdCookie());
return sessionManager;
}
// cookie
@Bean
public Cookie sessionIdCookie(){
Cookie sessionIdCookie=new SimpleCookie("STID");
sessionIdCookie.setMaxAge(-1);
sessionIdCookie.setHttpOnly(true);
return sessionIdCookie;
}
@Bean
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// realm
securityManager.setRealm(myShiroRealm());
// session
securityManager.setSessionManager(sessionManager());
// cache
securityManager.setCacheManager(redisCacheManager());
return securityManager;
}
@Bean
public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
aasa.setSecurityManager(securityManager());
return new AuthorizationAttributeSourceAdvisor();
}
@Bean
public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
daap.setProxyTargetClass(true);
return daap;
}
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean() {
Map filterChainDefinitionMap = new HashMap();
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager());
shiroFilterFactoryBean.setLoginUrl(getSTShiroConf().getLoginView());
shiroFilterFactoryBean.setSuccessUrl(getSTShiroConf().getSuccessUrl());
logger.info("*************************** , shiroFilter *****************************");
//
if(!AssertUtil.isEmpty(this.getSTShiroConf().getSysanon())){
for(String str:this.getSTShiroConf().getSysanon()){
filterChainDefinitionMap.put(str, "anon");
logger.debug("shiro:["+str+":"+"anon"+"]");
}
}
filterChainDefinitionMap.put("/**", "authc");
//filterChainDefinitionMap.put("/**", "anon");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
/**
* st-shiro
* @return
*/
@ConfigurationProperties(prefix="st.shiro.conf")
@Bean("sTShiroConf")
@Primary
public STShiroConf getSTShiroConf(){
return new STShiroConf();
}
}
6、Realm
package com.st.shiro.realm;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.PostConstruct;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.st.shiro.conf.STShiroConf;
import com.st.shiro.dto.CommentCodeVO;
import com.st.shiro.dto.SysUser;
import com.st.shiro.service.STShiroService;
public class MyShiroRealm extends AuthorizingRealm {
private static final Logger logger = LoggerFactory.getLogger(MyShiroRealm.class);
@Autowired
private STShiroService sTShiroService;
@Autowired
private STShiroConf sTShiroConf;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
logger.info("*************************** Shiro ******************************");
// , (String) principalCollection.fromRealm(getName()).iterator().next();
String loginName = (String)super.getAvailablePrincipal(principalCollection);
//
SysUser user=sTShiroService.getUserByUid(loginName);
if(user!=null){
// info, (role) (permission)
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
//
Set roles=sTShiroService.getRoleByUserId(user.getId());
if(roles!=null){
Set roleSet=new HashSet();
List roleIds=new ArrayList();
for(CommentCodeVO vo:roles){
roleSet.add(vo.getCode());
roleIds.add(vo.getId());
}
//
info.setRoles(roleSet);
Set permission=sTShiroService.getPermissionsByRoleId(roleIds);
if(permission!=null){
info.addStringPermissions(permission);
}
}
return info;
}
// null , , unauthorizedUrl
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
logger.info("*************************** Shiro ******************************");
//UsernamePasswordToken
UsernamePasswordToken token=(UsernamePasswordToken) authenticationToken;
logger.info(" Subject token :"+token);
//
SysUser user=sTShiroService.getUserByUid(token.getUsername());
if(user!=null){
// , info , ,Shiro
return new SimpleAuthenticationInfo(user.getLoginAccount(), user.getLoginPass(),ByteSource.Util.bytes(user.getSalt()),getName());
}
return null;
}
/**
*
*/
@PostConstruct
public void initCredentialsMatcher() {
HashedCredentialsMatcher matcher=new HashedCredentialsMatcher(sTShiroConf.getAlgorithmName());
matcher.setHashIterations(sTShiroConf.getHashIterations());
setCredentialsMatcher(matcher);
}
}
7、shiro配置(yml)
st:
#Shiro
shiro:
conf:
domain: .midea.com
cookiePath: /
successUrl: /index
loginView: /login
openToken: false
sessionTimeout: 1800000
algorithmName: md5
hashIterations: 5
#
sysanon:
- /login
- /regist
#
allowedOrigins:
- /**
8、STShiroConf配置
package com.st.shiro.conf;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* shiro
* @author ming
*
*/
//@Component
@ConfigurationProperties(prefix="st.shiro.conf")
public class STShiroConf {
/**
*
*/
private String algorithmName;
/**
*
*/
private int hashIterations;
/**
*
*/
private List sysanon;
/**
*
*/
private List allowedOrigins;
/**
*
*/
private String loginView;
/**
*
*/
private String successUrl;
/**
* token
*/
private boolean openToken;
/**
* session
*/
private Long sessionTimeout;
/**
* Cookie
*/
private String domain;
/**
* Cookie
*/
private String cookiePath;
/**
* cookie
*/
private String cookieName;
/**
* cookie
*/
private int cookieMaxAge;
/**
* token
*/
private String tokenName;
/**
*
*/
private boolean openSSO;
public String getAlgorithmName() {
return algorithmName;
}
public void setAlgorithmName(String algorithmName) {
this.algorithmName = algorithmName;
}
public int getHashIterations() {
return hashIterations;
}
public void setHashIterations(int hashIterations) {
this.hashIterations = hashIterations;
}
public List getSysanon() {
return sysanon;
}
public void setSysanon(List sysanon) {
this.sysanon = sysanon;
}
public List getAllowedOrigins() {
return allowedOrigins;
}
public void setAllowedOrigins(List allowedOrigins) {
this.allowedOrigins = allowedOrigins;
}
public String getLoginView() {
return loginView;
}
public void setLoginView(String loginView) {
this.loginView = loginView;
}
public String getSuccessUrl() {
return successUrl;
}
public void setSuccessUrl(String successUrl) {
this.successUrl = successUrl;
}
public boolean isOpenToken() {
return openToken;
}
public void setOpenToken(boolean openToken) {
this.openToken = openToken;
}
public Long getSessionTimeout() {
return sessionTimeout;
}
public void setSessionTimeout(Long sessionTimeout) {
this.sessionTimeout = sessionTimeout;
}
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
public String getCookiePath() {
return cookiePath;
}
public void setCookiePath(String cookiePath) {
this.cookiePath = cookiePath;
}
public String getCookieName() {
return cookieName;
}
public void setCookieName(String cookieName) {
this.cookieName = cookieName;
}
public int getCookieMaxAge() {
return cookieMaxAge;
}
public void setCookieMaxAge(int cookieMaxAge) {
this.cookieMaxAge = cookieMaxAge;
}
public String getTokenName() {
return tokenName;
}
public void setTokenName(String tokenName) {
this.tokenName = tokenName;
}
public boolean isOpenSSO() {
return openSSO;
}
public void setOpenSSO(boolean openSSO) {
this.openSSO = openSSO;
}
}
何度もredisからsession問題を獲得してまだ解決していないで、各位の大神に解決策をあげることを求めます
コンポーネントプロジェクトのソースリンク:http://download.csdn.net/download/qq_16055765/10247345