知識庫 / Spring / Spring Security RSS 訂閱

Spring Security OAuth2 新功能 – 驗證聲明

Spring Security
HongKong
15
02:23 PM · Dec 06 ,2025

1. 概述

本快速教程將介紹 Spring Security OAuth2 的實現,並學習如何使用新的 JwtClaimsSetVerifier 來驗證 JWT 聲明——該功能是在 Spring Security OAuth 2.2.0.RELEASE 中引入的。

2. Maven 配置

首先,我們需要將最新版本的 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. 令牌存儲配置

接下來,讓我們配置 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;
}

請注意我們如何將新的驗證器添加到 JwtAccessTokenConverter 中。

要了解如何配置 JwtTokenStore 的詳細信息,請查看有關使用 JWT 與 Spring Security OAuth 的編寫。

現在,在後續部分,我們將討論不同類型的聲明驗證器以及如何使它們協同工作。

4. 發行人聲明驗證器 (IssuerClaimVerifier)

我們將從簡單開始——通過使用 IssuerClaimVerifier 來驗證發行人聲明 "iss":

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

在本示例中,我們添加了一個簡單的 IssuerClaimVerifier 用於驗證我們的 issuer。如果 JWT 令牌包含 issuer “iss” 聲明的不同值,則會拋出一個簡單的 InvalidTokenException 異常。

自然地,如果令牌確實包含 issuer “iss” 聲明,則不會拋出任何異常,並且令牌被認為是有效的。

5. 自定義索賠驗證器

有趣的是,我們還可以構建自定義索賠驗證器:

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

以下是一個簡單的實現示例,用於檢查 user_name 聲明是否存在於我們的 JWT 令牌中:

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");
        }
    }
}

請注意,我們這裏只是實現了 JwtClaimsSetVerifier 接口,然後提供了一個完全自定義的 verify 方法的實現——這為我們提供了對任何需要的檢查類型進行完全靈活性的能力。

6. 組合多個聲明驗證器

最後,讓我們看看如何使用 DelegatingJwtClaimsSetVerifier 組合多個聲明驗證器,方法如下:

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

DelegatingJwtClaimsSetVerifier 接受一個 JwtClaimsSetVerifier 對象列表,並將身份聲明驗證過程委託給這些驗證器。

7. 簡單集成測試

現在我們完成了實現,讓我們使用一個簡單的集成測試來驗證我們的聲明驗證器:

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

    @Autowired
    private JwtTokenStore tokenStore;

    ...
}

我們先從一個不包含發行方的令牌開始(但包含一個user_name),這個令牌應該有效:

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

以下是翻譯後的內容:

之所以這行有效,是因為第一個驗證器僅在存在發行人聲明時才會激活。如果該聲明不存在,則驗證器不會啓動。

接下來,讓我們看一下包含有效發行人(http://localhost:8081)和user_name的令牌,這同樣應該有效。

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

當令牌包含無效的發行者(http://localhost:8082)時,它將被驗證並確定為無效:

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

接下來,如果令牌中不存在 user_name 聲明,則該令牌將被視為無效:

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

最後,如果令牌包含一個空的 user_name 聲明,則該令牌也將無效:

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

8. 結論

在本文中,我們簡要介紹了 Spring Security OAuth 中新引入的驗證器功能。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.