遵循可以在here中找到的教程,以替换现有的oauth配置,该配置为jwt令牌返回“访问令牌”。当我运行该应用程序并查询服务器以进行身份验证时,它似乎正在返回“ access_token”而不是JWT令牌。本教程使用的是Spring Boot,我们的应用程序是非Boot的普通Spring MVC,因此不确定是否涉及任何其他步骤吗?
服务器响应:{"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJ3aWxsbGFkaXNsYXciLCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6IjQ2OGI3MzFmLTUxMzgtNDZhYi04MTU3LTU1MmZlMjM1MzY2ZSIsImNsaWVudF9pZCI6ImNsaWVudGFwcCIsInNjb3BlIjpbInJlYWRfd3JpdGUiXSwib3JnYW5pemF0aW9uIjoid2lsbGxhZGlzbGF3QmdNSiJ9.fUhFeUDuhm8f2V7CuURsZWKoAKjNZixk5rUa0Jyzov8","refreshToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbsUiOiJ3aWxsbGFkaXNsYXciLCJzY29wZSI6WyJyZWFkX3dyaXRlIl0sIm9yZ2FuaXphdGlvbiI6IndpbGxsYWRpc2xhd0JnTUoiLCJhdGkiOiI0NjhiNzMxZi01MTM4LTQ2YWItODE1Ny01NTJmZTIzNTM2NmUiLCJleHAiOjE1ODM4NDA5NTgsImF1dGhvcml0aWVzIjpbIlJPTEVfQURNSU4iXSwianRpIjoiOGIxNGE3NjMtZmMwMy00MDQ4LWJkNGQtYjZiMTUyOGU2NTE4IiwiY2xpZW50X2lkIjoiY2xpZW50YXBwIn0.UhkxVsgM4CnZeRRKGyyCbiyqb2M0BmL56sHbsxt5Opk","idToken":null,"tokenEndpoint":"http://localhost:8080/oauth/token","scopes":["read_write"],"expiration":null}
// OAuth服务器
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter {
final String clientId;
final String clientSecret;
final String redirectUri;
final String grantType;
final String scope;
....
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
PasswordEncoder passwordEncoder;
@Autowired
DataSource dataSource;
@Autowired
RepositoryUserDetailsService userDetailsService;
@Autowired
private CustomAccessTokenConverter customAccessTokenConverter;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(
Arrays.asList(tokenEnhancer(), accessTokenConverter()));
endpoints.tokenStore(tokenStore())
.tokenEnhancer(tokenEnhancerChain)
.authenticationManager(authenticationManager);
}
@Bean
public TokenEnhancer tokenEnhancer() {
return new CustomTokenEnhancer();
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.passwordEncoder(passwordEncoder);
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("123");
return converter;
}
@Bean
@Primary
public ResourceServerTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
@Bean
protected AuthorizationCodeServices authorizationCodeServices() {
return new JdbcAuthorizationCodeServices(dataSource);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients)
throws Exception {
clients.
jdbc(dataSource)
.withClient(clientId)
.secret(passwordEncoder.encode(clientSecret))
.autoApprove(true)
.redirectUris(redirectUri)
.authorizedGrantTypes("password", "refresh_token")
.accessTokenValiditySeconds(0)
.scopes(scope);
}
}
//资源服务器
@Configuration
@EnableResourceServer
public class OAuth2ResourceServer extends ResourceServerConfigurerAdapter {
@Autowired
private CustomAccessTokenConverter customAccessTokenConverter;
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/register/**").permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin().loginPage("/signin/**")
.and()
.requestMatchers()
.antMatchers("/api/**");
}
@Override
public void configure(ResourceServerSecurityConfigurer config) {
config.tokenServices(tokenServices());
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setAccessTokenConverter(customAccessTokenConverter);
converter.setSigningKey("123");
return converter;
}
@Bean
@Primary
public ResourceServerTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
return defaultTokenServices;
}
}
// CustomTokenEnhancer类
public class CustomTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(
OAuth2AccessToken accessToken,
OAuth2Authentication authentication) {
Map<String, Object> additionalInfo = new HashMap<>();
additionalInfo.put(
"organization", authentication.getName() + randomAlphabetic(4));
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(
additionalInfo);
return accessToken;
}
}
// CustomAccessTokenConverter类
@Component
public class CustomAccessTokenConverter extends DefaultAccessTokenConverter {
@Override
public OAuth2Authentication extractAuthentication(Map<String, ?> claims) {
OAuth2Authentication authentication =
super.extractAuthentication(claims);
authentication.setDetails(claims);
return authentication;
}
}
您的Spring Security OAuth2配置可以正常工作,并且已经返回了JWT令牌。
以下是它返回的有效负载
eyJ1c2VyX25hbWUiOiJ3aWxsbGFkaXNsYXciLCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6IjQ2OGI3MzFmLTUxMzgtNDZhYi04MTU3LTU1MmZlMjM1MzY2ZSIsImNsaWVudF9pZCI6ImNsaWVudGFwcCIsInNjb3BlIjpbInJlYWRfd3JpdGUiXSwib3JnYW5pemF0aW9uIjoid2lsbGxhZGlzbGF3QmdNSiJ9
这是用base64解码后的样子
{"user_name":"willladislaw","authorities":["ROLE_ADMIN"],"jti":"468b731f-5138-46ab-8157-552fe235366e","client_id":"clientapp","scope":["read_write"],"organization":"willladislawBgMJ"}
您现在可以在标头值Authorization: Bearer <JWT Token>
中使用以下JWT令牌并访问任何受保护的资源。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJ3aWxsbGFkaXNsYXciLCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6IjQ2OGI3MzFmLTUxMzgtNDZhYi04MTU3LTU1MmZlMjM1MzY2ZSIsImNsaWVudF9pZCI6ImNsaWVudGFwcCIsInNjb3BlIjpbInJlYWRfd3JpdGUiXSwib3JnYW5pemF0aW9uIjoid2lsbGxhZGlzbGF3QmdNSiJ9.fUhFeUDuhm8f2V7CuURsZWKoAKjNZixk5rUa0Jyzov8
您已完成,您已要求Spring Security OAuth2生成一个JWT令牌,其中包含有关已登录用户的自包含信息,并将其替换为默认使用的基于标准UUID的accessToken
。仅仅因为您在使用JWT令牌并不意味着您将在登录时从oauth/token
端点获得jwtToken返回。进一步了解JWT。