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(Mapclaims) 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 .