Как декодировать и проверить настроенный JWT с сервера авторизации Spring на Spring Resource Server?

Я использую сервер авторизации Spring 1.0.0. В этом я настроил JWT в соответствии с моим требованием следующим образом. Допустим, есть пользователь «vinay». И его роль тоже «винай».

Я добавляю дополнительное поле «авторитет»: [{"role":"ROLE_vinay"}] в JWT. Ниже представлена ​​полезная нагрузка JWT.

{ "sub": "vinay", "aud": "messaging-client", "nbf": 1671430162, "authority": [ { "role": "ROLE_vinay" } ], "scope": [ "openid" ], "iss": "http://localhost:8000", "exp": 1671430462, "iat": 1671430162 }

Для роли "vinay" существует несколько разрешений/ограничений. Эти данные присутствуют в MySQL. После аутентификации пользователя (логина) я добавляю эти данные в Redis в пару KEY:VALUE, где ключ — «vinay», значение — [Ограничение 1, Разрешение 1, Разрешение 2].

"vinay" : [Permission 1, Permission 2, Restriction 1]

После успешного входа в систему от пользователя (vinay) клиент получает пользовательский токен и отправляет запрос на сервер ресурсов Spring с пользовательским JWT в заголовке с префиксом Bearer. Для каждого запроса. Как декодировать входящий JWT, получить «роль» и проверить ее от Redis? Если в Redis есть какие-то ограничения, то он не должен их разрешать. Он должен выдать «401 неавторизованный». Если есть разрешение, то он должен продолжить запрос.

1 ответ

В своем последнем комментарии вы описали использование только MySQL, и я думаю, что это имеет смысл. Я не вижу, чтобы Redis вписывался в этот сценарий. Итак, поток:

  1. На сервере авторизации вы используетеOAuth2TokenCustomizer<JwtEncodingContext>чтобы добавить поле в JWT (например, ).
  2. На сервере ресурсов вы используетесоставить картуauthorityполе JWT дляauthentication.getAuthorities()в весенней безопасности.

Проблема заключается в том, что в вашей БД вы сопоставляете роли непосредственно с набором разрешенных URL-адресов (например, =>POST /customer, ...). Возможно, вы имеете дело с существующей схемой базы данных и не можете спроектировать данные или отношения с нуля. Я ожидаю сопоставления ролей с набором разрешений (например, =>customer.write, ...).

Если у вас есть такая схема разрешений, вы можете выполнить поиск вJwtGrantedAuthoritiesConverterвыше и сопоставьте эти разрешения с полномочиями.


Однако, если данные в MySQL сопоставляют роли с шаблонами URL-адресов, лучше всего использовать API для интеграции авторизации с вашей таблицей MySQL (см. пример Configure RequestMatcherDelegatingAuthorizationManager в разделе Authorize HttpServletRequests with AuthorizationFilter ).

Пользователь может быть реализован для поискаROLE_xyzи динамически построить список правил авторизации сRequestMatcherDelegatingAuthorizationManager.builder().

Например:

      @Configuration
@EnableWebMvc
@EnableWebSecurity
public class SecurityConfiguration {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http, AuthorizationManager<RequestAuthorizationContext> access)
            throws Exception {
        // @formatter:off
        http
            .authorizeHttpRequests((authorize) -> authorize
                .anyRequest().access(access)
            )
            .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
        // @formatter:on

        return http.build();
    }

    @Bean
    AuthorizationManager<RequestAuthorizationContext> authorizationManager(
            HandlerMappingIntrospector introspector) {
        MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector);
        RequestMatcher anyRequest = AnyRequestMatcher.INSTANCE;

        AuthorizationManager<RequestAuthorizationContext> authenticated =
            AuthenticatedAuthorizationManager.authenticated();
        AuthorizationManager<RequestAuthorizationContext> denyAll =
            (a, c) -> new AuthorizationDecision(false);

        return (supplier, context) -> {
            Authentication authentication = supplier.get();
            HttpServletRequest request = context.getRequest();

            // TODO: Look up mappings in MySQL using authentication.getAuthorities()...

            RequestMatcherDelegatingAuthorizationManager.Builder builder =
                RequestMatcherDelegatingAuthorizationManager.builder();

            // TODO: Add custom mappings from MySQL...
            //builder.add(mvcMatcherBuilder.pattern("/customer/**"), authenticated);

            RequestMatcherDelegatingAuthorizationManager delegate =
                builder.add(anyRequest, denyAll).build();

            return delegate.check(() -> authentication, request);
        };
    }

}

Это может показаться сложным, но ваша схема авторизации (с использованием OAuth2 + JWT И ролей/полномочий И MySQL для управления ролями) представляет собой довольно сложную настройку. AuthorizationManagerAPI на самом деле делает это проще, чем в более ранних версиях Spring Security.

Также обратите внимание, что в приведенном выше примере предполагается, что сопоставления ролей в базе данных могут изменяться во время выполнения, и поэтому их необходимо просматривать каждый раз. Если это не так, пример можно изменить, чтобы загружать данные из MySQL только при запуске. Производительность поиска MySQL также может быть улучшена с помощью кэширования, если это необходимо.

Другие вопросы по тегам