Использование JWT с Spring Security OAuth

Использование JWT с Spring Security OAuth

1. обзор

В этом руководстве мы обсудим, как заставить нашу реализацию Spring Security OAuth2 использовать веб-токены JSON.

Мы также продолжаем использоватьthe previous article в этой серии OAuth.

Дальнейшее чтение:

Выйти из приложения с защитой OAuth

Практическое углубленное изучение того, как реализовать выход из системы в приложении Spring Security OAuth2 с помощью JWT.

Read more

OAuth2 Запомнить меня с токеном обновления

Узнайте, как реализовать функцию запомнить меня с помощью интерфейса Angular для приложения, защищенного с помощью Spring Security и OAuth2.

Read more

OAuth2 для API Spring REST - обработка маркера обновления в AngularJS

Мы узнали, как хранить токен обновления в клиентском приложении AngularJS, как обновить токен доступа с истекшим сроком действия и как использовать прокси Zuul.

Read more

 

Прежде чем мы начнем - одно важное замечание. Имейте в виду, чтоthe Spring Security core team is in the process of implementing a new OAuth2 stack - некоторые аспекты уже выполнены, а некоторые все еще находятся в процессе разработки.

Вот короткое видео, которое даст вам некоторый контекст вокруг этих усилий:

 

Хорошо, приступим.

2. Конфигурация Maven

Во-первых, нам нужно добавить зависимостьspring-security-jwt к нашемуpom.xml:


    org.springframework.security
    spring-security-jwt

Обратите внимание, что нам нужно добавить зависимостьspring-security-jwt как к серверу авторизации, так и к серверу ресурсов.

3. Сервер авторизации

Затем мы настроим наш сервер авторизации для использованияJwtTokenStore - следующим образом:

@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints)
      throws Exception {
        endpoints.tokenStore(tokenStore())
                 .accessTokenConverter(accessTokenConverter())
                 .authenticationManager(authenticationManager);
    }

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("123");
        return converter;
    }

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }
}

Обратите внимание, что мы использовалиsymmetric key в нашемJwtAccessTokenConverter для подписи наших токенов - это означает, что нам нужно будет использовать тот же точный ключ и для сервера ресурсов.

4. Ресурсный сервер

Теперь давайте посмотрим на конфигурацию нашего сервера ресурсов, которая очень похожа на конфигурацию сервера авторизации:

@Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(ResourceServerSecurityConfigurer config) {
        config.tokenServices(tokenServices());
    }

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("123");
        return converter;
    }

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        return defaultTokenServices;
    }
}

Имейте в виду, что мы определяем эти два сервера как полностью отдельные и независимо развертываемые. Вот почему нам нужно снова объявить некоторые из тех же beans здесь, в новой конфигурации.

5. Пользовательские утверждения в токене

Теперь давайте настроим некоторую инфраструктуру, чтобы можно было добавить несколькоcustom claims in the Access Token. Стандартные утверждения, предоставляемые фреймворком, хороши и хороши, но в большинстве случаев нам потребуется дополнительная информация в токене для использования на стороне клиента.

Мы определимTokenEnhancer, чтобы настроить наш токен доступа с этими дополнительными утверждениями.

В следующем примере мы добавим дополнительное поле «organization» к нашему токену доступа - с этимCustomTokenEnhancer:

public class CustomTokenEnhancer implements TokenEnhancer {
    @Override
    public OAuth2AccessToken enhance(
      OAuth2AccessToken accessToken,
      OAuth2Authentication authentication) {
        Map additionalInfo = new HashMap<>();
        additionalInfo.put(
          "organization", authentication.getName() + randomAlphabetic(4));
        ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(
          additionalInfo);
        return accessToken;
    }
}

Затем мы подключим это к нашей конфигурацииAuthorization Server следующим образом:

@Override
public void configure(
  AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
    tokenEnhancerChain.setTokenEnhancers(
      Arrays.asList(tokenEnhancer(), accessTokenConverter()));

    endpoints.tokenStore(tokenStore())
             .tokenEnhancer(tokenEnhancerChain)
             .authenticationManager(authenticationManager);
}

@Bean
public TokenEnhancer tokenEnhancer() {
    return new CustomTokenEnhancer();
}

Когда эта новая конфигурация запущена и работает - вот как будут выглядеть полезные данные токена:

{
    "user_name": "john",
    "scope": [
        "foo",
        "read",
        "write"
    ],
    "organization": "johnIiCh",
    "exp": 1458126622,
    "authorities": [
        "ROLE_USER"
    ],
    "jti": "e0ad1ef3-a8a5-4eef-998d-00b26bc2c53f",
    "client_id": "fooClientIdPassword"
}

5.1. Используйте токен доступа в JS-клиенте

Наконец, мы хотим использовать информацию о токене в нашем клиентском приложении AngualrJS. Для этого воспользуемся библиотекойangular-jwt.

Итак, мы собираемся использовать утверждение «organization» в нашемindex.html: