我们在上一遍文档中已经完成了Shiro验证功能。(http://www.cnblogs.com/nbfujx/p/7773789.html),在此基础上我们将完成分布式Session共享功能。

Redis的使用

Maven Plugin添加Redis相关jar包

   <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

添加Redis配置文件

 package com.goku.webapi.config.redis;

 import com.fasterxml.jackson.databind.DeserializationFeature;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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 com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.redis.serializer.StringRedisSerializer; /**
* Created by nbfujx on 2017/10/19.
*/
@Configuration
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport { @Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.timeout}")
private int timeout; @Bean
public CacheManager cacheManager(RedisTemplate<Object, Object> redisTemplate) {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
cacheManager.setDefaultExpiration(1800);
return cacheManager;
} @Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new RedisObjectSerializer());
return template;
}
}

添加RedisSessionDAO配置文件

 package com.goku.webapi.config.Shiro;

 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.data.redis.core.RedisTemplate; import javax.annotation.Resource;
import java.io.Serializable;
import java.util.concurrent.TimeUnit; /**
* Created by nbfujx on 2017-11-08.
*/
public class RedisSessionDAO extends EnterpriseCacheSessionDAO { // session 在redis过期时间是30分钟30*60
private static final int EXPIRE_TIME = 1800;
private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class);
private static String prefix = "shiro-session:"; @Resource
private RedisTemplate<String, Object> redisTemplate; // 创建session,保存到数据库
@Override
protected Serializable doCreate(Session session) {
Serializable sessionId = super.doCreate(session);
this.logger.info("创建session:{}", session.getId());
redisTemplate.opsForValue().set(prefix + sessionId.toString(), session);
return sessionId;
} // 获取session
@Override
protected Session doReadSession(Serializable sessionId) {
this.logger.info("获取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);
this.logger.info("获取session:{}", session.getId());
String key = prefix + session.getId().toString();
if (!redisTemplate.hasKey(key)) {
redisTemplate.opsForValue().set(key, session);
}
redisTemplate.expire(key, EXPIRE_TIME, TimeUnit.SECONDS);
} // 删除session
@Override
protected void doDelete(Session session) {
this.logger.info("删除session:{}", session.getId());
super.doDelete(session);
redisTemplate.delete(prefix + session.getId().toString());
}
}

添加ShiroCache配置文件

 package com.goku.webapi.config.Shiro;

 import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.data.redis.core.RedisTemplate; import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit; /**
* Created by nbfujx on 2017/11/8.
*/
public class ShiroCache<K, V> implements Cache<K, V> { private static final String REDIS_SHIRO_CACHE = "shiro-cache:";
private static final long GLOB_EXPIRE = 30;
private String cacheKey;
private RedisTemplate<K, V> redisTemplate; public ShiroCache(RedisTemplate<K, V> client, String name) {
this.cacheKey = REDIS_SHIRO_CACHE + name + ":";
this.redisTemplate = client;
} @Override
public V get(K key) throws CacheException {
redisTemplate.boundValueOps(getCacheKey(key)).expire(GLOB_EXPIRE, 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<K> keys() {
return redisTemplate.keys(getCacheKey("*"));
} @Override
public Collection<V> values() {
Set<K> set = keys();
List<V> list = new ArrayList<>();
for (K s : set) {
list.add(get(s));
}
return list;
} private K getCacheKey(Object k) {
return (K) (this.cacheKey + k);
}
}

添加RedisCacheManager配置文件

 package com.goku.webapi.config.Shiro;

 import javax.annotation.Resource;

 import com.goku.webapi.config.Shiro.ShiroCache;
import org.apache.shiro.cache.AbstractCacheManager;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.data.redis.core.RedisTemplate;
/**
* Created by nbfujx on 2017-11-08.
*/
public class RedisCacheManager extends AbstractCacheManager { @Resource
private RedisTemplate<String, Object> redisTemplate; @Override
protected Cache<String, Object> createCache(String name) throws CacheException {
return new ShiroCache<>(redisTemplate, name);
}
}

调整ShiroConfi配置文件

 package com.goku.webapi.config.Shiro;

 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.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn; import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map; /**
* shiro配置类
* Created by nbfujx on 2017/11/7.
*/
@Configuration
public class ShiroConfig { /**
* LifecycleBeanPostProcessor,这是个DestructionAwareBeanPostProcessor的子类,
* 负责org.apache.shiro.util.Initializable类型bean的生命周期的,初始化和销毁。
* 主要是AuthorizingRealm类的子类,以及EhCacheManager类。
*/
@Bean(name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
} /**
* ShiroRealm,这是个自定义的认证类,继承自AuthorizingRealm,
* 负责用户的认证和权限的处理,可以参考JdbcRealm的实现。
*/
@Bean(name = "shiroRealm")
@DependsOn("lifecycleBeanPostProcessor")
public ShiroRealm shiroRealm() {
ShiroRealm realm = new ShiroRealm();
realm.setCacheManager(redisCacheManager());
return realm;
} @Bean
public RedisCacheManager redisCacheManager() {
return new RedisCacheManager();
} @Bean(name = "redisSessionDAO")
public RedisSessionDAO sessionDAO() {
RedisSessionDAO sessionDAO = new RedisSessionDAO();
return sessionDAO;
} /**
* SessionManager session管理
*/
@Bean
public SessionManager sessionManager() {
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionDAO(sessionDAO());
sessionManager.setGlobalSessionTimeout(1800);
sessionManager.setCacheManager(redisCacheManager());
return sessionManager;
} /**
* SecurityManager,权限管理,这个类组合了登陆,登出,权限,session的处理,是个比较重要的类。
*/
@Bean(name = "securityManager")
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(shiroRealm());
securityManager.setCacheManager(redisCacheManager());
securityManager.setSessionManager(sessionManager());
return securityManager;
} /**
* ShiroFilterFactoryBean,是个factorybean,为了生成ShiroFilter。
* 它主要保持了三项数据,securityManager,filters,filterChainDefinitionManager。
*/
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean() {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager()); Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
shiroFilterFactoryBean.setFilters(filters); Map<String, String> filterChainDefinitionManager = new LinkedHashMap<String, String>();
filterChainDefinitionManager.put("/login", "anon");
filterChainDefinitionManager.put("/logout", "anon");
filterChainDefinitionManager.put("/sysUser/*", "authc,perms");//"authc,perms[sysUser:*]");
filterChainDefinitionManager.put("/sysMenu/*", "authc,perms");//"authc,perms[sysUser:*]");
filterChainDefinitionManager.put("/*", "anon");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionManager); shiroFilterFactoryBean.setLoginUrl("/notAuthc");
shiroFilterFactoryBean.setSuccessUrl("/");
shiroFilterFactoryBean.setUnauthorizedUrl("/notAuthz");
return shiroFilterFactoryBean;
} /**
* DefaultAdvisorAutoProxyCreator,Spring的一个bean,由Advisor决定对哪些类的方法进行AOP代理。
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
defaultAAP.setProxyTargetClass(true);
return defaultAAP;
} /**
* AuthorizationAttributeSourceAdvisor,shiro里实现的Advisor类,
* 内部使用AopAllianceAnnotationsAuthorizingMethodInterceptor来拦截用以下注解的方法。
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor aASA = new AuthorizationAttributeSourceAdvisor();
aASA.setSecurityManager(securityManager());
return aASA;
} }

新增RedisCacheManager,RedisSessionDAO,sessionManager相关bean,

securityManager 增加 securityManager.setSessionManager(sessionManager());

Shiro-Redis的使用验证

先进行登录验证操作

查看redis存储数据

进行数据查询

查看日志是否从redis获取

GITHUB

github : https://github.com/nbfujx/learn-java-demo/tree/master/Goku.WebService.Simple.Redis.Shiro

SpringBoot搭建基于Apache Shiro+Redis的分布式Session共享功能的更多相关文章

  1. SpringBoot搭建基于Apache Shiro的权限管理功能

    Shiro 是什么 Apache Shiro是一个强大易用的Java安全框架,提供了认证.授权.加密和会话管理等功能: 认证 - 用户身份识别,常被称为用户“登录”: 授权 - 访问控制: 密码加密 ...

  2. Spring Session + Redis实现分布式Session共享

    发表于 2016-09-29 文章目录 1. Maven依赖 2. 配置Filter 3. Spring配置文件 4. 解决Redis云服务Unable to configure Redis to k ...

  3. 基于Spring Boot/Spring Session/Redis的分布式Session共享解决方案

    分布式Web网站一般都会碰到集群session共享问题,之前也做过一些Spring3的项目,当时解决这个问题做过两种方案,一是利用nginx,session交给nginx控制,但是这个需要额外工作较多 ...

  4. springboot+redis实现分布式session共享

    官方文档,它是spring session项目的redis相关的一个子文档:https://docs.spring.io/spring-session/docs/2.0.0.BUILD-SNAPSHO ...

  5. 使用SpringSession和Redis解决分布式Session共享问题

    SpringSession优势 遵循servlet规范,同样方式获取session,对应用代码无侵入且对于developers透明化 关键点在于做到透明和兼容 接口适配:仍然使用HttpServlet ...

  6. Spring boot整合redis实现shiro的分布式session共享

    我们知道,shiro是通过SessionManager来管理Session的,而对于Session的操作则是通过SessionDao来实现的,默认的情况下,shiro实现了两种SessionDao,分 ...

  7. SpringBoot 搭建基于 MinIO 的高性能存储服务

    1.什么是MinIO MinIO是根据GNU Affero通用公共许可证v3.0发布的高性能对象存储.它与Amazon S3云存储服务兼容.使用MinIO构建用于机器学习,分析和应用程序数据工作负载的 ...

  8. Tornado 自定义session,与一致性哈希 ,基于redis 构建分布式 session框架

    Tornado 自定义session,与一致性哈希 ,基于redis 构建分布式 session import tornado.ioloop import tornado.web from myhas ...

  9. Linux搭建基于Apache的HTTP服务器

    Linux搭建基于Apache的HTTP服务器   实验目标: 通过本实验掌握基于Linux的WWW服务器搭建. 实验步骤: 1.安装http服务 2.防火墙放通http服务 3.编辑测试网页 4.开 ...

随机推荐

  1. SpringMvc返回JSON的工作原理。

    一:导入jar包.然后在springmvc.xml中配置上这么一句话 <!-- 能支持springmvc更高级的一些功能,JSR303校验,快捷的ajax,处理JSON数据.映射动态请求 --& ...

  2. 09-排序2 Insert or Merge(25 分)

    According to Wikipedia: Insertion sort iterates, consuming one input element each repetition, and gr ...

  3. Visual Studio 2008 附加进程调试

    关于附加进程调试的问题: 在项目当中经常使用“附加到进程”来调试项目,感觉挺方便的.我们做的项目通常都会发布到IIS(特别是B/S),一可以直接通过地址栏输入地址就可以运行项目,不必去使用开发工具来打 ...

  4. JS-iframe高度自适应内容

    iframe:https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/iframe iframe 内容加载后不改变 使用:onload=&q ...

  5. left、pixelLeft、posLeft的区别

    yexj00.style.pixelLeft=50yexj00.style.left=50pxyexj00.style.posLeft=50he.style.pixelLeft=39he.style. ...

  6. Mac版-Jdk安装与环境配置

    下载安装 oracle官网下载,地址:https://www.oracle.com/technetwork/java/javase/downloads/index.html 下载好后,点击安装包,一直 ...

  7. jQuery的toggle事件

    $(function () {    //默认隐藏   $("#SelTime").hide();  $("#SeniorSel").toggle(      ...

  8. .NET/VB.NET: solving the error “The system cannot find the file specified.” “\Temp\.NETFramework,Version=v4.0.AssemblyAttributes.vb”

    Source Link Bumped into this error a while ago in Visual Studio 2010: Kind Error Number 80 Descripti ...

  9. cross-env

    cross-env跨平台设置环境变量 安装npm install --save-dev cross-env config文件下新建环境对应文件 新建编译命令 修改build/webpack.prod. ...

  10. LoadRunner内部结构(转)

    LoadRunner内部结构 1,            被测系统是由驱动进程mdrv.exe(多线程驱动的进程)和r3vuser.exe来产生压力的,其中r3vuser.exe仿真应用程序的客户端, ...