前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用 JWT、Redis、MySQL 存储 OAuth2.0 数据~

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

作者头像
芋道源码
发布2020-07-09 15:44:41
2.5K0
发布2020-07-09 15:44:41
举报

周末。正在肝一篇 Netty 相关的内容,下周发,绝对干货!biubiubiu!

  • 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 定义的令牌存储器接口,它有如下实现类:

TokenStore 类图

  • 基于数据库的 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 2.0 访问令牌

“旁白君:这里的表结构设计,我们可以借鉴参考,实现自己的 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 文件,额外引入数据库连接池的依赖:

<!-- 实现对数据库连接池的自动化配置 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency> <!-- 本示例,我们使用 MySQL -->
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.48</version>
</dependency>

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_tokenoauth_refresh_token 表,查看访问令牌和刷新令牌。如下图所示:

oauth_access_token

oauth_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 的依赖:

<!-- 实现对 Spring Data Redis 的自动化配置 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

“友情提示:想要学习 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
                ;
    }

}

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

修改点

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
                ;
    }

}

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

修改点

4.2 简单测试

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

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

密码模式的认证

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

JWT 解析

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-07-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 芋道源码 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 概述
  • 2. 数据库存储器
    • 2.1 初始化数据库
      • 2.2 引入依赖
        • 2.3 配置文件
          • 2.4 OAuth2AuthorizationServerConfig
            • 2.5 简单测试
            • 3. Redis 存储器
              • 3.1 引入依赖
                • 3.2 配置文件
                  • 3.3 OAuth2AuthorizationServerConfig
                    • 3.4 简单测试
                    • 4. JWT 存储器
                      • 4.1 OAuth2AuthorizationServerConfig
                        • 4.2 简单测试
                        相关产品与服务
                        云数据库 Redis
                        腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档