oauth2 redis mysql_使用 JWT、Redis、MySQL 存储 OAuth2.0 数据~

论坛 期权论坛 脚本     
已经匿名di用户   2022-4-13 16:43   3124   0

摘要: 原创出处 http://www.iocoder.cn/Spring-Security/OAuth2-learning-store/ 「芋道源码」欢迎转载,保留摘要,谢谢!1. 概述

2. 数据库存储器

3. Redis 存储器

4. JWT 存储器

666. 彩蛋“

本文在提供完整代码示例,可见 https://github.com/YunaiV/SpringBoot-Labs 的 lab-68-spring-security-oauth 目录。

原创不易,给点个 Star 嘿,一起冲鸭!

1. 概述

在《芋道 Spring Security OAuth2 入门》文章中,我们完成了 Spring Security OAuth 框架的学习。但是我们在文末中也提到,采用基于内存的 InMemoryTokenStore,实现访问令牌和刷新令牌的存储。它会存在两个明显的缺点:重启授权服务器时,令牌信息会丢失,导致用户需要重新授权。

多个授权服务器时,令牌信息无法共享,导致用户一会授权成功,一会授权失败。

因此,本文我们来学习 Spring Security OAuth 提供的其它存储器。TokenStore 是 Spring Security OAuth 定义的令牌存储器接口,它有如下实现类:

828e0435942d26d90a3266e8371bf759.pngTokenStore 类图基于数据库的 JdbcTokenStore

基于 Redis 的 RedisTokenStore

基于 JWT 的 JwtTokenStore

下面,我们逐个小节来演示每个 TokenStore 的配置与使用。

2. 数据库存储器“

示例代码对应仓库:授权服务器:lab-68-demo11-authorization-server-by-jdbc-store

本小节,我们使用基于数据库存储的 JdbcTokenStore。

复制出 lab-68-demo11-authorization-server-by-jdbc-store 项目,进行改造接入 JdbcTokenStore 存储器。最终项目如下图所示:

项目结构

2.1 初始化数据库

① 执行 schema.sql 脚本,创建数据库表结构。drop table if exists oauth_client_details;

create table oauth_client_details (

client_id VARCHAR(255) PRIMARY KEY,

resource_ids VARCHAR(255),

client_secret VARCHAR(255),

scope VARCHAR(255),

authorized_grant_types VARCHAR(255),

web_server_redirect_uri VARCHAR(255),

authorities VARCHAR(255),

access_token_validity INTEGER,

refresh_token_validity INTEGER,

additional_information VARCHAR(4096),

autoapprove VARCHAR(255)

);

create table if not exists oauth_client_token (

token_id VARCHAR(255),

token LONG VARBINARY,

authentication_id VARCHAR(255) PRIMARY KEY,

user_name VARCHAR(255),

client_id VARCHAR(255)

);

create table if not exists oauth_access_token (

token_id VARCHAR(255),

token LONG VARBINARY,

authentication_id VARCHAR(255) PRIMARY KEY,

user_name VARCHAR(255),

client_id VARCHAR(255),

authentication LONG VARBINARY,

refresh_token VARCHAR(255)

);

create table if not exists oauth_refresh_token (

token_id VARCHAR(255),

token LONG VARBINARY,

authentication LONG VARBINARY

);

create table if not exists oauth_code (

code VARCHAR(255), authentication LONG VARBINARY

);

create table if not exists oauth_approvals (

userId VARCHAR(255),

clientId VARCHAR(255),

scope VARCHAR(255),

status VARCHAR(10),

expiresAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

lastModifiedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP

);

结果如下图所示:

表结构表作用oauth_access_tokenOAuth 2.0 访问令牌

oauth_refresh_tokenOAuth 2.0 刷新令牌

oauth_codeOAuth 2.0 授权码

oauth_client_detailsOAuth 2.0 客户端

oauth_client_token

oauth_approvals“

旁白君:这里的表结构设计,我们可以借鉴参考,实现自己的 OAuth 2.0 的功能。

② 执行 data.sql 脚本,插入一个客户端记录。INSERT INTO oauth_client_details

(client_id, client_secret, scope, authorized_grant_types,

web_server_redirect_uri, authorities, access_token_validity,

refresh_token_validity, additional_information, autoapprove)

VALUES

('clientapp', '112233', 'read_userinfo,read_contacts',

'password,refresh_token', null, null, 3600, 864000, null, true);

结果如下图所示:

oauth_client_details 表记录

2.2 引入依赖

修改 pom.xml 文件,额外引入数据库连接池的依赖:

org.springframework.boot

spring-boot-starter-jdbc

mysql

mysql-connector-java

5.1.48

2.3 配置文件

创建 application.yaml 配置文件,添加数据库连接池的配置:spring:

# datasource 数据源配置内容,对应 DataSourceProperties 配置属性类

datasource:

url: jdbc:mysql://127.0.0.1:43063/demo-68-authorization-server?useSSL=false&useUnicode=true&characterEncoding=UTF-8

driver-class-name: com.mysql.jdbc.Driver

username: root # 数据库账号

password: 123456 # 数据库密码

2.4 OAuth2AuthorizationServerConfig

修改 OAuth2AuthorizationServerConfig 配置类,设置使用 JdbcTokenStore 和 ClientDetailsService。代码如下:@Configuration

@EnableAuthorizationServer

public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter{

/**

* 用户认证 Manager

*/

@Autowired

private AuthenticationManager authenticationManager;

/**

* 数据源 DataSource

*/

@Autowired

private DataSource dataSource;

@Bean

public TokenStore jdbcTokenStore(){

return new JdbcTokenStore(dataSource);

}

@Override

public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception{

endpoints.authenticationManager(authenticationManager)

.tokenStore(jdbcTokenStore());

}

@Override

public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception{

oauthServer.checkTokenAccess("isAuthenticated()");

}

@Bean

public ClientDetailsService jdbcClientDetailsService(){

return new JdbcClientDetailsService(dataSource);

}

@Override

public void configure(ClientDetailsServiceConfigurer clients) throws Exception{

clients.withClientDetails(jdbcClientDetailsService());

}

}

具体的修改点,如下图所示:

修改点

2.5 简单测试

执行 AuthorizationServerApplication 启动授权服务器。下面,我们使用Postman 模拟一个 Client。

① POST 请求 http://localhost:8080/oauth/token 地址,使用密码模式进行授权。如下图所示:

密码模式的认证

② 查询 oauth_access_token 和 oauth_refresh_token 表,查看访问令牌和刷新令牌。如下图所示:

oauth_access_tokenoauth_refresh_token

3. Redis 存储器“

示例代码对应仓库:授权服务器:lab-68-demo11-authorization-server-by-redis-store

本小节,我们使用基于 Redis 存储的 RedisTokenStore。

复制出 lab-68-demo11-authorization-server-by-redis-store 项目,进行改造接入 RedisTokenStore 存储器。最终项目如下图所示:

项目结构

3.1 引入依赖

修改 pom.xml 文件,额外引入 Spring Data Redis 的依赖:

org.springframework.boot

spring-boot-starter-data-redis

友情提示:想要学习 Spring Data Redis 的胖友,可以看看《芋道 Spring Boot Redis 入门》文章。

3.2 配置文件

创建 application.yaml 配置文件,添加 Spring Data Redis 的配置:spring:

# 对应 RedisProperties 类

redis:

host: 127.0.0.1

port: 6379

3.3 OAuth2AuthorizationServerConfig

修改 OAuth2AuthorizationServerConfig 配置类,设置使用 RedisTokenStore。代码如下:@Configuration

@EnableAuthorizationServer

public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter{

/**

* 用户认证 Manager

*/

@Autowired

private AuthenticationManager authenticationManager;

/**

* Redis 连接的工厂

*/

@Autowired

private RedisConnectionFactory redisConnectionFactory;

@Bean

public TokenStore redisTokenStore(){

return new RedisTokenStore(redisConnectionFactory);

}

@Override

public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception{

endpoints.authenticationManager(authenticationManager)

.tokenStore(redisTokenStore());

}

@Override

public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception{

oauthServer.checkTokenAccess("isAuthenticated()");

}

@Override

public void configure(ClientDetailsServiceConfigurer clients) throws Exception{

clients.inMemory()

.withClient("clientapp").secret("112233") // Client 账号、密码。

.authorizedGrantTypes("password", "refresh_token") // 密码模式

.scopes("read_userinfo", "read_contacts") // 可授权的 Scope

// .and().withClient() // 可以继续配置新的 Client

;

}

}

具体的修改点,如下图所示:

932b27214cb838f159bd5e387a427ed9.png修改点

3.4 简单测试

执行 AuthorizationServerApplication 启动授权服务器。下面,我们使用Postman 模拟一个 Client。

① POST 请求 http://localhost:8080/oauth/token 地址,使用密码模式进行授权。如下图所示:

密码模式的认证

② 查看 Redis 中的 访问令牌和刷新令牌。如下图所示:

RDM 查看 Redis

4. JWT 存储器“

示例代码对应仓库:授权服务器:lab-68-demo11-authorization-server-by-jwt-store

本小节,我们使用基于 JWT 存储的 JwtTokenStore。“

友情提示:如果胖友对 JWT 不了解的胖友,可以先看看如下两篇文章:《JSON Web Token - 在Web应用间安全地传递信息》

《八幅漫画理解使用 JSON Web Token 设计单点登录系统》

复制出 lab-68-demo11-authorization-server-by-jwt-store 项目,进行改造接入 JwtTokenStore 存储器。最终项目如下图所示:

项目结构

4.1 OAuth2AuthorizationServerConfig

修改 OAuth2AuthorizationServerConfig 配置类,设置使用 JwtTokenStore。代码如下:@Configuration

@EnableAuthorizationServer

public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter{

/**

* 用户认证 Manager

*/

@Autowired

private AuthenticationManager authenticationManager;

@Bean

public JwtAccessTokenConverter jwtAccessTokenConverter(){

JwtAccessTokenConverter converter = new JwtAccessTokenConverter();

converter.setSigningKey("nainai_zui_shuai"); // JWT 秘钥

return converter;

}

@Bean

public JwtTokenStore jwtTokenStore(){

return new JwtTokenStore(jwtAccessTokenConverter());

}

@Override

public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception{

endpoints.authenticationManager(authenticationManager)

.tokenStore(jwtTokenStore())

.accessTokenConverter(jwtAccessTokenConverter());

}

@Override

public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception{

oauthServer.checkTokenAccess("isAuthenticated()");

// oauthServer.tokenKeyAccess("isAuthenticated()")

// .checkTokenAccess("isAuthenticated()");

// oauthServer.tokenKeyAccess("permitAll()")

// .checkTokenAccess("permitAll()");

}

@Override

public void configure(ClientDetailsServiceConfigurer clients) throws Exception{

clients.inMemory()

.withClient("clientapp").secret("112233") // Client 账号、密码。

.authorizedGrantTypes("password", "refresh_token") // 密码模式

.scopes("read_userinfo", "read_contacts") // 可授权的 Scope

// .and().withClient() // 可以继续配置新的 Client

;

}

}

具体的修改点,如下图所示:

639bc12b6ba1b24d03331cb7c47891ca.png修改点

4.2 简单测试

执行 AuthorizationServerApplication 启动授权服务器。下面,我们使用Postman 模拟一个 Client。

① POST 请求 http://localhost:8080/oauth/token 地址,使用密码模式进行授权。如下图所示:

3666db324080eeb52b24ef4f60880733.png密码模式的认证

② 使用 https://jwt.io/ 提供的工具,解析 JWT 令牌。如下图所示:

cd5702160c754f80ad1f80b6ba9957a8.pngJWT 解析

666. 彩蛋

比较简单的一篇文章,下一篇《芋道 Spring Security OAuth2 单点登录》走起!

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:81
帖子:4969
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP