1. Обзор
В этом кратком руководстве мы будем работать с реализацией Spring Security OAuth2 и узнаем, как проверить утверждения JWT с помощью нового JwtClaimsSetVerifier – введенного в Spring Security OAuth 2.2.0.RELEASE .
2. Конфигурация Maven
Во-первых, нам нужно добавить последнюю версию spring-security-oauth2 в наш pom.xml :
org.springframework.security.oauth spring-security-oauth2 2.2.0.RELEASE
3. Конфигурация хранилища Токенов
Далее, давайте настроим наше Хранилище токенов на сервере ресурсов:
@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 , ознакомьтесь с записью об использовании GWT с Spring Security OAuth .
Теперь в следующих разделах мы обсудим различные типы верификаторов утверждений и то, как заставить их работать вместе.
4. Верификатор претензий Эмитента
Мы начнем с простого – с проверки утверждения эмитента ” iss ” с помощью IssuerClaimVerifier – следующим образом:
@Bean
public JwtClaimsSetVerifier issuerClaimVerifier() {
try {
return new IssuerClaimVerifier(new URL("http://localhost:8081"));
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}В этом примере мы добавили простой Верификатор утверждений эмитента для проверки вашего эмитента. Если токен 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 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()));
}Делегирование Jwtclaimssetverifier берет список объектов Jwt Claims Set Verifier и делегирует процесс проверки утверждений этим верификаторам.
7. Простой Интеграционный тест
Теперь, когда мы закончили с реализацией, давайте протестируем наши верификаторы утверждений с помощью простого интеграционного теста :
@RunWith(SpringRunner.class)
@SpringBootTest(
classes = ResourceServerApplication.class,
webEnvironment = WebEnvironment.RANDOM_PORT)
public class JwtClaimsVerifierIntegrationTest {
@Autowired
private JwtTokenStore tokenStore;
...
}Мы начнем с токена, который не содержит эмитента (но содержит имя пользователя ) – который должен быть действительным:
@Test
public void whenTokenDontContainIssuer_thenSuccess() {
String tokenValue = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9....";
OAuth2Authentication auth = tokenStore.readAuthentication(tokenValue);
assertTrue(auth.isAuthenticated());
}Причина, по которой это допустимо, проста – первый верификатор активен только в том случае, если в токене существует утверждение эмитента. Если этого утверждения не существует – верификатор не срабатывает.
Далее давайте посмотрим на токен, который содержит действительного эмитента ( http://localhost:8081 ) и имя пользователя также. Это также должно быть действительным:
@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.
Как всегда, полный исходный код доступен на GitHub .