述
前面的文章中,实现了我们三种自定义登录方式的 token 返回,做的也全是一些资源服务器的配置,本文再来看一些关于认证服务器的配置, 比如 Token 的过期时间,存储方式等等
认证服务器配置
在之前的配置类 MyAuthorizationServerConfig
做修改,首先继承 AuthorizationServerConfigurerAdapter
client自定义配置
之前我们配置 client_id
和 client_serect
都是在应用的 application.yml
中去配置的,这种方式是基于内存的配置. 而且token的过期时间等等配置都是用的默认的配置, 在实际情况中, 每个应用的 client_id
和 client_serect
都应该放到数据库中去存储,就比如我们之前去QQ互联平台去创建应用一样, 下面看一下如何使用数据库存储client信息
首先需要修改我们认证服务器的配置类 MyAuthorizationServerConfig
,然后继承 AuthorizationServerConfigurerAdapter
, 代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34@Configuration
@EnableAuthorizationServer
public class MyAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private DataSource dataSource;
@Autowired
private TokenStore tokenStore;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
endpoints.userDetailsService(userDetailsService);
endpoints.tokenStore(tokenStore);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 这个地方指的是从jdbc查出数据来存储
clients.withClientDetails(clientDetails());
}
private ClientDetailsService clientDetails() {
return new JdbcClientDetailsService(dataSource);
}
}
这里重写了两个方法,上面的这个是 endpoints 的一些配置, 只要重写了这个方法,就必须我们自己去指定 authenticationManager
和 userDetailsService
然后下面这个就是对 client 的一些配置,只要重写了这个方法,之前我们在 application.yml
中的配置就失效了
client的信息默认是在内存中的,这种方式对于单个服务器是完全正常的(即,在发生故障的情况下,低流量和热备份备份服务器).大多数项目可以从这里开始,也可以在开发模式下运行,以便轻松启动没有依赖关系的服务器.
我们这里只介绍用数据库存储的方式, 就是设置一下数据源就可以了
然后这里在数据库里面需要用到一张表,如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14CREATE TABLE `oauth_client_details` (
`client_id` varchar(48) 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=utf8;
添一条测试数据1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27INSERT 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
)
VALUES
(
'testAppid',
NULL,
'testSecret',
'read,write,all',
'authorization_code,refresh_token,password',
'http://www.pinzhi365.com',
'ROLE_USER',
86400,
86400,
NULL,
FALSE
);
具体的每列的作用,说明在这里
配置 Token 的存储方式
在之前的配置中,Token都是存放在内存中的,只要重启应用,token就都失效了,通常情况下都是要放到redis里面的,下面看一下如何使用 redis 存储 Token
新建一个 TokenStoreConfig
类,如下:1
2
3
4
5
6
7
8
9
10
11@Configuration
public class TokenStoreConfig {
@Autowired
private RedisConnectionFactory connectionFactory;
@Bean
public TokenStore redisTokenStore(){
return new RedisTokenStore(connectionFactory);
}
}
然后在上面的配置类中的第一个 configure
方法中注入进去就ok了
踩坑
这里遇到一个问题,我们项目目前的依赖 spring-boot-starter-data-redis
的默认实现是 Jedis
, RedisTokenStore
中会使用 Pipeline
的功能,Jedis对于单节点可以支持 Pipeline
,但是集群则没有支持 Pipeline
, 因为我这里配置的是集群,所以这里就不能正常运行,错误如下:
1 | UnsupportedOperationException, Pipeline is currently not supported for JedisClusterConnection. |
要解决这个问题,要么自己实现Jedis对Pipeline的支持,这比较复杂.另一种就是使用lettuce代替Jedis,luttuce对于集群使用Pipeline有很好的支持.
我们只需要引入luttuce的依赖:1
2
3
4<dependency>
<groupId>biz.paluch.redis</groupId>
<artifactId>lettuce</artifactId>
</dependency>
然后在 redis
的配置类中,加入:1
2
3
4
5
6
7
8
9
10
11
12
13@Primary
@Bean
public LettuceConnectionFactory redisConnectionFactory(RedisProperties redisProperties) {
RedisProperties.Cluster cluster = redisProperties.getCluster();
if (cluster != null) {
RedisClusterConfiguration configuration = new RedisClusterConfiguration(cluster.getNodes());
return new LettuceConnectionFactory(configuration);
} else {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(redisProperties.getHost(), redisProperties.getPort());
connectionFactory.setPassword(redisProperties.getPassword());
return connectionFactory;
}
}
这样就ok了
测试
如下:
接口可以正常访问,就说明数据库配置的client信息已经生效了, 然后再看一下redis中
上面生成的token也正常的放到了redis中
本文代码传送门 (忘记创建分支了,跟前面一章写在了同一个分支上)