Как декодировать и проверить настроенный 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 вписывался в этот сценарий. Итак, поток:
- На сервере авторизации вы используете
OAuth2TokenCustomizer<JwtEncodingContext>
чтобы добавить поле в JWT (например, ). - На сервере ресурсов вы используетесоставить карту
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 для управления ролями) представляет собой довольно сложную настройку. AuthorizationManager
API на самом деле делает это проще, чем в более ранних версиях Spring Security.
Также обратите внимание, что в приведенном выше примере предполагается, что сопоставления ролей в базе данных могут изменяться во время выполнения, и поэтому их необходимо просматривать каждый раз. Если это не так, пример можно изменить, чтобы загружать данные из MySQL только при запуске. Производительность поиска MySQL также может быть улучшена с помощью кэширования, если это необходимо.