本篇文章是基于前几篇spring boot shiro redis的基础上,如果未看前几篇建议先看前几篇
4:spring boot shiro redis整合遇到的问题
spring boot shiro 使用redis对session进行管理请看 第3篇文章
shiro的认证,授权信息 也可以交给redis管理
本篇文章会和之前的使用redis管理session的那篇文章有些区别,对session的管理进行了重新实现
shiro的认证,授权信息 有redis管理的思想是:
shiro的认证,授权信息本身支持存放到缓存中,只需把之前shiro默认的ehcache缓存更换成redis缓存即可。
shiro 配置文件如下:重点的会使用红色标注:
package com.zyc.springboot.config;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.Filter;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.session.SessionListener;
import org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler;
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.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.filter.DelegatingFilterProxy;
import com.zyc.springboot.shiro.MyFormAuthenticationFilter;
import com.zyc.springboot.shiro.MyRealm;
import com.zyc.springboot.shiro.MyShiroSessionListener;
import com.zyc.springboot.shiro.RedisUtil;
import com.zyc.springboot.shiro.SessionDao;
import com.zyc.springboot.shiro.ShiroRedisCacheManager;
@Configuration
public class ShiroConfig {
/*@Bean(name = "shiroEhcacheManager")
public EhCacheManager getEhCacheManager() {
EhCacheManager em = new EhCacheManager();
em.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
return em;
}*/
@Bean(name="shiroRedisCacheManager")
public ShiroRedisCacheManager shiroRedisCacheManager(RedisTemplate redisTemplate){
ShiroRedisCacheManager shiroRedisCacheManager=new ShiroRedisCacheManager();
shiroRedisCacheManager.setRedisTemplate(redisTemplate);
return shiroRedisCacheManager;
}
@Bean(name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
LifecycleBeanPostProcessor lifecycleBeanPostProcessor = new LifecycleBeanPostProcessor();
return lifecycleBeanPostProcessor;
}
@Bean(name = "sessionValidationScheduler")
public ExecutorServiceSessionValidationScheduler getExecutorServiceSessionValidationScheduler(DefaultWebSessionManager defaultWebSessionManager) {
ExecutorServiceSessionValidationScheduler scheduler = new ExecutorServiceSessionValidationScheduler();
scheduler.setInterval(50*1000);
scheduler.setSessionManager(defaultWebSessionManager);
return scheduler;
}
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");// 散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashIterations(1);// 散列的次数,比如散列两次,相当于md5(md5(""));
hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
return hashedCredentialsMatcher;
}
@Bean(name = "defaultWebSecurityManager")
public DefaultWebSecurityManager defaultWebSecurityManager(MyRealm myRealm,DefaultWebSessionManager defaultWebSessionManager,ShiroRedisCacheManager shiroRedisCacheManager) {
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
defaultWebSecurityManager.setRealm(myRealm);
//defaultWebSecurityManager.setCacheManager(getEhCacheManager());
defaultWebSecurityManager.setCacheManager(shiroRedisCacheManager);
defaultWebSecurityManager.setSessionManager(defaultWebSessionManager);
defaultWebSecurityManager.setRememberMeManager(rememberMeManager());
return defaultWebSecurityManager;
}
@Bean(name = "rememberMeCookie")
public SimpleCookie rememberMeCookie() {
// 这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
// <!-- 记住我cookie生效时间30天 ,单位秒;-->
simpleCookie.setMaxAge(60*60*24*30);
return simpleCookie;
}
/**
* cookie管理对象;
*
* @return
*/
@Bean(name = "rememberMeManager")
public CookieRememberMeManager rememberMeManager() {
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
byte[] cipherKey = Base64.decode("wGiHplamyXlVB11UXWol8g==");
cookieRememberMeManager.setCipherKey(cipherKey);
return cookieRememberMeManager;
}
@Bean
@DependsOn(value = "lifecycleBeanPostProcessor")
public MyRealm myRealm(ShiroRedisCacheManager shiroRedisCacheManager) {
MyRealm myRealm = new MyRealm();
//启用缓存
myRealm.setCachingEnabled(true);
//启用授权缓存
myRealm.setAuthorizationCachingEnabled(true);
myRealm.setAuthorizationCacheName("shiro-AutorizationCache");
//启用认证信息缓存
myRealm.setAuthenticationCachingEnabled(true);
myRealm.setAuthenticationCacheName("shiro-AuthenticationCache");
myRealm.setCacheManager(shiroRedisCacheManager);
myRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return myRealm;
}
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator getAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true);
return creator;
}
@Bean
public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager defaultWebSecurityManager) {
AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
aasa.setSecurityManager(defaultWebSecurityManager);
return aasa;
}
@Bean(name = "sessionManager")
public DefaultWebSessionManager defaultWebSessionManager(SessionDao sessionDao) {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setGlobalSessionTimeout(1000*60*60*24*60);
// //url中是否显示session Id
sessionManager.setSessionIdUrlRewritingEnabled(false);
// // 删除失效的session
sessionManager.setDeleteInvalidSessions(true);
sessionManager.setSessionValidationSchedulerEnabled(true);
sessionManager.setSessionValidationInterval(18000000);
sessionManager.setSessionValidationScheduler(getExecutorServiceSessionValidationScheduler(sessionManager));
//sessionManager.setSessionValidationScheduler(quartzSessionValidationScheduler2(sessionManager));
//设置SessionIdCookie 导致认证不成功,不从新设置新的cookie,从sessionManager获取sessionIdCookie
//sessionManager.setSessionIdCookie(simpleIdCookie());
sessionManager.getSessionIdCookie().setName("session-z-id");
sessionManager.getSessionIdCookie().setPath("/");
sessionManager.getSessionIdCookie().setMaxAge(60*60*24*7);
sessionManager.setSessionDAO(sessionDao);
Collection<SessionListener> c=new ArrayList<>();
c.add(new MyShiroSessionListener());
sessionManager.setSessionListeners(c);
return sessionManager;
}
// @Bean
// public QuartzSessionValidationScheduler2 quartzSessionValidationScheduler2(DefaultWebSessionManager sessionManager){
// QuartzSessionValidationScheduler2 quartzSessionValidationScheduler2=new QuartzSessionValidationScheduler2();
// quartzSessionValidationScheduler2.setSessionManager(sessionManager);
// quartzSessionValidationScheduler2.setSessionValidationInterval(1000*5);
// return quartzSessionValidationScheduler2;
// }
@Bean
public SessionDao sessionDao(RedisUtil redisUtil,ShiroRedisCacheManager shiroRedisCacheManager) {
SessionDao sessionDao = new SessionDao();
//设置缓存器的名称
sessionDao.setActiveSessionsCacheName("shiro-activeSessionCache1");
//注入缓存管理器默认的是ehcache缓存
sessionDao.setCacheManager(shiroRedisCacheManager);
//注入缓存管理器2(实现session由redis控制有多种方法,上一步是一种,下面这样写也行)
sessionDao.setRedisUtil(redisUtil);
return sessionDao;
}
@Bean
public RedisUtil redisUtil(RedisTemplate<String,Object> redisTemplate) {
RedisUtil redisUtil = new RedisUtil();
redisUtil.setRedisTemplate(redisTemplate);
return redisUtil;
}
@Bean(name = "filterRegistrationBean1")
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new DelegatingFilterProxy(
"shiroFilter"));
filterRegistrationBean
.addInitParameter("targetFilterLifecycle", "true");
filterRegistrationBean.setEnabled(true);
filterRegistrationBean.addUrlPatterns("/");
// filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST,
// DispatcherType.FORWARD, DispatcherType.INCLUDE,
// DispatcherType.ERROR);
return filterRegistrationBean;
}
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(
@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
// SecurityUtils.setSecurityManager(defaultWebSecurityManager);
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSuccessUrl("/getIndex");
shiroFilterFactoryBean.setUnauthorizedUrl("/login");
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
Map<String, Filter> filterMap1 = shiroFilterFactoryBean.getFilters();
filterMap1.put("authc", new MyFormAuthenticationFilter());
shiroFilterFactoryBean.setFilters(filterMap1);
Map<String, String> filterMap = new LinkedHashMap<String, String>();
filterMap.put("/static/**", "anon");
filterMap.put("/api/**", "anon");
filterMap.put("/logout", "anon");
filterMap.put("/login", "authc");
filterMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
}
@Bean(name="shiroRedisCacheManager")
public ShiroRedisCacheManager shiroRedisCacheManager(RedisTemplate redisTemplate){
ShiroRedisCacheManager shiroRedisCacheManager=new ShiroRedisCacheManager();
shiroRedisCacheManager.setRedisTemplate(redisTemplate);
return shiroRedisCacheManager;
}
@Bean(name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
LifecycleBeanPostProcessor lifecycleBeanPostProcessor = new LifecycleBeanPostProcessor();
return lifecycleBeanPostProcessor;
}
@Bean(name = "sessionValidationScheduler")
public ExecutorServiceSessionValidationScheduler getExecutorServiceSessionValidationScheduler(DefaultWebSessionManager defaultWebSessionManager) {
ExecutorServiceSessionValidationScheduler scheduler = new ExecutorServiceSessionValidationScheduler();
scheduler.setInterval(50*1000);
scheduler.setSessionManager(defaultWebSessionManager);
return scheduler;
}
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
hashedCredentialsMatcher.setHashAlgorithmName("md5");// 散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashIterations(1);// 散列的次数,比如散列两次,相当于md5(md5(""));
hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
return hashedCredentialsMatcher;
}
@Bean(name = "defaultWebSecurityManager")
public DefaultWebSecurityManager defaultWebSecurityManager(MyRealm myRealm,DefaultWebSessionManager defaultWebSessionManager,ShiroRedisCacheManager shiroRedisCacheManager) {
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
defaultWebSecurityManager.setRealm(myRealm);
//defaultWebSecurityManager.setCacheManager(getEhCacheManager());
defaultWebSecurityManager.setCacheManager(shiroRedisCacheManager);
defaultWebSecurityManager.setSessionManager(defaultWebSessionManager);
defaultWebSecurityManager.setRememberMeManager(rememberMeManager());
return defaultWebSecurityManager;
}
@Bean(name = "rememberMeCookie")
public SimpleCookie rememberMeCookie() {
// 这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
// <!-- 记住我cookie生效时间30天 ,单位秒;-->
simpleCookie.setMaxAge(60*60*24*30);
return simpleCookie;
}
/**
* cookie管理对象;
*
* @return
*/
@Bean(name = "rememberMeManager")
public CookieRememberMeManager rememberMeManager() {
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
byte[] cipherKey = Base64.decode("wGiHplamyXlVB11UXWol8g==");
cookieRememberMeManager.setCipherKey(cipherKey);
return cookieRememberMeManager;
}
@Bean
@DependsOn(value = "lifecycleBeanPostProcessor")
public MyRealm myRealm(ShiroRedisCacheManager shiroRedisCacheManager) {
MyRealm myRealm = new MyRealm();
//启用缓存
myRealm.setCachingEnabled(true);
//启用授权缓存
myRealm.setAuthorizationCachingEnabled(true);
myRealm.setAuthorizationCacheName("shiro-AutorizationCache");
//启用认证信息缓存
myRealm.setAuthenticationCachingEnabled(true);
myRealm.setAuthenticationCacheName("shiro-AuthenticationCache");
myRealm.setCacheManager(shiroRedisCacheManager);
myRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return myRealm;
}
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator getAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true);
return creator;
}
@Bean
public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager defaultWebSecurityManager) {
AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
aasa.setSecurityManager(defaultWebSecurityManager);
return aasa;
}
@Bean(name = "sessionManager")
public DefaultWebSessionManager defaultWebSessionManager(SessionDao sessionDao) {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setGlobalSessionTimeout(1000*60*60*24*60);
// //url中是否显示session Id
sessionManager.setSessionIdUrlRewritingEnabled(false);
// // 删除失效的session
sessionManager.setDeleteInvalidSessions(true);
sessionManager.setSessionValidationSchedulerEnabled(true);
sessionManager.setSessionValidationInterval(18000000);
sessionManager.setSessionValidationScheduler(getExecutorServiceSessionValidationScheduler(sessionManager));
//sessionManager.setSessionValidationScheduler(quartzSessionValidationScheduler2(sessionManager));
//设置SessionIdCookie 导致认证不成功,不从新设置新的cookie,从sessionManager获取sessionIdCookie
//sessionManager.setSessionIdCookie(simpleIdCookie());
sessionManager.getSessionIdCookie().setName("session-z-id");
sessionManager.getSessionIdCookie().setPath("/");
sessionManager.getSessionIdCookie().setMaxAge(60*60*24*7);
sessionManager.setSessionDAO(sessionDao);
Collection<SessionListener> c=new ArrayList<>();
c.add(new MyShiroSessionListener());
sessionManager.setSessionListeners(c);
return sessionManager;
}
// @Bean
// public QuartzSessionValidationScheduler2 quartzSessionValidationScheduler2(DefaultWebSessionManager sessionManager){
// QuartzSessionValidationScheduler2 quartzSessionValidationScheduler2=new QuartzSessionValidationScheduler2();
// quartzSessionValidationScheduler2.setSessionManager(sessionManager);
// quartzSessionValidationScheduler2.setSessionValidationInterval(1000*5);
// return quartzSessionValidationScheduler2;
// }
@Bean
public SessionDao sessionDao(RedisUtil redisUtil,ShiroRedisCacheManager shiroRedisCacheManager) {
SessionDao sessionDao = new SessionDao();
//设置缓存器的名称
sessionDao.setActiveSessionsCacheName("shiro-activeSessionCache1");
//注入缓存管理器默认的是ehcache缓存
sessionDao.setCacheManager(shiroRedisCacheManager);
//注入缓存管理器2(实现session由redis控制有多种方法,上一步是一种,下面这样写也行)
sessionDao.setRedisUtil(redisUtil);
return sessionDao;
}
@Bean
public RedisUtil redisUtil(RedisTemplate<String,Object> redisTemplate) {
RedisUtil redisUtil = new RedisUtil();
redisUtil.setRedisTemplate(redisTemplate);
return redisUtil;
}
@Bean(name = "filterRegistrationBean1")
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new DelegatingFilterProxy(
"shiroFilter"));
filterRegistrationBean
.addInitParameter("targetFilterLifecycle", "true");
filterRegistrationBean.setEnabled(true);
filterRegistrationBean.addUrlPatterns("/");
// filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST,
// DispatcherType.FORWARD, DispatcherType.INCLUDE,
// DispatcherType.ERROR);
return filterRegistrationBean;
}
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(
@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
// SecurityUtils.setSecurityManager(defaultWebSecurityManager);
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSuccessUrl("/getIndex");
shiroFilterFactoryBean.setUnauthorizedUrl("/login");
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
Map<String, Filter> filterMap1 = shiroFilterFactoryBean.getFilters();
filterMap1.put("authc", new MyFormAuthenticationFilter());
shiroFilterFactoryBean.setFilters(filterMap1);
Map<String, String> filterMap = new LinkedHashMap<String, String>();
filterMap.put("/static/**", "anon");
filterMap.put("/api/**", "anon");
filterMap.put("/logout", "anon");
filterMap.put("/login", "authc");
filterMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
}
ShiroRedisCacheManager实现如下:
package com.zyc.springboot.shiro;
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;
/**
* ClassName: ShiroRedisCacheManager
* @author zyc-admin
* @date 2018年3月1日
* @Description: TODO
*/
public class ShiroRedisCacheManager implements CacheManager {
private RedisTemplate<String, Object> redisTemplate;
public RedisTemplate<String, Object> getRedisTemplate() {
return redisTemplate;
}
public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Override
public <K, V> Cache<K, V> getCache(String arg0) throws CacheException {
// TODO Auto-generated method stub
return new ShiroRedisCache<>(arg0,redisTemplate);
}
}
ShiroRedisCache实现如下:
package com.zyc.springboot.shiro;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.data.redis.core.RedisTemplate;
/**
* ClassName: ShiroRedisCache
*
* @author zyc-admin
* @date 2018年3月1日
* @Description: TODO
*/
@SuppressWarnings("unchecked")
public class ShiroRedisCache<K, V> implements Cache<K, V> {
private String cacheKey;
private RedisTemplate redisTemplate;
public ShiroRedisCache(String name, RedisTemplate redisTemplate) {
this.cacheKey="shiro:cache:" + name + ":";
this.redisTemplate=redisTemplate;
}
@Override
public void clear() throws CacheException {
// TODO Auto-generated method stub
redisTemplate.delete(keys());
}
@Override
public V get(K arg0) throws CacheException {
return (V) redisTemplate.opsForValue().get(getCacheKey(arg0));
}
@Override
public Set<K> keys() {
return redisTemplate.keys(getCacheKey("*"));
}
@Override
public V put(K arg0, V arg1) throws CacheException {
V old = get(arg0);
redisTemplate.boundValueOps(getCacheKey(arg0)).set(arg1);
redisTemplate.expire(getCacheKey(arg0), 1, TimeUnit.HOURS);
return old;
}
@Override
public V remove(K arg0) throws CacheException {
V old = get(arg0);
redisTemplate.delete(getCacheKey(arg0));
return old;
}
@Override
public int size() {
return keys().size();
}
@Override
public Collection<V> values() {
Set<K> keys = keys();
List<V> list = new ArrayList<>();
for (K s : keys) {
list.add(get(s));
}
return list;
}
public String getCacheKey() {
return cacheKey;
}
public K getCacheKey(Object arg0) {
return (K) (cacheKey + arg0);
}
public void setCacheKey(String cacheKey) {
this.cacheKey = cacheKey;
}
public RedisTemplate getRedisTemplate() {
return redisTemplate;
}
public void setRedisTemplate(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
}
对shiro的认证,授权信息 缓存 还需要对MyRealm进行部分重写如下:在退出的时候清除缓存(你也可不清除,看自己项目需求)
package com.zyc.springboot.shiro;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.beanutils.BeanUtils;
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.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.subject.PrincipalCollection;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zyc.springboot.entity.User;
import com.zyc.springboot.service.AccountService;
import com.zyc.springboot.util.SpringContext;
public class MyRealm extends AuthorizingRealm {
@Override
public CacheManager getCacheManager() {
// TODO Auto-generated method stub
return super.getCacheManager();
}
/**
* 权限认证
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
System.out.println("授权=====");
// 获取登录用户的信息,在认证时存储的是ShiroUser 所以得到的就是ShiroUser
// 在其他地方也可通过SecurityUtils.getSubject().getPrincipals()获取用户信息
String userName = principals.getPrimaryPrincipal().toString();
// 权限字符串
List<String> permissions = new ArrayList<>();
// 从数据库中获取对应权限字符串并存储permissions
permissions.add("111");
// 角色字符串
List<String> roles = new ArrayList<>();
// 从数据库中获取对应角色字符串并存储roles
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
simpleAuthorizationInfo.addStringPermissions(permissions);
simpleAuthorizationInfo.addRoles(roles);// 角色类型
return simpleAuthorizationInfo;
}
/**
* 登录验证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken arg0) throws AuthenticationException {
System.out.println("认证=====");
String userName = ((MyAuthenticationToken) arg0).getUsername();
char[] password = ((MyAuthenticationToken) arg0).getPassword();
User user = new User();// 根据用户名密码获取user
Object obj = new SimpleHash("md5", new String(password), null, 1);
user.setPassword(obj.toString());
user.setUserName(userName);
user = ((AccountService) SpringContext.getBean("accountService"))
.findByPw(user);
if (user == null) {
throw new AuthenticationException("用户名密码错误");
}
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
userName, user.getPassword(), this.getName());
return simpleAuthenticationInfo;
}
@Override
protected void doClearCache(PrincipalCollection principals) {
// TODO Auto-generated method stub
super.doClearCache(principals);
clearCachedAuthenticationInfo(principals);
clearCachedAuthorizationInfo(principals);
}
@Override
protected void clearCachedAuthenticationInfo(PrincipalCollection principals) {
// TODO Auto-generated method stub
super.clearCachedAuthenticationInfo(principals);
Object key = principals.getPrimaryPrincipal();
// ShiroUser shiroUser=new ShiroUser();
// try {
// BeanUtils.copyProperties(shiroUser, key);
// } catch (Exception e) {
// // TODO Auto-generated catch block
// }
getAuthenticationCache().remove(key);
}
@Override
protected void clearCachedAuthorizationInfo(PrincipalCollection principals) {
// TODO Auto-generated method stub
super.clearCachedAuthorizationInfo(principals);
Object key = getAuthorizationCacheKey(principals);
getAuthorizationCache().remove(key);
}
protected Object getAuthorizationCacheKey(PrincipalCollection principals) {
return principals.getPrimaryPrincipal();
}
}
@Override
protected void doClearCache(PrincipalCollection principals) {
// TODO Auto-generated method stub
super.doClearCache(principals);
clearCachedAuthenticationInfo(principals);
clearCachedAuthorizationInfo(principals);
}
@Override
protected void clearCachedAuthenticationInfo(PrincipalCollection principals) {
// TODO Auto-generated method stub
super.clearCachedAuthenticationInfo(principals);
Object key = principals.getPrimaryPrincipal();
// ShiroUser shiroUser=new ShiroUser();
// try {
// BeanUtils.copyProperties(shiroUser, key);
// } catch (Exception e) {
// // TODO Auto-generated catch block
// }
getAuthenticationCache().remove(key);
}
@Override
protected void clearCachedAuthorizationInfo(PrincipalCollection principals) {
// TODO Auto-generated method stub
super.clearCachedAuthorizationInfo(principals);
Object key = getAuthorizationCacheKey(principals);
getAuthorizationCache().remove(key);
}
protected Object getAuthorizationCacheKey(PrincipalCollection principals) {
return principals.getPrimaryPrincipal();
}
}
本篇redis缓存sessio的代码改动了如下:主要是sessiondao本身也支持缓存,之前没发现,现在使用自带的功能加以修正,简单方便
package com.zyc.springboot.shiro;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.SimpleSession;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
public class SessionDao extends EnterpriseCacheSessionDAO {
private String cacheKey="shiro:cache:shiro-activeSessionCache1:";
private RedisUtil redisUtil;
public RedisUtil getRedisUtil() {
return redisUtil;
}
public void setRedisUtil(RedisUtil redisUtil) {
this.redisUtil = redisUtil;
}
// 创建session,保存到数据库
@Override
protected Serializable doCreate(Session session) {
@SuppressWarnings("unused")
Serializable sessionId = super.doCreate(session);
//redisUtil.set(cacheKey+session.getId().toString(), sessionToByte(session),1*60L);
getCacheManager().getCache("shiro-activeSessionCache1").put(session.getId().toString(), session);
return session.getId();
}
// 获取session
@Override
protected Session doReadSession(Serializable sessionId) {
// 先从缓存中获取session,如果没有再去数据库中获取
//Session session = super.doReadSession(sessionId);
// if(session == null){
// byte[] bytes = (byte[]) redisUtil.get(sessionId.toString());
// if(bytes != null && bytes.length > 0){
// session = byteToSession(bytes);
// }
// }
Session session = getActiveSessionsCache().get(sessionId);
return session;
}
// 更新session的最后一次访问时间
@Override
protected void doUpdate(Session session) {
super.doUpdate(session);
//redisUtil.set(session.getId().toString(), sessionToByte(session),1*60L);
getActiveSessionsCache().put(session.getId().toString(), session);
}
// 删除session
@Override
protected void doDelete(Session session) {
System.out.println("doDelete......");
// super.doDelete(session);
// redisUtil.remove(session.getId().toString());
getActiveSessionsCache().remove(session.getId().toString());
}
// 把session对象转化为byte保存到redis中
public byte[] sessionToByte(Session session){
ByteArrayOutputStream bo = new ByteArrayOutputStream();
byte[] bytes = null;
try {
ObjectOutput oo = new ObjectOutputStream(bo);
oo.writeObject(session);
bytes = bo.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return bytes;
}
// 把byte还原为session
public Session byteToSession(byte[] bytes){
ByteArrayInputStream bi = new ByteArrayInputStream(bytes);
ObjectInputStream in;
SimpleSession session = null;
try {
in = new ObjectInputStream(bi);
session = (SimpleSession) in.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return session;
}
}
getCacheManager().getCache("shiro-activeSessionCache1").put(session.getId().toString(), session);
return session.getId();
}
// 获取session
@Override
protected Session doReadSession(Serializable sessionId) {
// 先从缓存中获取session,如果没有再去数据库中获取
//Session session = super.doReadSession(sessionId);
// if(session == null){
// byte[] bytes = (byte[]) redisUtil.get(sessionId.toString());
// if(bytes != null && bytes.length > 0){
// session = byteToSession(bytes);
// }
// }
Session session = getActiveSessionsCache().get(sessionId);
return session;
}
// 更新session的最后一次访问时间
@Override
protected void doUpdate(Session session) {
super.doUpdate(session);
//redisUtil.set(session.getId().toString(), sessionToByte(session),1*60L);
getActiveSessionsCache().put(session.getId().toString(), session);
}
// 删除session
@Override
protected void doDelete(Session session) {
System.out.println("doDelete......");
// super.doDelete(session);
// redisUtil.remove(session.getId().toString());
getActiveSessionsCache().remove(session.getId().toString());
}
// 把session对象转化为byte保存到redis中
public byte[] sessionToByte(Session session){
ByteArrayOutputStream bo = new ByteArrayOutputStream();
byte[] bytes = null;
try {
ObjectOutput oo = new ObjectOutputStream(bo);
oo.writeObject(session);
bytes = bo.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return bytes;
}
// 把byte还原为session
public Session byteToSession(byte[] bytes){
ByteArrayInputStream bi = new ByteArrayInputStream(bytes);
ObjectInputStream in;
SimpleSession session = null;
try {
in = new ObjectInputStream(bi);
session = (SimpleSession) in.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return session;
}
}
package com.zyc.zspringboot.shiro;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.SessionListener;
import com.zyc.zspringboot.util.SpringContext;
public class MyShiroSessionListener implements SessionListener {
@Override
public void onStart(Session session) {
}
@Override
public void onStop(Session session) {
// TODO 退出登录时,先调用此方法,然后会继续调用SessionDao中的doDelete方法
System.out.println("onStop===" + session.getId());
RedisUtil redisUtil = (RedisUtil) SpringContext.getBean("redisUtil");
// 清除session
redisUtil.remove(session.getId().toString());
// 清除缓存
redisUtil.remove("shiro:cache:shiro-activeSessionCache1:"
+ session.getId().toString());
}
@Override
public void onExpiration(Session session) {
System.out.println("onExpiration===" + session.getId());
RedisUtil redisUtil = (RedisUtil) SpringContext.getBean("redisUtil");
// 清除session
redisUtil.remove(session.getId().toString());
// 清除缓存
redisUtil.remove("shiro:cache:shiro-activeSessionCache1:"
+ session.getId().toString());
}
}
整合完毕,如果遇到部分问题,可以看之前写的几篇文章中是否已经提到并解决,也可留言提出问题,我及时更新改正