Spring Security выполнит проверку токена на основе конфигураций на сервере авторизации.
Для автономной проверки код будет выглядеть следующим образом:
RsaVerifier verifier = new RsaVerifier(RSAPublicKey);
Jwt tokenDecoded = JwtHelper.decodeAndVerify(token, verifier);
Map<String, Object> claimsMap = (Map<String, Object>) new
ObjectMapper().readValue(tokenDecoded.getClaims(), Map.class);
//Verify the claims then
// 1 Verify if the token has not already expired
// 2 Verify the issuance date ( should be before this date )
// 3 Verify if the issuer of this token is contained in verified authorities.
// 4 Verify if the token was issued for this client
// 5 Verify if the token contained any expected claims...
Но вышеописанное реализованоSpring Security для процесса аутентификации Oauth2, клиентское приложение просто должно предоставить конфигурации.
Триггер OAuth2AuthenticationProcessingFilter в цепочке фильтров безопасности Spring.Этот фильтр добавляется, когда ресурсы защищены защитой Oauth2.
В вашем приложении конфигурация сервера авторизации будет выглядеть так (только соответствующие ориентировочные выдержки конфигурации приведены ниже)
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
...
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
RSAPemKeyPairLoader keyPairLoader = new RSAPemKeyPairLoader();
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(...);
converter.setVerifierKey(...);
return converter;
}
@Bean
@Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(...);
defaultTokenServices.setAccessTokenValiditySeconds(...);
defaultTokenServices.setRefreshTokenValiditySeconds(...);
return defaultTokenServices;
}
}
В вашем приложенииконфигурация сервера ресурсов будет выглядеть следующим образом:
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
...
}
}
Для отслеживания в реализации Spring, где запрашиваемый токен перехватывается и проверяется, посмотрите на реализацию Spring OAUTH2 - подробности потока ниже, где объект Authentication, экземпляр OAuth2Authentication будетпопытаться создать его для успешных запросов.
Все приведенные ниже извлечения кода взяты из реализаций spring-security-oauth2-2.0.8.RELEASE.
public class OAuth2AuthenticationManager implements AuthenticationManager {
....
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (authentication == null) {
throw new InvalidTokenException("Invalid token (token not found)");
}
String token = (String) authentication.getPrincipal();
OAuth2Authentication auth = tokenServices.loadAuthentication(token);
...
}
}
loadAuthentication будет в основном проверять токен доступа и пытаться преобразовать его в OAuth2Authentication
public class DefaultTokenServices implements AuthorizationServerTokenServices ...{
public OAuth2Authentication loadAuthentication(String accessTokenValue) throws AuthenticationException, InvalidTokenException {
OAuth2AccessToken accessToken = tokenStore.readAccessToken(accessTokenValue);
...
}
}
JwtTokenStore создаст OAuth2AccessToken и в процессе декодирования и проверки токена String.
public class JwtTokenStore implements TokenStore {
public OAuth2AccessToken readAccessToken(String tokenValue) {
OAuth2AccessToken accessToken = convertAccessToken(tokenValue);
if (jwtTokenEnhancer.isRefreshToken(accessToken)) {
throw new InvalidTokenException("Encoded token is a refresh token");
}
return accessToken;
}
private OAuth2AccessToken convertAccessToken(String tokenValue) {
return jwtTokenEnhancer.extractAccessToken(tokenValue, jwtTokenEnhancer.decode(tokenValue));
}
}
JWTAccessTokenConverter выполняет декодирование и извлечение заявок на токены.
public class JwtAccessTokenConverter implements AccessTokenConverter {
protected Map<String, Object> decode(String token) {
try {
Jwt jwt = JwtHelper.decodeAndVerify(token, verifier);
String content = jwt.getClaims();
Map<String, Object> map = objectMapper.parseMap(content);
if (map.containsKey(EXP) && map.get(EXP) instanceof Integer) {
Integer intValue = (Integer) map.get(EXP);
map.put(EXP, new Long(intValue));
}
return map;
}
catch (Exception e) {
throw new InvalidTokenException("Cannot convert access token to JSON", e);
}
}
JwtHelper выполнит декодирование и запросит подтверждение.
public static Jwt decodeAndVerify(String token, SignatureVerifier verifier) {
Jwt jwt = decode(token);
jwt.verifySignature(verifier);
return jwt;
}
JwttImpl вызывает верификатор.
public void verifySignature(SignatureVerifier verifier) {
verifier.verify(signingInput(), crypto);
}
Например, верификатор RSA Signature наконец выполнит проверку:
public class RsaVerifier implements SignatureVerifier {
public void verify(byte[] content, byte[] sig) {
try {
Signature signature = Signature.getInstance(algorithm);
signature.initVerify(key);
signature.update(content);
if (!signature.verify(sig)) {
throw new InvalidSignatureException("RSA Signature did not match content");
}
}
catch (GeneralSecurityException e) {
throw new RuntimeException(e);
}
}
}