问题

令牌往哪里存?
客户端信息入库
第三方应用优化

1.令牌往哪里存?

我们配置授权模式时候,有两个东西当时存在内存中:

我们所使用的 InMemoryTokenStore 实现了 TokenStore 接口,我们来看下 TokenStore 接口实现类:
在这里插入图片描述

可以看到,我们有多种方式存储 access_token

  1. InMemoryTokenStore,这是我们之前使用的,也是系统默认的,就是access_token 存到内存中,单机应用这个没有问题,但是在分布式环境下不推荐
  2. JdbcTokenStore,看名字知道,这种方式令牌会被保存数据中,这样就可以方便的和其他应用共享令牌信息
  3. JwtTokenStore,这个其实不是存储,因为使用jwt 之后,在生成jwt 中就有用户的所有信息服务端需要保存,这也是无状态登录关于 OAuth2 结合 JWT 的用法,松哥本系列未来的文章中,也会详细介绍,这里就不再多说。
  4. RedisTokenStore,这个很明显就是access_token 存到 redis 中。
    JwkTokenStore,将 access_token 保存到 JSON Web Key。
    虽然这里支持方案比较多,但是我们常用的实际上主要是两个,RedisTokenStore 和 JwtTokenStore,JwtTokenStore 的比较复杂,我会在后面专门写文章来单独介绍,这里先来跟大家演示存入 RedisTokenStore。

首先我们启动一个 Redis 服务然后authserver 添加 Redis 依赖

        <!--redis依赖--&gt;
        <dependency&gt;
            <groupId&gt;org.springframework.boot</groupId&gt;
            <artifactId&gt;spring-boot-starter-data-redis</artifactId&gt;
        </dependency&gt;

依赖添加成功后,在 application.properties 中添加 redis 配置

spring.redis.host=
spring.redis.port=6379
spring.redis.password=

配置完成后,我们修改 TokenStore 的实例如下

package com.xql.authorization_server.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;

@Configuration
public class AccessTokenConfig {

    @Autowired
    RedisConnectionFactory redisConnectionFactory;

    @Bean
    TokenStore tokenStore() {
        return new RedisTokenStore(redisConnectionFactory);
    }
}

然后分别启动项目,走一遍第三方登录流程然后我们发现派发access_token 在 redis 中也有一份:
在这里插入图片描述

2.客户端信息入库

所以我们要将客户端信息存入数据库中。

客户端信息入库涉及到的接口主要是 ClientDetailsService,这个接口主要有两个实现类,如下
在这里插入图片描述
InMemoryClientDetailsService 就不多说了,这是存在内存中的。如果要存入数据库,很明显是 JdbcClientDetailsService,我们来大概看下 JdbcClientDetailsService源码,就能分析数据库结构了:

CREATE TABLE `oauth_client_details` (
  `client_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '客户端ID,唯一标识',
  `client_secret` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '客户访问秘钥,BCryptPasswordEncoder加密算法加密',
  `resource_ids` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '可访问资源id(英文逗号分隔)',
  `scope` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '授权范围(英文逗号分隔)',
  `authorized_grant_types` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '授权类型(英文逗号分隔)',
  `web_server_redirect_uri` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '重定向uri',
  `authorities` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '@PreAuthorize("hasAuthority(''admin'')")可以方法上标志 用户或者说client 需要说明样的权限rnnn指定客户端所拥有的Spring Security的权限rn(英文逗号分隔)',
  `access_token_validity` int NOT NULL COMMENT '令牌有效期(单位:秒)',
  `refresh_token_validity` int NOT NULL COMMENT '刷新令牌有效期(单位:秒)',
  `additional_information` varchar(4096) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '预留字段,在Oauth流程没有实际的使用(JSON格式数据)',
  `autoapprove` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '设置用户是否自动Approval操作, 默认值为 ''false''rn可选值包括 ''true'',''false'', ''read'',''write''.rn该字段只适用于grant_type="authorization_code"的情况,当用户登录成功后,若该值为''true''或支持scope值,则会跳过用户Approve的页面, 直接授权',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`client_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC;

接下来我们将一开始定义客户端的关键信息存入数据库中,如下

在这里插入图片描述

xql	$2a$10$SMP8P9hRmdTFzMfZBXksuuDNBm7AV9q1SFomvqc9FR38e/MMR7XiC	res1	all	authorization_code,password, client_credentials, implicit,refresh_token	http://localhost:8089/goods/index		7200	259200		false	2023-05-06 01:14:19	2023-05-06 06:14:30

既然用到数据库依赖当然也要提供相应的支持,我们给 authorization_server 添加如下依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

然后application.properties配置一下数据库连接信息

spring.datasource.river-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url= jdbc:mysql://xxxx:3307/oauth?useUnicode=true&amp;characterEncoding=utf8
spring.datasource.username= root
spring.datasource.password= xxxx

这里配置多了最后一条。这是因为我们一会创建自己的 ClientDetailsService,而系统已经创建了 ClientDetailsService,加了最后一条就允许我们自己实例覆盖系统默认实例

    @Resource
    private DataSource dataSource;

    @Bean
    public ClientDetailsService detailsService(){
        return new JdbcClientDetailsService(dataSource);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(detailsService());
        //内存配置的方式配置用户信息
        //内存方式
//        clients.inMemory()
//                //内存模拟client_id
//                .withClient("xql")
//                //客户端 秘钥 以及加密方式BCryptPasswordEncoder
//                .secret(new BCryptPasswordEncoder().encode("xql123"))
//                //客户端拥有的资源列表
//                .resourceIds("res1")
//                //该client允许的授权类型
//                .authorizedGrantTypes("authorization_code",
//                        "password", "client_credentials", "implicit",
//                        "refresh_token")
//                //允许的授权范围
//                .scopes("all")
//                //跳转到授权页面
//                .autoApprove(false)
//                //回调地址
//                .redirectUris("http://localhost:8089/goods/index");
//                .redirectUris("http://localhost:8089/goods/implicit.jsp");
//                .redirectUris("http://localhost:8089/goods/login");
        //继续注册其他客户端
        // .and()
        // .withClient()
        // 加载自定义的客户端管理服务
//         clients.withClientDetails(clientDetailsService);
    }

修改后的 AuthorizationServerTokenServices 实例如下

    @Autowired
    private ClientDetailsService clientDetailsService;
    /**
     * 这个 Bean 主要用来配置 Token 的一些基本信息,
     * 例如 Token 是否支持刷新、Token 的存储位置、Token 的有效期以及刷新 Token 的有效期等等。
     * Token 有效期这个好理解刷新 Token 的有效期我说一下,当 Token 快要过期时候,
     * 我们需要获取一个新的 Token,在获取新的 Token 时候需要一个凭证信息,
     * 这个凭证信息不是旧的 Token,而是另外一个 refresh_token,这个 refresh_token 也是有有效期的。
     */
    @Bean
    public AuthorizationServerTokenServices authorizationServerTokenServices() {
        DefaultTokenServices services = new DefaultTokenServices();
        //客户端详情服务
        services.setClientDetailsService(clientDetailsService);
        //允许令牌自动刷新
        services.setSupportRefreshToken(true);
        //令牌存储策略-内存
        services.setTokenStore(tokenStore);
        // 令牌默认有效期2小时
        services.setAccessTokenValiditySeconds(60 * 60 * 2);
        // 刷新令牌默认有效期3天
        services.setRefreshTokenValiditySeconds(60 * 60 * 24 * 3);
        return services;
    }

原文地址:https://blog.csdn.net/qq_42264638/article/details/130519064

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_46042.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注