OAuth + Security - 5 - Token存储升级(数据库、Redis)
PS:此文章为系列文章,建议从第一篇开始阅读。
在我们之前的文章中,我们当时获取到Token令牌时,此时的令牌时存储在内存中的,这样显然不利于我们程序的扩展,所以为了解决这个问题,官方给我们还提供了其它的方式来存储令牌,存储到数据库或者Redis中,下面我们就来看一看怎么实现。
不使用Jwt令牌的实现
- 存储到数据库中(JdbcTokenStore)
使用数据库存储方式之前,我们需要先准备好对应的表。Spring Security OAuth仓库可以找到相应的脚本:https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql。该脚本为HSQL,所以需要根据具体使用的数据库进行相应的修改,以MySQL为例,并且当前项目中,只需要使用到oauth_access_token和oauth_refresh_token数据表,所以将创建这两个库表的语句改为MySQL语句:
CREATE TABLE oauth_access_token (
token_id VARCHAR ( 256 ),
token BLOB,
authentication_id VARCHAR ( 256 ),
user_name VARCHAR ( 256 ),
client_id VARCHAR ( 256 ),
authentication BLOB,
refresh_token VARCHAR ( 256 )
);
CREATE TABLE oauth_refresh_token (
token_id VARCHAR ( 256 ),
token BLOB, authentication BLOB
);
然后我们需要去配置对应的认证服务器,主要就是修改之前文章中TokenConfigure类中的tokenStore()方法:
// 同时需要注入数据源
@Autowired
private DataSource dataSource;
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
同时需要添加jdbc的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
认证服务器中的配置保持本系列第一章的配置不变,此处不再赘述。
其中若有不理解的地方,请参考该系列的第一篇文章
关于数据源的补充:
在我们项目中配置的数据源,可能不一定是使用的官方提供的格式,比如我们自定义的格式,或者使用第三方的数据源,那么我们如何去配置呢?这里以mybatis-plus的多数据源为例:
@Configuration
@EnableAuthorizationServer
public class FebsAuthorizationServerConfigure extends AuthorizationServerConfigurerAdapter {
......
@Autowired
private DynamicRoutingDataSource dynamicRoutingDataSource;
@Bean
public TokenStore tokenStore() {
DataSource dimplesCloudBase = dynamicRoutingDataSource.getDataSource("dimples_cloud_base");
return new JdbcTokenStore(febsCloudBase);
}
......
}
然后启动项目,重新获取Token进行测试,能正确的获取到Token:
我们查看数据中,看是否已经存入相关信息到数据库中:
- 存储到redis(RedisTokenStore)
令牌存储到redis中相比于存储到数据库中来说,存储redis中,首先在性能上有一定的提升,其次,令牌都有有效时间,超过这个时间,令牌将不可再用,而redis的可以给对应的key设置过期时间,完美切合需求,所有令牌存储到redis中也是一种值得使用的方法。
首先,我们需要在项目中添加redis依赖,同时配置redis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
新建配置类RedisConfigure
@Configuration
public class RedisConfigure{
@Bean
@ConditionalOnClass(RedisOperations.class)
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(mapper);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用 String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的 key也采用 String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用 jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的 value序列化方式采用 jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
配置redis的连接
spring:
redis:
database: 0
host: 127.0.0.1
port: 6379
lettuce:
pool:
min-idle: 8
max-idle: 500
max-active: 2000
max-wait: 10000
timeout: 5000
这时我们启动项目测试,会发现项目将会报错:
Caused by: java.lang.ClassNotFoundException: org.apache.commons.pool2.impl.GenericObjectPoolConfig
这是由于我们配置RedisConfigure时,使用到了一个ObjectMapper类,这个类需要我们引入Apache的一个工具包
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
最后,我们需要在认证服务器中配置token的存储方式,还是同jdbc的配置,在tokenStore()方法中配置,打开我们的TokenConfigure类,然后做如下配置:
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Bean
public TokenStore tokenStore() {
return new RedisTokenStore(redisConnectionFactory);
}
认证服务器中的配置还是跟之前的一样,保持不变,启动项目,获取Token测试:
我们查看Redis中,看是否已经存入相关信息到数据库中:
- 其它
我们打开TokenStore接口的实现类,会发现,还有一种JwkTokenStore,这种实际上就是将我们UUID格式令牌变成可以带特殊含义的jwt格式的令牌,我们已经在第三篇文章中介绍过了,可以参考前面的文章。
但是我们需要明白一点的是,这种令牌还是存储在内存中的,后期我们如何将其存储到redis中是我们研究的方向。
在上面的token存储到数据库和存储到redis中,我们会发现一个问题,那就是我们多次获取令牌,但是其值是固定不变的,为了解决这个问题,我们可以使用如下方式解决:
@Bean
public TokenStore tokenStore() {
RedisTokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory);
// 解决每次生成的 token都一样的问题
redisTokenStore.setAuthenticationKeyGenerator(oAuth2Authentication -> UUID.randomUUID().toString());
return redisTokenStore;
}
使用JWT令牌的实现
在之前的所有使用方法中,我们要么是将Token存储在数据库或者redis中的时候,令牌的格式是UUID的无意义字符串,或者是使用JWT的有意义字符串,但是确是将令牌存储在内存中,那么,我们现在想使用JWT令牌的同时,也想将令牌存储到数据库或者Redis中。我们该怎么配置呢?下面我们以Redis存储为例,进行探索:
首先,我们还是要使用到TokenConfigure中的JWT和Redis配置:
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
//对称秘钥,资源服务器使用该秘钥来验证
converter.setSigningKey(SIGNING_KEY);
return converter;
}
@Bean
public TokenStore tokenStore() {
RedisTokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory);
// 解决每次生成的 token都一样的问题
redisTokenStore.setAuthenticationKeyGenerator(oAuth2Authentication -> UUID.randomUUID().toString());
return redisTokenStore;
}
接下来,是配置认证服务器,在认证服务器中,跟之前的配置有一点区别,如下:
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
@Autowired
private TokenStore tokenStore;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
// 配置密码模式管理器
.authenticationManager(authenticationManager)
// 配置授权码模式管理器
.authorizationCodeServices(authorizationCodeServices())
// 令牌管理
// .tokenServices(tokenServices());
.accessTokenConverter(jwtAccessTokenConverter)
.tokenStore(tokenStore);
}
启动项目,进行测试,获取token
然后使用该令牌请求资源
至此,我们差不多完成了Token令牌的存储和获取
源码传送门: https://gitee.com/dimples820/dimples-explore
OAuth + Security - 5 - Token存储升级(数据库、Redis)的更多相关文章
- 使用Redis作为Spring Security OAuth2的token存储
写在前边 本文对Spring Security OAuth2的token使用Redis保存,相比JWT实现的token存储,Redis可以随时吊销access_token,并且Redis响应速度很快, ...
- 使用JWT作为Spring Security OAuth2的token存储
序 Spring Security OAuth2的demo在前几篇文章中已经讲过了,在那些模式中使用的都是RemoteTokenService调用授权服务器来校验token,返回校验通过的用户信息供上 ...
- ASP.NET OWIN OAuth:refresh token的持久化
在前一篇博文中,我们初步地了解了refresh token的用途——它是用于刷新access token的一种token,并且用简单的示例代码体验了一下获取refresh token并且用它刷新acc ...
- linux --- 8. mysql数据库,redis 数据库
一. mysql 数据库 1.安装方式 ①yum安装 ②源代码编译安装 ③rpm包安装 yum安装的前提条件,是准备好yum源,可以选择163源,清华源,阿里云源,等等等 .安装mariadb的yum ...
- Android学习笔记(十八)——再谈升级数据库
//此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 之前我们为了保证数据库中的表是最新的,只是简单地在 onUpgrade()方法中删除掉了当前所有的表,然后强制 ...
- Web安全--使用Salt + Hash将密码加密后再存储进数据库
转载原地址 http://www.bozhiyue.com/mianshiti/_net/2016/0728/314239.html (一) 为什么要用哈希函数来加密密码 如果你需要保存密码(比如网站 ...
- DevOps之存储和数据库
唠叨话 关于德语噢屁事的知识点,仅提供专业性的精华汇总,具体知识点细节,参考教程网址,如需帮助,请留言. <数据(Data)> 了解有关数据部分.涉及存储及数据库的概念:知识与技能的层次( ...
- 缓存数据库-redis数据类型和操作(list)
转: 狼来的日子里! 奋发博取 缓存数据库-redis数据类型和操作(list) 一:Redis 列表(List) Redis列表是简单的字符串列表,按照插入顺序排序.你可以添加一个元素导列表的头部( ...
- Spring Security教程(二):通过数据库获得用户权限信息
上一篇博客中,Spring Security教程(一):初识Spring Security,我把用户信息和权限信息放到了xml文件中,这是为了演示如何使用最小的配置就可以使用Spring Securi ...
随机推荐
- 【题解】[SCOI2015]小凸玩矩阵
题目链接 思路:题目要求变相解答一下,求出是否有n-k个数,不大于当前求的第k个数 而每一行每一列只能有一个数,就可以得到一个二分图的思路,边上的权值就是第i行第j列这个数的值 对于答案就是第k大的数 ...
- app测试、web测试-怎么测?
app测试 前言 看过许多大神对APP测试的理解,博主总结了一下我们平时测试APP应该注意的一些测试点并结合大神的理解,总结出这篇文章. 一.测试周期 测试周期一般为两周,根据项目情况以及版本质量可适 ...
- spark机器学习从0到1特征抽取–Word2Vec(十四)
一.概念 Word2vec是一个Estimator,它采用一系列代表文档的词语来训练word2vecmodel.该模型将每个词语映射到一个固定大小的向量.word2vecmodel使用文档中每个词 ...
- AI技术原理|机器学习算法
摘要 机器学习算法分类:监督学习.半监督学习.无监督学习.强化学习 基本的机器学习算法:线性回归.支持向量机(SVM).最近邻居(KNN).逻辑回归.决策树.k平均.随机森林.朴素贝叶斯.降维.梯度增 ...
- babel转码时generator的regeneratorRuntime
今天写generator函数时发现出错:regeneratorRuntime. 在stackoverflow网友说需是本地babel软件包没有安装完全. package.json: "dev ...
- 愉快地使用Open Live Writer写博客
想要坚持写博客的习惯,却又无法忍受网页编辑器的各种不方便?open live writer是一个不错的选择.对我来说最有诱惑的就是能够快速的黏贴图片.代码.使用过程遇到不少坑,最坑的就是不能使用163 ...
- Spring 基于 Java 的配置
前面已经学习如何使用 XML 配置文件来配置 Spring bean. 基于 Java 的配置可以达到基于XML配置的相同效果. 基于 Java 的配置选项,可以使你在不用配置 XML 的情况下编写大 ...
- vue2.0 axios前后端数据处理
目前主流的 Vue 项目,都选择 axios 来完成 ajax 请求,而大型项目都会使用 Vuex 来管理数据. 前言: 使用 cnpm 安装 axios cnpm install axios -S ...
- pytest 使用
import pytestfrom web_ui_YXBI.test_datas.common_datas import Common_Datas as cfrom selenium import w ...
- 【Leetcode】287. 寻找重复数(数组模拟链表的快慢指针法)
寻找重复数 根据题意,数组中的数字都在1~n之间,所以数字的范围是小于数组的范围的,数组的元素可以和数组的索引相联系. 例如:nums[0] = 1 即可以将nums[0]作为索引 通过nums[0] ...