SpringOAuth2从数据库读取配置

标签: Springboot 分类: Java 创建时间:2020-08-11 02:47:35 更新时间:2024-11-15 10:49:43

我在参考文章2的基础上实现了oauth2的客户端和密码模式,存储在内存中,进一步的,我想通过参考文章2实现从数据库中读取配置文件。

参考文章:
1.微服务权限终极解决方案,Spring Cloud Gateway + Oauth2 实现统一认证和鉴权! (这篇文章实现了oauth2的密码模式和客户端模式)
2.oauth2.0通过JdbcClientDetailsService从数据库读取相应的配置 (这篇文章是我的主要参考文章,实现JdbcClientDetalsService,也是我的第一篇参考文章,但是他的需求和我的稍微一些不一样,就是我实现的是client模式,而不是授权码模式)
3.Springboot2+SpringSecurity+Oauth2+Mysql数据库实现持久化客户端数据 (这篇文章里面的代码有点乱,没有换行)
4.Spring Security +Oauth2 +Spring boot 动态定义权限 (这篇文章暂时没有用到)

1.数据表

提供的参考文章是使用的MySQL数据库,我这里改成了SQL Server数据库。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CREATE TABLE [数据库名].dbo.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 DEFAULT NULL,
refresh_token_validity int DEFAULT NULL,
additional_information varchar(4096) DEFAULT NULL,
autoapprove varchar(256) DEFAULT NULL,
PRIMARY KEY (client_id)
)

数据例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"oauth_client_details": [
{
"client_id" : "client_2",
"resource_ids" : null,
"client_secret" : "$2a$10$Cjeag\/\/umnkFDVRNZlreP.RUCheKinx.2cX6IxnzdzIWYLfBMDy\/q",
"scope" : "all",
"authorized_grant_types" : "client_credentials",
"web_server_redirect_uri" : null,
"authorities" : "client",
"access_token_validity" : null,
"refresh_token_validity" : null,
"additional_information" : null,
"autoapprove" : null
}
]}

其中的client_secret最好用bcrypt密文的方式进行存储,比如我下面的client_secret,明文是123456。可以使用PasswordEncoder类的encode方法产生相应的密码。

1
2
private final PasswordEncoder passwordEncoder;
System.out.println(passwordEncoder.encode("123456"));
参考文章:
1.SQL Server CREATE TABLE
2.该如何设计你的 PasswordEncoder? (密码的生成规则,以及密码的生成历史,多种密码策略以及相应的从明文到密文的过度方法)

2.pom.xml配置

因为用到了sql server数据库,然后还使用了jpa,于是添加下面的依赖。

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<!--sql server-->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>8.1.0.jre8-preview</version>
</dependency>

3.application.yml配置

在spring配置默认的数据源。

1
2
3
4
5
6
7
8
9
10
spring:
datasource:
## default connection pool
hikari:
connection-timeout: 20000
maximum-pool-size: 5
username: xxx
password: xx
url: jdbc:sqlserver://xxx:5433;databasename=xxx
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver

4.编写oauth2配置

这里我贴出了全部的Oauth2ServerConfig配置代码,其中大部分的内容也都是(微服务权限终极解决方案,Spring Cloud Gateway + Oauth2 实现统一认证和鉴权! (这篇文章实现了oauth2的密码模式和客户端模式))这篇文章中的,我只是改掉了ClientDetailsServiceConfigurer从数据库中获取配置的内容。除此之外,文章中还有些Token增强的内容,即在返回的内容之外又新添了自己的内容。

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
@AllArgsConstructor
@Configuration
@EnableAuthorizationServer
public class Oauth2ServerConfig extends AuthorizationServerConfigurerAdapter {

private static final String RESOURCE_IDS = "order";

private final PasswordEncoder passwordEncoder;
private final UserServiceImpl userDetailsService;
private final AuthenticationManager authenticationManager;
private final JwtTokenEnhancer jwtTokenEnhancer;

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//这个地方指的是从jdbc查出数据来存储
clients.withClientDetails(clientDetails());
}

@Resource
private DataSource dataSource;

@Bean
public ClientDetailsService clientDetails() {
JdbcClientDetailsService jdbcClientDetailsService=new JdbcClientDetailsService(dataSource);
jdbcClientDetailsService.setPasswordEncoder();
return jdbcClientDetailsService;
}

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
List<TokenEnhancer> delegates = new ArrayList<>();
delegates.add(jwtTokenEnhancer);
delegates.add(accessTokenConverter());
enhancerChain.setTokenEnhancers(delegates); //配置JWT的内容增强器
endpoints.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService) //配置加载用户信息的服务
.accessTokenConverter(accessTokenConverter())
.tokenEnhancer(enhancerChain);
}

@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients();
}

@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
jwtAccessTokenConverter.setKeyPair(keyPair());
return jwtAccessTokenConverter;
}

@Bean
public KeyPair keyPair() {
//从classpath下的证书中获取秘钥对
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("jwt.jks"), "123456".toCharArray());
return keyStoreKeyFactory.getKeyPair("jwt", "123456".toCharArray());
}

}

还有一点要说明的,就是生成密钥对的工具,在自己的java安装目录下的bin文件夹中。

使用下面的命令行即可生成。

1
keytool -genkey -alias jwt -keyalg RSA -keystore jwt.jks
参考文章:
1.从头开始spring security oauth 2.0 (二)keytool (这篇文章中,还有一步”从生成的JKS中导出公钥”,我觉得没有必要,因为我用的示例代码只需要生成密钥然后拷贝到resource文件夹就好了)
2.pring Cloud OAuth2.0 微服务中配置 Jwt Token 签名/验证
3.windows下使用keytool生成ssl自生成证书并在tomcat7中配置 (如何在windows上生成密钥)
4.Spring Security 实战干货:用户信息UserDetails相关入门 (放在这里没有什么用,就是看到了相关的信息,主要讲UserDetails的内容)
5.Spring Security入门(三):密码加密 (内容其实也不是很多,但是还是讲了Security默认的BCryptPasswordEncoder加密方式)
6.Spring Boot+OAuth2,如何自定义返回的 Token 信息?
7.想让 OAuth2 和 JWT 在一起愉快玩耍?请看松哥的表演
小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。