OAuth2 和 SpringSecurity完成授权认证中心(二) 通过jwt令牌,以及JDBC存储
前面写了如何配置OAuth2 和 SpringSeurity 授权中心,但是使用的内存存储的,以及使用的默认InMemoryTokenStore 普通令牌,这次我们修改为Jwt令牌,并且使用JDBC存储客户端信息。
前一篇文章
OAuth2 和 SpringSecurity完成授权认证中心(一)搭建授权认证
初始化SQL
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for oauth_client_details
-- ----------------------------
DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (
`client_id` varchar(255) NOT NULL,
`resource_ids` varchar(255) DEFAULT NULL,
`client_secret` varchar(255) DEFAULT NULL,
`scope` varchar(255) DEFAULT NULL,
`authorized_grant_types` varchar(255) DEFAULT NULL,
`web_server_redirect_uri` varchar(255) DEFAULT NULL,
`authorities` varchar(255) DEFAULT NULL,
`access_token_validity` int(11) DEFAULT NULL,
`refresh_token_validity` int(11) DEFAULT NULL,
`additional_information` longtext,
`create_time` datetime DEFAULT NULL,
`archived` tinyint(4) DEFAULT NULL,
`trusted` tinyint(4) DEFAULT NULL,
`autoapprove` varchar(255) DEFAULT NULL,
PRIMARY KEY (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of oauth_client_details
-- ----------------------------
INSERT INTO `oauth_client_details` VALUES ('c1', 'res1', '$2a$10$LNl3wbdkZX54Tj/9SlxHiOw.a8Iqg0jBplzJcCIbfJVSIPr8mAGvS', 'ROLE_ADMIN,ROLE_USER,ROLE_API', 'client_credentails,password,authorization_code,implicit,refresh_token', 'http://www.baidu.com', null, '7200', '259200', null, '2019-11-13 14:20:08', '0', '0', 'false');
INSERT INTO `oauth_client_details` VALUES ('c2', 'res2', '$2a$10$NlBC84MVb7F95EXYTXwLneXgCca6/GipyWR5NHm8K0203bSQMLpvm', 'ROLE_API', 'client_credentails,password,authorization_code,implicit,refresh_token', 'http://www.baidu.com', null, '31536000', '259200', null, '2019-11-13 14:21:11', '0', '0', 'false');
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for oauth_code
-- ----------------------------
DROP TABLE IF EXISTS `oauth_code`;
CREATE TABLE `oauth_code` (
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`code` varchar(255) DEFAULT NULL,
`authentication` blob,
KEY `code_index` (`code`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
修改TokenConfig,改变令牌策略
@Configuration
public class TokenConfig {
private static final String SIGNING_KEY = "uaa123";
// 令牌存储策略
@Bean
public TokenStore tokenStore()
{
// Jwt令牌存储方案
return new JwtTokenStore(assessTokenConverter());
}
@Bean
public JwtAccessTokenConverter assessTokenConverter()
{
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(SIGNING_KEY);//
return converter;
}
}
修改AuthorizationServer.java 类
添加JwtAccessTokenConverter
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
修改令牌管理服务方法
// 令牌管理服务
public AuthorizationServerTokenServices tokenServices()
{
DefaultTokenServices service = new DefaultTokenServices();
service.setClientDetailsService(clientDetailsService); // 客户端信息服务
service.setSupportRefreshToken(true); // 是否产生刷新令牌
service.setTokenStore(tokenStore); // 设置令牌存储策略
// 令牌增强
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter));
service.setTokenEnhancer(tokenEnhancerChain);
service.setAccessTokenValiditySeconds(7200);// 令牌默认有效期 2 小时
service.setRefreshTokenValiditySeconds(259200);
return service;
}
配置 客户端Jdbc详细信息
private AuthorizationCodeServices authorizationCodeServices;
@Bean
public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource)
{
return new JdbcAuthorizationCodeServices(dataSource);
}
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
private PasswordEncoder passwordEncoder;
@Bean
public ClientDetailsService clientDetailsService(DataSource dataSource)
{
JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
clientDetailsService.setPasswordEncoder(passwordEncoder);
return clientDetailsService;
}
配置修改客户端详细信息方法
// 配置客户端详细信息
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetailsService);
}
最终AuthorizationServer 类
@Configuration
@EnableAuthorizationServer
public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
@Autowired
private AuthorizationCodeServices authorizationCodeServices;
@Bean
public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource)
{
return new JdbcAuthorizationCodeServices(dataSource);
}
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
private PasswordEncoder passwordEncoder;
@Bean
public ClientDetailsService clientDetailsService(DataSource dataSource)
{
JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
clientDetailsService.setPasswordEncoder(passwordEncoder);
return clientDetailsService;
}
// 配置客户端详细信息
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetailsService);
}
// 令牌管理服务
public AuthorizationServerTokenServices tokenServices()
{
DefaultTokenServices service = new DefaultTokenServices();
service.setClientDetailsService(clientDetailsService); // 客户端信息服务
service.setSupportRefreshToken(true); // 是否产生刷新令牌
service.setTokenStore(tokenStore); // 设置令牌存储策略
// 令牌增强
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter));
service.setTokenEnhancer(tokenEnhancerChain);
service.setAccessTokenValiditySeconds(7200);// 令牌默认有效期 2 小时
service.setRefreshTokenValiditySeconds(259200);
return service;
}
/**
* 令怕i访问端点
* @param endpoints
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
// 密码管理模式
.authenticationManager(authenticationManager)
// 授权码模式
.authorizationCodeServices(authorizationCodeServices)
.tokenServices(tokenServices()) // 令牌管理服务
.allowedTokenEndpointRequestMethods(HttpMethod.POST); // 允许post提交
}
/**
* 令牌访问端点的安全策略
* @param security
* @throws Exception
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()") // /oauth/token_key 公开
.checkTokenAccess("permitAll()") // /auth/check_token 检测令牌
.allowFormAuthenticationForClients(); // 允许通过表单认证,申请令牌
}
}
修改order 服务
TokenConfig.java
@Configuration
public class TokenConfig{
private static final String SIGNING_KEY = "uaa123";
// 令牌存储策略
@Bean
public TokenStore tokenStore()
{
// Jwt令牌存储方案
return new JwtTokenStore(assessTokenConverter());
}
@Bean
public JwtAccessTokenConverter assessTokenConverter()
{
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(SIGNING_KEY);//
return converter;
}
}
修改ResourceServerConfig.java
文件
将all
修改为数据库中scope字段中一个 ROLE_ADMIN
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**").access("#oauth2.hasScope('ROLE_ADMIN')")
.and().csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
super.configure(http);
}
因为要使用本地 检查token 所以 将 tokenServices 注释掉
最终配置类ResourceServerConfig
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
public static final String RESOURCE_ID = "res1";
@Autowired
private TokenStore tokenStore;
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/**").access("#oauth2.hasScope('ROLE_ADMIN')")
.and().csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
super.configure(http);
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(RESOURCE_ID) // 资源id
.tokenStore(tokenStore)
.stateless(true);
}
}
依次启动 UaaJwtServer
和 OrderJwtServer
使用postman 进行测试
通过浏览器 地址栏获取 code 的值
点击Authorize 获取 code. 查看数据库
回调的百度链接后带的code
获取token。
携带token 去访问有的 资源
一、简化模式
/uaa/oauth/authorize?client_id=c1&response_type=token&scope=all&redirect_uri=http://www.baidu.com
参数描述和授权码模式,注意reponse_type=token, 说明是 简化模式
二、密码模式
POST
/uaa//oauth/token?client_id=c1&client_secret=secret&grant_type=password&username=zhangsan&password=123
- 资源拥有者将用户名 密码发给客户端
- 客户端拿着资源拥有者的用户名,密码向服务器请求令牌
- 授权服务器将令牌发送给client
参数列表:
- client_id : 客户端标识
- client_secret: 客户端**
- grant_tyoe: 授权类型 填写password 表示 密码模式
- username: 用户名
- password: 密码
三、客户端模式
POST
/uaa/oath/token?grant_type=client_credentials&client_id=c1&client_secret=secret
- 客户端向授权服务器发送自己的身份呢信息,并请求令牌
- 确认客户端身份无误,将颁发令牌给客户端
参数列表
- client_id:客户端标识
- client_secret: 客户端**
- grant_type: 授权类型, client_credentials 表示客户端模式