Building a microservice API open platform based on Oauth2 Part 2-Building an authentication and authorization center service oauth2-server

To build an authorization center, we first understand a few tables.

This is the address of the table structure provided by the developer on GitHub: https://github.com/spring-projects/spring-security-oauth/blob/main/spring-security-oauth2/src/test/resources/schema.sql

This is the address for Chinese people to interpret the table structure: https://andaily.com/spring-oauth-server/db_table_description.html

Next, we build a table and get some test data by the way.

DROP TABLE IF EXISTS `oauth_access_token`;CREATE TABLE `oauth_access_token`  (  `token_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' access_token的值通过MD5加密后存储的',  `token` blob NULL COMMENT ' AccessToken 二进制序列化后的值',  `authentication_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT ' ',  `user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' ',  `client_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' ',  `authentication` blob NULL COMMENT ' ',  `refresh_token` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' 刷新token,MD5的值',  PRIMARY KEY (`authentication_id`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;  DROP TABLE IF EXISTS `oauth_approvals`;CREATE TABLE `oauth_approvals`  (  `user_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' ',  `client_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' ',  `scope` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' ',  `status` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' ',  `expires_at` datetime(0) NULL DEFAULT NULL COMMENT ' ',  `last_modified_at` datetime(0) NULL DEFAULT NULL) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;  DROP TABLE IF EXISTS `oauth_client_details`;CREATE TABLE `oauth_client_details`  (  `client_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT ' 客户端ID,唯一',  `resource_ids` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' 客户端所能访问的资源id集合',  `client_secret` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '客户端(client)的访问密匙 ',  `scope` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '客户端申请的权限范围,可选值包括read,write,trust;若有多个权限范围用逗号(,)分隔',  `authorized_grant_types` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' 指定客户端支持的grant_type',  `web_server_redirect_uri` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' 客户端的重定向URI',  `authorities` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' 客户端所拥有的Spring Security的权限值',  `access_token_validity` int(11) NULL DEFAULT NULL COMMENT ' 设定客户端的access_token的有效时间值(单位:秒)',  `refresh_token_validity` int(11) NULL DEFAULT NULL COMMENT ' 设定客户端的refresh_token的有效时间值(单位:秒)',  `additional_information` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '预留的字段,在Oauth的流程中没有实际的使用,必须是JSON格式的数据 ',  `autoapprove` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' 设置用户是否自动Approval操作, 默认值为 false',  PRIMARY KEY (`client_id`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;  INSERT INTO `oauth_client_details` VALUES ('good123', NULL, '202cb962ac59075b964b07152d234b70', 'trust', 'authorization_code,password,refresh_token', 'http://www.baidu.com', 'ROLE_UNITY,ROLE_USER', 7200, 7200, NULL, 'false');  DROP TABLE IF EXISTS `oauth_client_token`;CREATE TABLE `oauth_client_token`  (  `token_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' access_token的值',  `token` blob NULL COMMENT ' 进制的字段,AccessToken 二进制序列化后的值',  `authentication_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT ' 该字段具有唯一性, 是根据当前的username(如果有),client_id与scope通过MD5加密\r\n生成的',  `user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' 登录时的用户名',  `client_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' 客户端ID',  PRIMARY KEY (`authentication_id`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;  DROP TABLE IF EXISTS `oauth_code`;CREATE TABLE `oauth_code`  (  `code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' 存储服务端系统生成的code的值(未加密)',  `authentication` blob NULL) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;  DROP TABLE IF EXISTS `oauth_refresh_token`;CREATE TABLE `oauth_refresh_token`  (  `token_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT ' refresh_token的值通过MD5加密后存储',  `token` blob NULL COMMENT ' refresh_token 二进制值',  `authentication` blob NULL) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;  DROP TABLE IF EXISTS `t_user`;CREATE TABLE `t_user`  (  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID,也是用户ID',  `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户名',  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '密码',  `enabled` bit(1) NULL DEFAULT b'1' COMMENT '是否生效,1=true,0=false',  `account_non_expired` bit(1) NULL DEFAULT b'1' COMMENT '是否未过期,1=true,0=false',  `account_non_locked` bit(1) NULL DEFAULT b'1' COMMENT '是否未锁定,1=true,0=false',  `credentials_non_expired` bit(1) NULL DEFAULT b'1' COMMENT '证书是否未过期,1=true,0=false',  PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;  INSERT INTO `t_user` VALUES (1, 'admin', '202cb962ac59075b964b07152d234b70', b'1', b'1', b'1', b'1');INSERT INTO `t_user` VALUES (2, 'user', '250cf8b51c773f3f8dc8b4be867a9a02', b'1', b'1', b'1', b'1'); 

Description: t_user is a table we created to use Spring Security.

If you don’t know Spring Security, you can check my blog: https://blog.csdn.net/BiandanLoveyou/article/details/117400876

The overall code structure of this case is as follows:

Outer pom.xml configuration:

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelVersion>4.0.0</modelVersion>     <groupId>com.study</groupId>    <artifactId>study-oauth2</artifactId>    <packaging>pom</packaging>    <version>1.0-SNAPSHOT</version>    <modules>        <module>oauth2-server</module>        <module>order-server</module>    </modules>     <parent>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-parent</artifactId>        <version>2.2.2.RELEASE</version>    </parent>     <dependencies>        <!--Spring boot 集成包-->        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>        </dependency>        <!-- SpringBoot整合Web组件 -->        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-test</artifactId>            <scope>test</scope>        </dependency>        <!-- 阿里巴巴 fastjson -->        <dependency>            <groupId>com.alibaba</groupId>            <artifactId>fastjson</artifactId>            <version>1.2.75</version>        </dependency>        <!-->spring-boot 整合security -->        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-security</artifactId>        </dependency>        <!-- spring-cloud-starter-oauth2 -->        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-oauth2</artifactId>        </dependency>        <!-- 阿里巴巴的druid数据库连接池 -->        <dependency>            <groupId>com.alibaba</groupId>            <artifactId>druid-spring-boot-starter</artifactId>            <version>1.1.20</version>        </dependency>        <!-- 该 starter 会扫描配置文件中的 DataSource,然后自动创建使用该 DataSource 的 SqlSessionFactoryBean,并注册到 Spring 上下文中 -->        <dependency>            <groupId>org.mybatis.spring.boot</groupId>            <artifactId>mybatis-spring-boot-starter</artifactId>            <version>2.0.0</version>        </dependency>        <!-- 数据库MySQL 依赖包 -->        <dependency>            <groupId>mysql</groupId>            <artifactId>mysql-connector-java</artifactId>            <version>5.1.48</version>        </dependency>        <!-- mybatis 依赖包 -->        <dependency>            <groupId>org.mybatis</groupId>            <artifactId>mybatis</artifactId>            <version>3.4.6</version>        </dependency>    </dependencies>     <dependencyManagement>        <dependencies>            <dependency>                <groupId>org.springframework.cloud</groupId>                <artifactId>spring-cloud-dependencies</artifactId>                <version>Hoxton.SR2</version>                <type>pom</type>                <scope>import</scope>            </dependency>        </dependencies>    </dependencyManagement> </project>

Write down the configuration of oauth2-server.

application.yml placement

server:  port: 8080 # 将SpringBoot项目作为单实例部署调试时,不需要注册到注册中心eureka:  client:    fetch-registry: false    register-with-eureka: false spring:  application:    name: aouth2-server  # 数据源配置  datasource:    # 使用阿里巴巴的 druid 数据源    druid:      driver-class-name: com.mysql.jdbc.Driver      url: jdbc:mysql://localhost:3306/study_oauth2?characterEncoding=utf-8      username: root      password: root # mybatis 配置mybatis:  # Mybatis扫描的mapper文件  mapper-locations: classpath:mapper/*.xml

UserEntityMapper.xml:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.study.dao.UserMapper">   <resultMap id="BaseResultMap" type="com.study.entity.UserEntity">    <id column="id" jdbcType="INTEGER" property="id" />    <result column="username" jdbcType="VARCHAR" property="username" />    <result column="password" jdbcType="VARCHAR" property="password" />    <result column="enabled" jdbcType="BIT" property="enabled" />    <result column="account_non_expired" jdbcType="BIT" property="accountNonExpired" />    <result column="account_non_locked" jdbcType="BIT" property="accountNonLocked" />    <result column="credentials_non_expired" jdbcType="BIT" property="credentialsNonExpired" />  </resultMap>    <!-- 根据用户名查询数据 -->  <select id="getByUsername" parameterType="java.lang.String" resultMap="BaseResultMap">    select *    from t_user    where username = #{username,jdbcType=INTEGER}  </select> </mapper>

UserEntity entity class:

package com.study.entity; import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.userdetails.UserDetails; import java.util.ArrayList;import java.util.List; /** * @author biandan * @description 用户实体类,需要实现 UserDetails 接口 * @signature 让天下没有难写的代码 * @create 2021-05-31 下午 12:43 */public class UserEntity implements UserDetails {     private Integer id;     //用户名    private String username;     //密码    private String password;     //用户所有权限集合    private List<GrantedAuthority> authorities = new ArrayList<>();     //是否生效,1=true,0=false    private boolean enabled;     //是否未过期,1=true,0=false    private boolean accountNonExpired;     //是否未锁定,1=true,0=false    private boolean accountNonLocked;     //证书是否未过期,1=true,0=false    private boolean credentialsNonExpired;     省略 get、set 方法,请补上}

UserMapper mapping file:

package com.study.dao; import com.study.entity.UserEntity;import org.apache.ibatis.annotations.Mapper; @Mapper //如果不在 dao 层增加 @Mapper 注解,就在启动类增加扫描 dao 层的包public interface UserMapper {     /**     * 根据用户名查询     * @param username     * @return     */    UserEntity getByUsername(String username); }

MyUserDetailService code: pay attention to implement the  org.springframework.security.core.userdetails.UserDetailsService interface.

package com.study.service; import com.study.dao.UserMapper;import com.study.entity.UserEntity;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.core.userdetails.UsernameNotFoundException;import org.springframework.stereotype.Component; /** * @author biandan * @description * @signature 让天下没有难写的代码 * @create 2021-05-09 下午 2:45 */@Componentpublic class MyUserDetailService implements UserDetailsService {     @Autowired    private UserMapper userMapper;      /**     * 查询用户信息,并返回给 security 需要的用户对象     * @param username     * @return     * @throws UsernameNotFoundException     */    @Override    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {        UserEntity userEntity = userMapper.getByUsername(username);        return userEntity;    }}

SpringSecurity related configuration class: SecurityConfig

package com.study.config; import com.study.service.MyUserDetailService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.authentication.AuthenticationManager;import org.springframework.security.authentication.dao.DaoAuthenticationProvider;import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import org.springframework.security.crypto.password.PasswordEncoder;import org.springframework.util.DigestUtils; /** * @author biandan * @description * @signature 让天下没有难写的代码 * @create 2021-05-30 下午 9:38 */@[email protected] class SecurityConfig extends WebSecurityConfigurerAdapter {     @Autowired    private MyUserDetailService myUserDetailService;     // 配置认证用户信息和权限    @Override    protected void configure(AuthenticationManagerBuilder auth) throws Exception {        //从数据库中获取数据,并校验密码是否一致        auth.userDetailsService(myUserDetailService).passwordEncoder(myPasswordEncoder());    }     // 配置拦截请求资源    @Override    protected void configure(HttpSecurity http) throws Exception {        http.authorizeRequests().antMatchers("/**")                .fullyAuthenticated().and().httpBasic()                .and().csrf().disable();     }     // 授权中心管理器    @Bean    @Override    public AuthenticationManager authenticationManagerBean() throws Exception {        return super.authenticationManager();    }     @Bean    public DaoAuthenticationProvider daoAuthenticationProvider() {        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();        // 设置userDetailsService        daoAuthenticationProvider.setUserDetailsService(userDetailsService());        // 禁止隐藏用户,抛出未找到异常        daoAuthenticationProvider.setHideUserNotFoundExceptions(false);        // 加密方式        daoAuthenticationProvider.setPasswordEncoder(myPasswordEncoder());        return daoAuthenticationProvider;    }      //自定义加密方式    @Bean    PasswordEncoder myPasswordEncoder() {        PasswordEncoder passwordEncoder = new PasswordEncoder() {            //重写加密方法            @Override            public String encode(CharSequence charSequence) {                String md5Pwd = DigestUtils.md5DigestAsHex(((String) charSequence).getBytes());                return md5Pwd;            }             /**             * 判断密码是否匹配             *             * @param charSequence 请求的密码             * @param sqlPwd       数据库密码             * @return             */            @Override            public boolean matches(CharSequence charSequence, String sqlPwd) {                String reqPwd = encode(charSequence);                boolean result = reqPwd.equals(sqlPwd);                System.out.println("matches reqPwd=" + reqPwd + ";sqlPwd=" + sqlPwd + ",匹配结果:result=" + result);                return result;//只有返回 true 的情况才会验证成功            }        };        return passwordEncoder;    }}

The highlight of AuthorizationServerConfig code:

package com.study.config; import com.study.service.MyUserDetailService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.http.HttpHeaders;import org.springframework.security.authentication.AuthenticationManager;import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;import org.springframework.security.oauth2.provider.token.TokenStore;import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;import org.springframework.web.cors.CorsConfiguration;import org.springframework.web.cors.CorsConfigurationSource;import org.springframework.web.filter.CorsFilter; import javax.servlet.http.HttpServletRequest;import javax.sql.DataSource; /** * @author biandan * @description * @signature 让天下没有难写的代码 * @create 2021-06-05 下午 3:39 */@[email protected] //开启认证授权中心public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {     @Autowired    private AuthenticationManager authenticationManager;     @Autowired    private DataSource dataSource;     @Autowired    private MyUserDetailService myUserDetailService;     //设置保存token的方式,一共有五种,这里采用数据库的方式    @Bean    public TokenStore tokenStore() {        return new JdbcTokenStore(dataSource);    }     //配置授权(authorization)以及令牌(token)的访问端点和令牌服务    @Override    public void configure(AuthorizationServerEndpointsConfigurer endpoints){        endpoints.tokenStore(tokenStore())//配置token存储方式                //开启密码授权类型                .authenticationManager(authenticationManager)                //要使用refresh_token的话,需要额外配置userDetailsService                .userDetailsService(myUserDetailService);    }     //配置客户端详情服务    @Override    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {        clients.jdbc(dataSource);    }     //配置令牌端点(Token Endpoint)的安全约束    @Override    public void configure(AuthorizationServerSecurityConfigurer security){        //配置oauth2服务跨域        CorsConfigurationSource configurationSource = new CorsConfigurationSource() {            @Override            public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {                CorsConfiguration corsConfiguration = new CorsConfiguration();                corsConfiguration.addAllowedHeader("*");                corsConfiguration.addAllowedOrigin(request.getHeader( HttpHeaders.ORIGIN));                corsConfiguration.addAllowedMethod("*");                corsConfiguration.setAllowCredentials(true);                corsConfiguration.setMaxAge(3600L);                return corsConfiguration;            }        };         security.tokenKeyAccess("permitAll()")//开启/oauth/token_key验证端口无权限访问                .checkTokenAccess("permitAll()")//开启/oauth/check_token验证端口认证权限访问                .allowFormAuthenticationForClients()//允许表单登录                .addTokenEndpointAuthenticationFilter(new CorsFilter(configurationSource));//跨域    }}

Description: We implement the AuthorizationServerConfigurerAdapter adapter and rewrite several methods.

①AuthorizationServerEndpointsConfigurer: Configure authorization and token access endpoints and token services

②ClientDetailsServiceConfigurer: configure the client details service, here we use the method of reading the database. clients.jdbc(dataSource);

③AuthorizationServerSecurityConfigurer: Configure the security constraints of the Token Endpoint

Our TokenStore uses JdbcTokenStore, which is convenient and fast and saves a lot of time. If you use jwt, you need to study it, and the token generated by jwt is very long.

Start class Oauth2Application:

package com.study; import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication; /** * @author biandan * @description * @signature 让天下没有难写的代码 * @create 2021-06-05 下午 1:59 */@SpringBootApplicationpublic class Oauth2Application {     public static void main(String[] args) {        SpringApplication.run(Oauth2Application.class,args);    }}

Combined with our database test data (table: oauth_client_details), let's test it.

1. Obtain the authorization code and enter the browser address: http://127.0.0.1:8080/oauth/authorize?client_id=good123&response_type=code&redirect_uri=http://www.baidu.com

Description: client_id, redirect_uri should correspond to the database, response_type=code, fixed, get the authorization code. The first login will enter the verification interface of SpringSecurity. Reference table: t_user

Click [Login], Oauth2 will return the authorization code according to the redirect_uri passed by us. As shown in the figure:

We copy the data behind the code.

2. Obtain the accessToken. We need to use the postman tool. Enter the address: http://127.0.0.1:8080/oauth/token    and the following parameters (put it in the Params parameter list, POST request, you need to enter the account and password of the client, refer to the table: oauth_client_details, redirect_uri is required, and follow The address where we get the authorization code is the same. scope=trust, many on the Internet say scope=all, that is the old version, if you use the current version, all will report an error.):

Full path: http://127.0.0.1:8080/oauth/token ?grant_type=authorization_code&code=x9mUj9&redirect_uri=http://www.baidu.com&scope=trust&client_id=good123&client_secret=123

As shown in the figure:

OK, get access_token and refresh_token, and expires_in indicates how many seconds are left in the validity period, scope indicates the scope, the old version is all, and the new version is trust. token_type = bearer, we will talk about how to use this later.

3. Use refresh_token to get access_token. Because the validity period of the access_token is 2 hours, we can't wait until the access_token expires to get the latest one, otherwise the user suddenly jumps to the authorization page while using it, it would be embarrassing. So our approach is to open a timed task to refresh the access_token.

http://127.0.0.1:8080/oauth/token?grant_type=refresh_token&refresh_token=37661e5e-7ed2-4dde-a8c3-ebfcd42b467a&client_id=good123&client_secret=123&redirect_uri=http://www.baidu.com&scope=trust

As shown in the figure, we select the body's parameter transfer method, x-www-form-urlencoded encoding parameters (you can view the blog: https://blog.csdn.net/BiandanLoveyou/article/details/117440256 ), and then enter the refresh_token value, And the account and password of the client. After the latest access_token is obtained, the old access_token cannot be used.

In the actual project, we will store the obtained access_token in Redis, and then open a timed task to refresh and obtain the latest access_token when the access_token is about to expire (for example, every hour).

4、校验 access_token :http://localhost:8080/oauth/check_token?token=dc25fa3f-f6a0-4742-8ab8-2d6b63548fcc

OK, the establishment of the certification and authorization center service is completed.

The blog code address: https://pan.baidu.com/s/1Ys02FMGHbw49PK3Fp-FChQ    extraction code: agmr