New in Spring Security OAuth2 – Verify Claims – Spring Security OAuth2 &#8211中的新内容;验证要求

最后修改: 2017年 9月 8日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this quick tutorial, we’ll work with a Spring Security OAuth2 implementation and we’ll learn how to verify JWT claims using the new JwtClaimsSetVerifier – introduced in Spring Security OAuth 2.2.0.RELEASE.

在本快速教程中,我们将使用 Spring Security OAuth2 实现,并学习如何使用新的 JwtClaimsSetVerifier 验证 JWT 声明 – 在 Spring Security OAuth 2.2.0.RELEASE 中介绍。

2. Maven Configuration

2.Maven配置

First, we need to add the latest version of spring-security-oauth2 into our pom.xml:

首先,我们需要将最新版本的spring-security-oauth2加入我们的pom.xml

<dependency>
    <groupId>org.springframework.security.oauth</groupId>
    <artifactId>spring-security-oauth2</artifactId>
    <version>2.2.0.RELEASE</version>
</dependency>

3. Token Store Configuration

3.令牌库配置

Next, let’s configure our TokenStore in the Resource Server:

接下来,让我们在资源服务器中配置我们的TokenStore

@Bean
public TokenStore tokenStore() {
    return new JwtTokenStore(accessTokenConverter());
}

@Bean
public JwtAccessTokenConverter accessTokenConverter() {
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    converter.setSigningKey("123");
    converter.setJwtClaimsSetVerifier(jwtClaimsSetVerifier());
    return converter;
}

Note how we’re adding the new verifier to our JwtAccessTokenConverter.

注意我们如何将新的验证器添加到我们的JwtAccessTokenConverter

For more details on how to configure JwtTokenStore, check out the writeup about using JWT with Spring Security OAuth.

有关如何配置JwtTokenStore的详细信息,请查看有关使用JWT与Spring Security OAuth的文章。

Now, in the following sections, we’ll discuss different types of claim verifier and how to make them work together.

现在,在下面的章节中,我们将讨论不同类型的索赔核查器以及如何使它们一起工作。

4. IssuerClaimVerifier

4、IssuerClaimVerifier

We’ll start simple – by verifying the Issuer “iss” claim using IssuerClaimVerifier – as follows:

我们将从简单的开始–通过使用IssuerClaimVerifier验证发行人”iss“索赔–如下。

@Bean
public JwtClaimsSetVerifier issuerClaimVerifier() {
    try {
        return new IssuerClaimVerifier(new URL("http://localhost:8081"));
    } catch (MalformedURLException e) {
        throw new RuntimeException(e);
    }
}

In this example, we added a simple IssuerClaimVerifier to verify our issuer. If the JWT token contains a different value for issuer “iss” claim, a simple InvalidTokenException will be thrown.

在这个例子中,我们添加了一个简单的IssuerClaimVerifier来验证我们的发行者。如果JWT令牌包含一个不同的发行人 “iss “声明的值,一个简单的InvalidTokenException将被抛出。

Naturally, if the token does contain the issuer “iss” claim, no exception will be thrown and the token is considered valid.

当然,如果令牌确实包含发行人 “iss “的要求,则不会抛出异常,令牌被视为有效。

5. Custom Claim Verifier

5.自定义索赔验证器

But, what’s interesting here is that we can also build our custom claim verifier:

但是,这里有趣的是,我们也可以建立我们自定义的索赔验证器。

@Bean
public JwtClaimsSetVerifier customJwtClaimVerifier() {
    return new CustomClaimVerifier();
}

Here’s a simple implementation of what this can look like – to check if the user_name claim exists in our JWT token:

下面是一个简单的实现–检查user_name claim是否存在于我们的JWT token中。

public class CustomClaimVerifier implements JwtClaimsSetVerifier {
    @Override
    public void verify(Map<String, Object> claims) throws InvalidTokenException {
        String username = (String) claims.get("user_name");
        if ((username == null) || (username.length() == 0)) {
            throw new InvalidTokenException("user_name claim is empty");
        }
    }
}

Notice how we’re simply implementing the JwtClaimsSetVerifier interface here, and then provide a completely custom implementation for the verify method – which gives us full flexibility for any kind of check we need.

请注意,我们在这里简单地实现了JwtClaimsSetVerifier接口,然后为验证方法提供了一个完全自定义的实现–这为我们需要的任何类型的检查提供了充分的灵活性。

6. Combine Multiple Claim Verifiers

6.合并多个索赔验证人

Finally, let’s see how to combine multiple claim verifier using DelegatingJwtClaimsSetVerifier – as follows:

最后,让我们看看如何使用DelegatingJwtClaimsSetVerifier组合多个索赔验证器–如下所示。

@Bean
public JwtClaimsSetVerifier jwtClaimsSetVerifier() {
    return new DelegatingJwtClaimsSetVerifier(Arrays.asList(
      issuerClaimVerifier(), customJwtClaimVerifier()));
}

DelegatingJwtClaimsSetVerifier takes a list of JwtClaimsSetVerifier objects and delegates the claim verification process to these verifiers.

DelegatingJwtClaimsSetVerifier接收一个JwtClaimsSetVerifier对象列表,并将索赔验证过程委托给这些验证器。

7. Simple Integration Test

7.简单的集成测试

Now that we’re done with the implementation, let’s test our claims verifiers with a simple integration test:

现在我们已经完成了实现,让我们用一个简单的集成测试来测试我们的索赔核查器。

@RunWith(SpringRunner.class)
@SpringBootTest(
  classes = ResourceServerApplication.class, 
  webEnvironment = WebEnvironment.RANDOM_PORT)
public class JwtClaimsVerifierIntegrationTest {

    @Autowired
    private JwtTokenStore tokenStore;

    ...
}

We’ll start with a token that doesn’t contain an issuer (but contains a user_name) – which should be valid:

我们将从一个不包含发行人的令牌开始(但包含一个user_name)–它应该是有效的。

@Test
public void whenTokenDontContainIssuer_thenSuccess() {
    String tokenValue = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9....";
    OAuth2Authentication auth = tokenStore.readAuthentication(tokenValue);
    
    assertTrue(auth.isAuthenticated());
}

The reason this is valid is simple – the first verifier is only active if an issuer claim exists in the token. If that claim doesn’t exist – the verifier doesn’t kick in.

这样做的原因很简单–只有当代币中存在发行人主张时,第一个验证器才会发挥作用。如果该声明不存在–验证器就不会启动。

Next, let’s have a look at a token which contains a valid issuer (http://localhost:8081) and a user_name as well. This should also be valid:

接下来,让我们看看一个包含有效发行者(http://localhost:8081)和用户名的令牌。这也应该是有效的。

@Test
public void whenTokenContainValidIssuer_thenSuccess() {
    String tokenValue = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9....";
    OAuth2Authentication auth = tokenStore.readAuthentication(tokenValue);
    
    assertTrue(auth.isAuthenticated());
}

When the token contains an invalid issuer (http://localhost:8082) – then it’s going to be verified and determined to be invalid:

当令牌包含一个无效的发行者(http://localhost:8082)–那么它将被验证并确定为无效的。

@Test(expected = InvalidTokenException.class)
public void whenTokenContainInvalidIssuer_thenException() {
    String tokenValue = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9....";
    OAuth2Authentication auth = tokenStore.readAuthentication(tokenValue);
    
    assertTrue(auth.isAuthenticated());
}

Next, when the token doesn’t contain an user_name claim, then it’s going to be invalid:

接下来,当令牌不包含user_name要求时,那么它将是无效的。

@Test(expected = InvalidTokenException.class)
public void whenTokenDontContainUsername_thenException() {
    String tokenValue = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9....";
    OAuth2Authentication auth = tokenStore.readAuthentication(tokenValue);
    
    assertTrue(auth.isAuthenticated());
}

And finally, when the token contains an empty user_name claim, then it’s also invalid:

最后,当令牌包含一个空的user_name要求,那么它也是无效的。

@Test(expected = InvalidTokenException.class)
public void whenTokenContainEmptyUsername_thenException() {
    String tokenValue = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9....";
    OAuth2Authentication auth = tokenStore.readAuthentication(tokenValue);
    
    assertTrue(auth.isAuthenticated());
}

8. Conclusion

8.结论

In this quick article, we had a look at the new verifier functionality in the Spring Security OAuth.

在这篇快速文章中,我们看了一下Spring Security OAuth的新验证器功能。

As always, the full source code is available over on GitHub.

一如既往,完整的源代码可在GitHub上获得