我们在上一遍文档中已经完成了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. Hadoop编程调用HDFS(PYTHON)

    1.运行环境 开发工具:PyCharm Python 版本:3.5 Hadoop环境: Cloudera QuickStart 2.GITHUB地址 https://github.com/nbfujx ...

  2. 迅捷路由器FW325R的无线桥接

    1.恢复路由器默认设置 长按路由器后面的按钮直到指示灯全亮后只剩一个灯亮时松开按钮,此时就已经重置路由器了.然后设置路由器后台密码什么的,那些向导什么的可以跳过 2.高级设置内容 进入路由器高级设置: ...

  3. Android工作两年之后的第一个App--天真无谐

    一.前言 好长时间没写blog了,主要还是工作上的事有点多,周末又得在家开发自己的app,所以时间真的不够用了,当然今天这篇文章主要就要说一下,工作两年的我如何从产品角度去做一个app,以及app的发 ...

  4. LUOGU P4088 [USACO18FEB]Slingshot(线段树)

    传送门 解题思路 推了推式子发现是个二维数点,想了想似乎排序加线段树难写,就写了个树套树,结果写完看见空间才\(128M\)..各种奇技淫巧卡空间还是\(MLE\)到天上.后来只好乖乖的写排序+线段树 ...

  5. Linux 通配符和特殊符号

  6. webstorm启动vue项目配置

    使用命令窗口运行 1. npm run mock 2.npm run dev 每次都打开命令窗口比较麻烦,可以在webstorm内进行配置,从webstorm内启动 选中run下面的edit conf ...

  7. think PHP提取字符串中的数字,并到数据库中使用in查询所关联表的字段值

    /* * 提取数字并去数据库取得相应的分类名 * $strs 需要处理的字符串 * $table 数据表名 * $condition 条件字段 * $field 获取的字段 */ public fun ...

  8. 伪造请求头向url传递参数爬取百度默认翻译

    from urllib import request,parse import json # 翻译函数 def fanyi(msg): #参数封装 data = { "kw": c ...

  9. P3375 【模板】KMP字符串匹配——kmp算法

    先上一波题目 https://www.luogu.org/problem/P3375 kmp模板 看了好久才想起来是个什么东西qwq #include<cstdio> #include&l ...

  10. Apache Shiro 会话+缓存+记住我(三)

    1.会话管理SessionDao和SessionManager 1)安装Redis 2)依赖 <dependency> <groupId>redis.clients</g ...