我们在上一遍文档中已经完成了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. 使用C#获取IP地址方法

    C#中如何获取IP地址?,看到问题的时候我也很纠结,纠结的不是这个问题是如何的难回答,而是纠结的是这些问题都是比较基本的常识,也是大家会经常用到的.但是却不断的有人问起,追根究底的原因估计就是没有好好 ...

  2. hdu 2732 Leapin' Lizards (最大流 拆点建图)

    Problem Description Your platoon of wandering lizards has entered a strange room in the labyrinth yo ...

  3. 31 July

    P1005 矩阵取数游戏 高精度不能更坑-- #include <cstdio> #include <cstring> struct INT { long long h, l; ...

  4. 5 November in 614

    Contest A. ssoj2964 交错的士兵 \(n\) 个数的排列,从左到右依次为 1, 2, -, \(n\).\(n\) 次操作,对于第 \(i\) 次操作,从左到右分成很多段,每段 \( ...

  5. @encode关键字

    @encode() 为了更好的互操作性,Objective-C 的数据类型,甚至自定义类型.函数或方法的元类型,都可以使用 ASCII 编码.@encode(aType) 可以返回该类型的 C 字符串 ...

  6. (转)docker run的--rm选项详解

    转:https://blog.csdn.net/taiyangdao/article/details/73076770 在Docker容器退出时,默认容器内部的文件系统仍然被保留,以方便调试并保留用户 ...

  7. spring事务传播行为讲解转载

    https://segmentfault.com/a/1190000013341344 前言 Spring在TransactionDefinition接口中规定了7种类型的事务传播行为.事务传播行为是 ...

  8. composer 国内加速,修改镜像源

    为什么慢 由于默认情况下执行 composer 各种命令是去国外的 composer 官方镜像源获取需要安装的具体软件信息,所以在不使用代理.不翻墙的情况下,从国内访问国外服务器的速度相对比较慢 如何 ...

  9. Honk's pool(二分模板题)

    题意:有n个水池,每个水池有a[i]单位水,有k次操作,每次操作将水量最多的水池减少一单位水,水量最少的水池增加一单位水,问最后水量最大的水池和水量最少的水池相差的水量. 思路:二分最后的最大水量和最 ...

  10. upc组队赛14 Bus stop【签到水】

    Bus Stop 题目描述 In a rural village in Thailand, there is a long, straight, road with houses scattered ...