Novo no Spring Security OAuth2 - Verificar reivindicações
1. Visão geral
Neste tutorial rápido, trabalharemos com uma implementação Spring Security OAuth2 e aprenderemos como verificar as declarações JWT usando o novoJwtClaimsSetVerifier - introduzido emSpring Security OAuth 2.2.0.RELEASE.
2. Configuração do Maven
Primeiro, precisamos adicionar a versão mais recente despring-security-oauth2 em nossopom.xml:
org.springframework.security.oauth
spring-security-oauth2
2.2.0.RELEASE
3. Configuração de Token Store
A seguir, vamos configurar nossoTokenStore no servidor de recursos:
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("123");
converter.setJwtClaimsSetVerifier(jwtClaimsSetVerifier());
return converter;
}
Observe como estamos adicionando o novo verificador ao nossoJwtAccessTokenConverter.
Para obter mais detalhes sobre como configurarJwtTokenStore, verifique o artigo sobreusing JWT with Spring Security OAuth.
Agora, nas seções a seguir, discutiremos diferentes tipos de verificador de declaração e como fazê-los trabalhar juntos.
4. IssuerClaimVerifier
Começaremos de maneira simples - verificando a declaração do emissor “iss” usandoIssuerClaimVerifier - da seguinte forma:
@Bean
public JwtClaimsSetVerifier issuerClaimVerifier() {
try {
return new IssuerClaimVerifier(new URL("http://localhost:8081"));
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
Neste exemplo, adicionamos umIssuerClaimVerifier simples para verificar nosso emissor. Se o token JWT contiver um valor diferente para a declaração do emissor “iss”, umInvalidTokenException simples será lançado.
Naturalmente, se o token contiver a reivindicação "iss" do emissor, nenhuma exceção será lançada e o token será considerado válido.
5. Verificador de reivindicação personalizado
Mas, o que é interessante aqui é que também podemos construir nosso verificador de declaração personalizado:
@Bean
public JwtClaimsSetVerifier customJwtClaimVerifier() {
return new CustomClaimVerifier();
}
Aqui está uma implementação simples de como isso pode ser - para verificar se a declaraçãouser_name existe em nosso token JWT:
public class CustomClaimVerifier implements JwtClaimsSetVerifier {
@Override
public void verify(Map claims) throws InvalidTokenException {
String username = (String) claims.get("user_name");
if ((username == null) || (username.length() == 0)) {
throw new InvalidTokenException("user_name claim is empty");
}
}
}
Observe como estamos simplesmente implementando a interfaceJwtClaimsSetVerifier aqui e, em seguida, fornecemos uma implementação totalmente personalizada para o método de verificação - o que nos dá total flexibilidade para qualquer tipo de verificação de que precisamos.
6. Combine Multiple Claim Verifiers
Finalmente, vamos ver como combinar o verificador de múltiplas declarações usandoDelegatingJwtClaimsSetVerifier - da seguinte maneira:
@Bean
public JwtClaimsSetVerifier jwtClaimsSetVerifier() {
return new DelegatingJwtClaimsSetVerifier(Arrays.asList(
issuerClaimVerifier(), customJwtClaimVerifier()));
}
DelegatingJwtClaimsSetVerifier pega uma lista de objetosJwtClaimsSetVerifier e delega o processo de verificação de sinistro a esses verificadores.
7. Teste de integração simples
Agora que concluímos a implementação, vamos testar nossos verificadores de declarações com um simplesintegration test:
@RunWith(SpringRunner.class)
@SpringBootTest(
classes = ResourceServerApplication.class,
webEnvironment = WebEnvironment.RANDOM_PORT)
public class JwtClaimsVerifierIntegrationTest {
@Autowired
private JwtTokenStore tokenStore;
...
}
Começaremos com um token que não contém um emissor (mas contém umuser_name) - que deve ser válido:
@Test
public void whenTokenDontContainIssuer_thenSuccess() {
String tokenValue = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9....";
OAuth2Authentication auth = tokenStore.readAuthentication(tokenValue);
assertTrue(auth.isAuthenticated());
}
A razão pela qual isso é válido é simples - o primeiro verificador estará ativo apenas se houver uma solicitação de emissor no token. Se essa reivindicação não existir - o verificador não entra em ação.
A seguir, vamos dar uma olhada em um token que contém um emissor válido (http://localhost:8081) e umuser_name também. Isso também deve ser válido:
@Test
public void whenTokenContainValidIssuer_thenSuccess() {
String tokenValue = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9....";
OAuth2Authentication auth = tokenStore.readAuthentication(tokenValue);
assertTrue(auth.isAuthenticated());
}
Quando o token contém um emissor inválido (http://localhost:8082) - então, ele será verificado e considerado inválido:
@Test(expected = InvalidTokenException.class)
public void whenTokenContainInvalidIssuer_thenException() {
String tokenValue = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9....";
OAuth2Authentication auth = tokenStore.readAuthentication(tokenValue);
assertTrue(auth.isAuthenticated());
}
A seguir, quando o token não contém uma declaraçãouser_name, ele será inválido:
@Test(expected = InvalidTokenException.class)
public void whenTokenDontContainUsername_thenException() {
String tokenValue = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9....";
OAuth2Authentication auth = tokenStore.readAuthentication(tokenValue);
assertTrue(auth.isAuthenticated());
}
E, finalmente, quando o token contém uma declaraçãouser_name vazia, então também é inválido:
@Test(expected = InvalidTokenException.class)
public void whenTokenContainEmptyUsername_thenException() {
String tokenValue = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9....";
OAuth2Authentication auth = tokenStore.readAuthentication(tokenValue);
assertTrue(auth.isAuthenticated());
}
8. Conclusão
Neste artigo rápido, vimos a nova funcionalidade do verificador no Spring Security OAuth.
Como sempre, o código-fonte completo está disponívelover on GitHub.