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 中的新驗證器功能進行了簡要了解。