前言

前面的文章Spring Cloud进阶之路 | 八:授权服务(Spring Cloud Oauth2)中,介绍了基于Spring Cloud Oauth2框架的微服务授权服务器。其中,关于认证客户端相关信息均存储在内存中,服务一旦重启,即随即丢失,非常不利于维护。在实际项目中,势必要持久化存储。

本文即对认证客户端信息持久化ClientDetailsServic之JdbcClientDetailsService做相关说明。

 

准备工作

复用文章Spring Cloud进阶之路 | 八:授权服务(Spring Cloud Oauth2)中的xmall-auth授权工程。

 

授权服务器配置改造

通过方法public void configure(ClientDetailsServiceConfigurer clients) throws Exception配置ClientDetailsServic为JdbcClientDetailsService。

其中,共有四种方案。下面将分别介绍。

 

方案一

此方案最简单常见,只需配置DataSource即可,其它交给框架自动配置。

package com.luas.xmall.auth.configuration;
​
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.builders.JdbcClientDetailsServiceBuilder;
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.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
​
import javax.sql.DataSource;
​
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
​
    @Autowired
    private PasswordEncoder passwordEncoder;
​
    @Autowired
    private UserDetailsService userDetailsService;
​
    @Autowired
    private AuthenticationManager authenticationManager;
​
    @Autowired
    private DataSource dataSource;
​
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.
                allowFormAuthenticationForClients()
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("permitAll()")
        ;
    }
​
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(new InMemoryTokenStore())
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService)
                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
    }
​
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 配置方法1,只需配置DataSource即可,其它交给框架自动配置
        clients.jdbc(dataSource).passwordEncoder(passwordEncoder);
    }
​
}

​​

方案二

本方案以构建ClientDetailsServiceBuilder为最终目的。

package com.luas.xmall.auth.configuration;
​
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.builders.JdbcClientDetailsServiceBuilder;
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.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
​
import javax.sql.DataSource;
​
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
​
    @Autowired
    private PasswordEncoder passwordEncoder;
​
    @Autowired
    private UserDetailsService userDetailsService;
​
    @Autowired
    private AuthenticationManager authenticationManager;
​
    @Autowired
    private DataSource dataSource;
​
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.
                allowFormAuthenticationForClients()
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("permitAll()")
        ;
    }
​
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(new InMemoryTokenStore())
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService)
                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
    }
​
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 配置方法2,构建ClientDetailsServiceBuilder
        clients.configure(jdbcClientDetailsServiceBuilder());
    }
​
    private JdbcClientDetailsServiceBuilder jdbcClientDetailsServiceBuilder() {
        return new JdbcClientDetailsServiceBuilder().dataSource(dataSource).passwordEncoder(passwordEncoder);
    }
}

 

方案三

此方案以构建ClientDetailsService为最终目的,本例中,我们使用ClientDetailsServiceBuilder来构建ClientDetailsService,即以JdbcClientDetailsServiceBuilder构建JdbcClientDetailsService,比较方便,也可以直接构建JdbcClientDetailsService对象。

使用JdbcClientDetailsServiceBuilder构建JdbcClientDetailsService。

package com.luas.xmall.auth.configuration;
​
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.builders.JdbcClientDetailsServiceBuilder;
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.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
​
import javax.sql.DataSource;
​
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
​
    @Autowired
    private PasswordEncoder passwordEncoder;
​
    @Autowired
    private UserDetailsService userDetailsService;
​
    @Autowired
    private AuthenticationManager authenticationManager;
​
    @Autowired
    private DataSource dataSource;
​
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.
                allowFormAuthenticationForClients()
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("permitAll()")
        ;
    }
​
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(new InMemoryTokenStore())
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService)
                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
    }
​
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 配置方法3,使用ClientDetailsServiceBuilder构建ClientDetailsService
        clients.withClientDetails(jdbcClientDetailsService());
    }
​
    private ClientDetailsService jdbcClientDetailsService() throws Exception {
        return new JdbcClientDetailsServiceBuilder().dataSource(dataSource).passwordEncoder(passwordEncoder).build();
    }
​
}

直接构建JdbcClientDetailsService对象。

package com.luas.xmall.auth.configuration;
​
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.builders.JdbcClientDetailsServiceBuilder;
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.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
​
import javax.sql.DataSource;
​
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
​
    @Autowired
    private PasswordEncoder passwordEncoder;
​
    @Autowired
    private UserDetailsService userDetailsService;
​
    @Autowired
    private AuthenticationManager authenticationManager;
​
    @Autowired
    private DataSource dataSource;
​
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.
                allowFormAuthenticationForClients()
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("permitAll()")
        ;
    }
​
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(new InMemoryTokenStore())
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService)
                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
    }
​
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 配置方法3,使用ClientDetailsServiceBuilder构建ClientDetailsService
        clients.withClientDetails(jdbcClientDetailsService());
    }
​
    private ClientDetailsService jdbcClientDetailsService() throws Exception {
        // 直接构建JdbcClientDetailsService对象
        JdbcClientDetailsService jdbcClientDetailsService = new JdbcClientDetailsService(dataSource);
        jdbcClientDetailsService.setPasswordEncoder(passwordEncoder);
        return jdbcClientDetailsService;
    }
}

 

方案四

本方案为自定义ClientDetailsService,实际项目中,也许存在不按照官方建议的数据结构的情况,此时,就需要自行定义数据结构,同时,也必须自行定义对应的ClientDetailsService,用以获取ClientDetails。

package com.luas.xmall.auth.configuration;
​
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.builders.JdbcClientDetailsServiceBuilder;
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.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
​
import javax.sql.DataSource;
​
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
​
    @Autowired
    private PasswordEncoder passwordEncoder;
​
    @Autowired
    private UserDetailsService userDetailsService;
​
    @Autowired
    private AuthenticationManager authenticationManager;
​
    @Autowired
    private DataSource dataSource;
​
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.
                allowFormAuthenticationForClients()
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("permitAll()")
        ;
    }
​
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(new InMemoryTokenStore())
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService)
                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
    }
​
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 配置方法4,自定义ClientDetailsService
        clients.withClientDetails(myClientDetailsService());
    }
​
    public ClientDetailsService myClientDetailsService() throws Exception {
        return new ClientDetailsService() {
            @Override
            public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
                // TODO 调用dao、service查询自定义数据结构、库,组织对应的ClientDetails
                return null;
            }
        };
    }
}

 

聚合配置

聚合四种方案,配置如下,可自行注释、取消相关注释,以开启对应方案。

package com.luas.xmall.auth.configuration;
​
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.builders.JdbcClientDetailsServiceBuilder;
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.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
​
import javax.sql.DataSource;
​
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
​
    @Autowired
    private PasswordEncoder passwordEncoder;
​
    @Autowired
    private UserDetailsService userDetailsService;
​
    @Autowired
    private AuthenticationManager authenticationManager;
​
    @Autowired
    private DataSource dataSource;
​
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.
                allowFormAuthenticationForClients()
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("permitAll()")
        ;
    }
​
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(new InMemoryTokenStore())
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService)
                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
    }
​
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 配置方法1,只需配置DataSource即可,其它交给框架自动配置
        clients.jdbc(dataSource).passwordEncoder(passwordEncoder);
​
        // 配置方法2,构建ClientDetailsServiceBuilder
        //clients.configure(jdbcClientDetailsServiceBuilder());
​
        // 配置方法3,使用ClientDetailsServiceBuilder构建ClientDetailsService
        //clients.withClientDetails(jdbcClientDetailsService());
​
        // 配置方法4,自定义ClientDetailsService
        //clients.withClientDetails(myClientDetailsService());
    }
​
    private JdbcClientDetailsServiceBuilder jdbcClientDetailsServiceBuilder() {
        return new JdbcClientDetailsServiceBuilder().dataSource(dataSource).passwordEncoder(passwordEncoder);
    }
​
    private ClientDetailsService jdbcClientDetailsService() throws Exception {
        return new JdbcClientDetailsServiceBuilder().dataSource(dataSource).passwordEncoder(passwordEncoder).build();
​
        // 直接构建JdbcClientDetailsService对象
//        JdbcClientDetailsService jdbcClientDetailsService = new JdbcClientDetailsService(dataSource);
//        jdbcClientDetailsService.setPasswordEncoder(passwordEncoder);
//        return jdbcClientDetailsService;
    }
​
    public ClientDetailsService myClientDetailsService() throws Exception {
        return new ClientDetailsService() {
            @Override
            public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
                // TODO 调用dao、service查询自定义数据结构、库,组织对应的ClientDetails
                return null;
            }
        };
    }
}

 

数据源

配置数据源DataSource。

server:
  port: 7777
​
spring:
  datasource:
    name: test
    url: jdbc:mysql://127.0.0.1:3306/xmall-auth?characterEncoding=utf8&generateSimpleParameterMetadata=true&serverTimezone=GMT%2B8
    username: root
    password: 123456
    # 使用druid数据源
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    filters: stat,slf4j
    maxActive: 20
    initialSize: 2
    minIdle: 1
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60
    minEvictableIdleTimeMillis: 300000
    validationQuery: select 'x'
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    maxOpenPreparedStatements: 20

 

数据结构

官方建议的数据结构如下,可根据数据库类型,自行调整。shcema.sql文件位于src/main/resources下。

create table oauth_client_details (
  client_id VARCHAR(256) PRIMARY KEY,
  resource_ids VARCHAR(256),
  client_secret VARCHAR(256),
  scope VARCHAR(256),
  authorized_grant_types VARCHAR(256),
  web_server_redirect_uri VARCHAR(256),
  authorities VARCHAR(256),
  access_token_validity INTEGER,
  refresh_token_validity INTEGER,
  additional_information VARCHAR(4096),
  autoapprove VARCHAR(256),
  create_time TIMESTAMP
);
​
create table oauth_client_token (
  token_id VARCHAR(256),
  token LONGVARBINARY,
  authentication_id VARCHAR(256) PRIMARY KEY,
  user_name VARCHAR(256),
  client_id VARCHAR(256),
  create_time TIMESTAMP
);
​
create table oauth_access_token (
  token_id VARCHAR(256),
  token LONGVARBINARY,
  authentication_id VARCHAR(256) PRIMARY KEY,
  user_name VARCHAR(256),
  client_id VARCHAR(256),
  authentication LONGVARBINARY,
  refresh_token VARCHAR(256),
  create_time TIMESTAMP
);
​
create table oauth_refresh_token (
  token_id VARCHAR(256),
  token LONGVARBINARY,
  authentication LONGVARBINARY,
  create_time TIMESTAMP
);
​
create table oauth_code (
  code VARCHAR(256), authentication LONGVARBINARY, create_time TIMESTAMP
);
​
create table oauth_approvals (
  userId VARCHAR(256),
  clientId VARCHAR(256),
  scope VARCHAR(256),
  status VARCHAR(10),
  expiresAt TIMESTAMP,
  lastModifiedAt TIMESTAMP,
  create_time TIMESTAMP
);
​
​
create table ClientDetails (
  appId VARCHAR(256) PRIMARY KEY,
  resourceIds VARCHAR(256),
  appSecret VARCHAR(256),
  scope VARCHAR(256),
  grantTypes VARCHAR(256),
  redirectUrl VARCHAR(256),
  authorities VARCHAR(256),
  access_token_validity INTEGER,
  refresh_token_validity INTEGER,
  additionalInformation VARCHAR(4096),
  autoApproveScopes VARCHAR(256),
  create_time TIMESTAMP
);

另外,针对mysql,笔者改造了一版mysql数据库对应的数据结构,shcema-mysql.sql文件位于src/main/resources下。

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_time TIMESTAMP
);
​
create table oauth_client_token (
  token_id VARCHAR(255),
  token BLOB,
  authentication_id VARCHAR(255) PRIMARY KEY,
  user_name VARCHAR(255),
  client_id VARCHAR(255),
  create_time TIMESTAMP
);
​
create table oauth_access_token (
  token_id VARCHAR(255),
  token BLOB,
  authentication_id VARCHAR(255) PRIMARY KEY,
  user_name VARCHAR(255),
  client_id VARCHAR(255),
  authentication BLOB,
  refresh_token VARCHAR(255),
  create_time TIMESTAMP
);
​
create table oauth_refresh_token (
  token_id VARCHAR(255),
  token BLOB,
  authentication BLOB,
  create_time TIMESTAMP
);
​
create table oauth_code (
  code VARCHAR(255), authentication BLOB, create_time TIMESTAMP
);
​
create table oauth_approvals (
  userId VARCHAR(255),
  clientId VARCHAR(255),
  scope VARCHAR(255),
  status VARCHAR(10),
  expiresAt TIMESTAMP,
  lastModifiedAt TIMESTAMP,
  create_time TIMESTAMP
);
​
​
create table ClientDetails (
  appId VARCHAR(255) PRIMARY KEY,
  resourceIds VARCHAR(255),
  appSecret VARCHAR(255),
  scope VARCHAR(255),
  grantTypes VARCHAR(255),
  redirectUrl VARCHAR(255),
  authorities VARCHAR(255),
  access_token_validity INTEGER,
  refresh_token_validity INTEGER,
  additionalInformation VARCHAR(4096),
  autoApproveScopes VARCHAR(255),
  create_time TIMESTAMP
);

 

时间戳字段问题

mysql版本不同,对TIMESTAMP类型解释也不同,如mysql5.7,版本,create_time TIMESTAMP代表的含义如下:

  1. 如果该字段是第一个TIMESTAMP字段,则等同于create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

  2. 如果该字段不是第一个TIMESTAMP字段,则等同于create_time TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00'。特别说明一下,此种情况下,数据库会报错,因为不允许0类型的日期值存在。

至于其它版本的解释,读者可自行查阅相关资料,笔者后续也会详细介绍此数据库字段类型。

 

客户端信息


将之前在内存中存储的客户端信息初始化到数据库中,sql文件见目录src/main/resources/

INSERT INTO `oauth_client_details`(`client_id`, `resource_ids`, `client_secret`, `scope`, `authorized_grant_types`, `web_server_redirect_uri`, `authorities`, `access_token_validity`, `refresh_token_validity`, `additional_information`, `autoapprove`, `create_time`) VALUES ('admin', 'xmall-auth,xmall-product', '$2a$10$zNDgAkXKu4xSeupcLlZsKuSpmU75MQDqODhieBZvTMdeNEKwaUoIi', 'server,select', 'authorization_code,password,refresh_token,client_credentials,implicit', 'http://www.baidu.com', NULL, NULL, NULL, NULL, NULL, '2020-02-14 17:23:07');
INSERT INTO `oauth_client_details`(`client_id`, `resource_ids`, `client_secret`, `scope`, `authorized_grant_types`, `web_server_redirect_uri`, `authorities`, `access_token_validity`, `refresh_token_validity`, `additional_information`, `autoapprove`, `create_time`) VALUES ('client_1', 'xmall-auth,xmall-product', '$2a$10$zNDgAkXKu4xSeupcLlZsKuSpmU75MQDqODhieBZvTMdeNEKwaUoIi', 'server,select', 'password,refresh_token', NULL, NULL, NULL, NULL, NULL, NULL, '2020-02-14 17:24:17');
INSERT INTO `oauth_client_details`(`client_id`, `resource_ids`, `client_secret`, `scope`, `authorized_grant_types`, `web_server_redirect_uri`, `authorities`, `access_token_validity`, `refresh_token_validity`, `additional_information`, `autoapprove`, `create_time`) VALUES ('client_2', 'xmall-auth,xmall-product', '$2a$10$zNDgAkXKu4xSeupcLlZsKuSpmU75MQDqODhieBZvTMdeNEKwaUoIi', 'server,select', 'client_credentials,refresh_token', NULL, NULL, NULL, NULL, NULL, NULL, '2020-02-14 17:24:57');

 

验证

启动xmall-auth工程,端口为7777。

访问http://localhost:7777/oauth/token,输入一众参数,诸如client_id、client_secret、grant_type等,点击Send,即出现access_token、refresh_token等信息。

 

源码


github

https://github.com/liuminglei/SpringCloudLearning/tree/master/18/

gitee

https://gitee.com/xbd521/SpringCloudLearning/tree/master/18/

 

 

本文系【银河架构师】原创,如需转载请在文章明显处注明作者及出处。

微信搜索【银河架构师】,发现更多精彩内容。

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐