Spring Security OAuth2 新功能 – 驗證聲明

Spring Security
Remote
0
11:52 PM · Nov 29 ,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. Token 存儲配置接下來,讓我們配置 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 來驗證我們的發行人。如果 JWT 令牌包含發行人“iss”聲明的不同值,則會拋出簡單的 InvalidTokenException

當然,如果令牌確實包含發行人“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 聲明為空");
        }
    }
}

請注意,我們只是實現了 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.