OAuth2.0 - 使用JWT替换Token 及 JWT内容增强
Posted 小毕超
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OAuth2.0 - 使用JWT替换Token 及 JWT内容增强相关的知识,希望对你有一定的参考价值。
一、OAuth2.0
上篇文章我们讲解了OAuth2.0的几种认证模式,前面的讲解Token采用OAuth2.0自带的方式生成的Token,但是这种方式也存在这弊端,通过前面的测试我们发现,当资源服务和授权服务不在一起时资源服务使用RemoteTokenServices 远程请求授权服务验证token,如果访问量较大将会影响系统的性能 。
因此我们可以采用JWT生成令牌,用户认证通过会得到一个JWT令牌,JWT令牌中已经包括了用户相关的信息,客户端只需要携带JWT访问资源服务,资源服务根据事先约定的算法自行完成令牌校验,无需每次都请求认证服务完成授权。
下面是上篇文章的地址:
二、OAuth2.0整合JWT
本篇文章接着上篇文章的内容继续修改。
认证服务修改
先声明JWT的签名模式,这里采用对称加密的方式,密钥设为bxc123
,这个在资源服务器也是这么修改:
@Configuration
public class TokenConfig
private String SIGNING_KEY = "bxc123";
@Bean
public TokenStore tokenStore()
return new JwtTokenStore(accessTokenConverter());
@Bean
public JwtAccessTokenConverter accessTokenConverter()
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(SIGNING_KEY); //对称秘钥,资源服务器使用该秘钥来验证
return converter;
下面还要修改AuthorizationServer
配制类,主要AuthorizationServerTokenServices
的配制,增加一个TokenEnhancerChain
,将上面声明出的JwtAccessTokenConverter
配制进去。
@Configuration
@EnableAuthorizationServer
public class AuthorizationServer extends AuthorizationServerConfigurerAdapter
@Autowired
private TokenStore tokenStore;
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private AuthorizationCodeServices authorizationCodeServices;
@Autowired
private JwtAccessTokenConverter accessTokenConverter;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception
clients.inMemory()// 使用in‐memory存储
.withClient("c1")// client_id
.secret(new BCryptPasswordEncoder().encode("secret"))
.resourceIds("res1")
.authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token")// 该client允许的授权类型 authorization_code,password,refresh_token,implicit,client_credentials
.scopes("all")// 允许的授权范围
.autoApprove(false) //加上验证回调地址
.authorities("admin")
.redirectUris("http://www.baidu.com");
//设置授权码模式的授权码如何存取,暂时采用内存方式
@Bean
public AuthorizationCodeServices authorizationCodeServices()
return new InMemoryAuthorizationCodeServices();
@Bean
public AuthorizationServerTokenServices tokenService()
DefaultTokenServices service = new DefaultTokenServices();
service.setClientDetailsService(clientDetailsService);
service.setSupportRefreshToken(true);
service.setTokenStore(tokenStore);
//令牌增强
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
List<TokenEnhancer> tokenEnhancers = new ArrayList<>();
tokenEnhancers.add(accessTokenConverter);
tokenEnhancerChain.setTokenEnhancers(tokenEnhancers);
service.setTokenEnhancer(tokenEnhancerChain);
service.setAccessTokenValiditySeconds(7200); // 令牌默认有效期2小时
service.setRefreshTokenValiditySeconds(259200); // 刷新令牌默认有效期3天
return service;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
endpoints
.authenticationManager(authenticationManager)//认证管理器
.authorizationCodeServices(authorizationCodeServices)//授权码服务
.tokenServices(tokenService())//令牌管理服务
.allowedTokenEndpointRequestMethods(HttpMethod.POST);
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception
security
.tokenKeyAccess("permitAll()") //oauth/token_key是公开
.checkTokenAccess("permitAll()") //oauth/check_token公开
.allowFormAuthenticationForClients(); //表单认证(申请令牌)
重启auth认证服务。
资源服务修改
将上面写的TokenConfig
类,覆盖到资源服务中,并修改ResouceServerConfig
配制类,将前面写的远程访问认证服务校验令牌的逻辑,就可以去除掉了:
@Configuration
@EnableResourceServer
public class ResouceServerConfig extends ResourceServerConfigurerAdapter
public static final String RESOURCE_ID = "res1";
@Autowired
TokenStore tokenStore;
@Override
public void configure(ResourceServerSecurityConfigurer resources)
resources.resourceId(RESOURCE_ID)//资源 id
.tokenStore(tokenStore)
.stateless(true);
@Override
public void configure(HttpSecurity http) throws Exception
http
.authorizeRequests()
.antMatchers("/admin/**").hasAuthority("admin")
.antMatchers("/common/**").hasAuthority("common")
.and().csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
重启资源服务。
三、测试
使用密码模式登录系统获取token
,可以看到获取的token已经是Jwt格式的了:
可以在一些Jwt在线解析的网站,解析下JWT:
下面使用token
去访问资源服务接口:
四、JWT内容增强
上面可以看到JWT中默认放置了一些用户的信息,如果我们想要存放其他东西呢,只需使用DefaultOAuth2AccessToken
的setAdditionalInformation
方法,传递一个Map即可放置自定义的数据,其中可以获取用户的信息,也可以再查找其他自定义的信息放置,下面修改认证服务的AuthorizationServer
配制类:
添加TokenEnhancer tokenEnhancer()
方法:
/**
* JWT内容增强
*/
@Bean
public TokenEnhancer tokenEnhancer()
return (accessToken, authentication) ->
Map<String, Object> additionalInfo = new HashMap<>();
User principal = (User)authentication.getUserAuthentication().getPrincipal();
String username = principal.getUsername();
additionalInfo.put("three","额外的内容!");
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
return accessToken;
;
在构建TokenEnhancerChain
对象时,将上面配制的设置进去:
@Bean
public AuthorizationServerTokenServices tokenService()
DefaultTokenServices service = new DefaultTokenServices();
service.setClientDetailsService(clientDetailsService);
service.setSupportRefreshToken(true);
service.setTokenStore(tokenStore);
//令牌增强
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
List<TokenEnhancer> tokenEnhancers = new ArrayList<>();
//内容增强
tokenEnhancers.add(tokenEnhancer());
tokenEnhancers.add(accessTokenConverter);
tokenEnhancerChain.setTokenEnhancers(tokenEnhancers);
service.setTokenEnhancer(tokenEnhancerChain);
service.setAccessTokenValiditySeconds(7200); // 令牌默认有效期2小时
service.setRefreshTokenValiditySeconds(259200); // 刷新令牌默认有效期3天
return service;
重启认证服务,再次登录,就可以看到增加的信息已经有了:
如果解析JWT,也可以看到内容:
喜欢的小伙伴可以关注我的个人微信公众号,获取更多学习资料!
以上是关于OAuth2.0 - 使用JWT替换Token 及 JWT内容增强的主要内容,如果未能解决你的问题,请参考以下文章
OAuth 2.0 范围参数与 OAuth 2.0 JWT access_token 范围声明