在上面的案例中,TokenStore 的默认实现为 InMemoryTokenStore 即内存存储,对于 Client 信息,ClientDetailsService 接口负责从存储仓库中读取数据,在上面的案例中默认使用的也是 InMemoryClientDetailsService 实现类。
如果要想使用数据库存储,只要提供这些接口的实现类即可,而框架已经为我们写好 JdbcTokenStore 和 JdbcClientDetailsService
建表:
https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql
# 注意: 并用 BLOB 替换语句中的 LONGVARBINARY 类型
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for clientdetails
-- ----------------------------
DROP TABLE IF EXISTS `clientdetails`;
CREATE TABLE `clientdetails` (
`appId` varchar(256) NOT NULL,
`resourceIds` varchar(256) DEFAULT NULL,
`appSecret` varchar(256) DEFAULT NULL,
`scope` varchar(256) DEFAULT NULL,
`grantTypes` varchar(256) DEFAULT NULL,
`redirectUrl` varchar(256) DEFAULT NULL,
`authorities` varchar(256) DEFAULT NULL,
`access_token_validity` int(11) DEFAULT NULL,
`refresh_token_validity` int(11) DEFAULT NULL,
`additionalInformation` varchar(4096) DEFAULT NULL,
`autoApproveScopes` varchar(256) DEFAULT NULL,
PRIMARY KEY (`appId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for oauth_access_token
-- ----------------------------
DROP TABLE IF EXISTS `oauth_access_token`;
CREATE TABLE `oauth_access_token` (
`token_id` varchar(256) DEFAULT NULL,
`token` blob,
`authentication_id` varchar(256) NOT NULL,
`user_name` varchar(256) DEFAULT NULL,
`client_id` varchar(256) DEFAULT NULL,
`authentication` blob,
`refresh_token` varchar(256) DEFAULT NULL,
PRIMARY KEY (`authentication_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for oauth_approvals
-- ----------------------------
DROP TABLE IF EXISTS `oauth_approvals`;
CREATE TABLE `oauth_approvals` (
`userId` varchar(256) DEFAULT NULL,
`clientId` varchar(256) DEFAULT NULL,
`scope` varchar(256) DEFAULT NULL,
`status` varchar(10) DEFAULT NULL,
`expiresAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`lastModifiedAt` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for oauth_client_details
-- ----------------------------
DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (
`client_id` varchar(256) NOT NULL,
`resource_ids` varchar(256) DEFAULT NULL,
`client_secret` varchar(256) DEFAULT NULL,
`scope` varchar(256) DEFAULT NULL,
`authorized_grant_types` varchar(256) DEFAULT NULL,
`web_server_redirect_uri` varchar(256) DEFAULT NULL,
`authorities` varchar(256) DEFAULT NULL,
`access_token_validity` int(11) DEFAULT NULL,
`refresh_token_validity` int(11) DEFAULT NULL,
`additional_information` varchar(4096) DEFAULT NULL,
`autoapprove` varchar(256) DEFAULT NULL,
PRIMARY KEY (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for oauth_client_token
-- ----------------------------
DROP TABLE IF EXISTS `oauth_client_token`;
CREATE TABLE `oauth_client_token` (
`token_id` varchar(256) DEFAULT NULL,
`token` blob,
`authentication_id` varchar(256) NOT NULL,
`user_name` varchar(256) DEFAULT NULL,
`client_id` varchar(256) DEFAULT NULL,
PRIMARY KEY (`authentication_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for oauth_code
-- ----------------------------
DROP TABLE IF EXISTS `oauth_code`;
CREATE TABLE `oauth_code` (
`code` varchar(256) DEFAULT NULL,
`authentication` blob
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for oauth_refresh_token
-- ----------------------------
DROP TABLE IF EXISTS `oauth_refresh_token`;
CREATE TABLE `oauth_refresh_token` (
`token_id` varchar(256) DEFAULT NULL,
`token` blob,
`authentication` blob
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
SET FOREIGN_KEY_CHECKS = 1;
-- 写入客户端信息
INSERT INTO `oauth_client_details` VALUES ('client', NULL, '$2a$10$QCsINtuRfP8kM112xRVdvuI58MrefLlEP2mM0kzB5KZCPhnOf4392', 'read', 'authorization_code,refresh_token', 'http://www.baidu.com', NULL, NULL, NULL, NULL, NULL);
引入依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
编写配置文件
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/oauth?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root
编写数据库信息实现
@Configuration
@EnableAuthorizationServer
public class JdbcAuthorizationServer extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
private final PasswordEncoder passwordEncoder;
private final DataSource dataSource;
@Autowired
public JdbcAuthorizationServer(AuthenticationManager authenticationManager, PasswordEncoder passwordEncoder, DataSource dataSource) {
this.authenticationManager = authenticationManager;
this.passwordEncoder = passwordEncoder;
this.dataSource = dataSource;
}
@Bean // 声明TokenStore实现
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
@Bean // 声明 ClientDetails实现
public ClientDetailsService clientDetails() {
JdbcClientDetailsService jdbcClientDetailsService = new JdbcClientDetailsService(dataSource);
jdbcClientDetailsService.setPasswordEncoder(passwordEncoder);
return jdbcClientDetailsService;
}
@Override //配置使用数据库实现
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);//认证管理器
endpoints.tokenStore(tokenStore());//配置令牌存储为数据库存储
// 配置TokenServices参数
DefaultTokenServices tokenServices = new DefaultTokenServices();//修改默认令牌生成服务
tokenServices.setTokenStore(endpoints.getTokenStore());//基于数据库令牌生成
tokenServices.setSupportRefreshToken(true);//是否支持刷新令牌
tokenServices.setReuseRefreshToken(true);//是否重复使用刷新令牌(直到过期)
tokenServices.setClientDetailsService(endpoints.getClientDetailsService());//设置客户端信息
tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());//用来控制令牌存储增强策略
//访问令牌的默认有效期(以秒为单位)。过期的令牌为零或负数。
tokenServices.setAccessTokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(30)); // 30天
//刷新令牌的有效性(以秒为单位)。如果小于或等于零,则令牌将不会过期
tokenServices.setRefreshTokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(3)); //3天
endpoints.tokenServices(tokenServices);//使用配置令牌服务
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetails());//使用 jdbc存储
}
}
启动测试,发现数据库中已经存储相关的令牌