Я использую сервер авторизации 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 неавторизованный». Если есть разрешение, то он должен продолжить запрос.
Привет @SteveRiesenberg, я могу проверить и проверить токен на сервере ресурсов. Я представил свой собственный «JwtDecoder», который имеет реализацию класса «OAuth2TokenValidator», которая выполняет пользовательскую проверку. Он проходит, но у меня все еще есть некоторые сомнения. 1) Что происходит, когда Сервер авторизации меняет пару ключей? Нужно ли перезапускать сервер ресурсов или в любом случае уведомлять сервер ресурсов? 2) Как получить информацию о входящем запросе в «JwtDecoder» или «OAuth2TokenValidator»? Я использую «(ServletRequestAttributes) RequestContextHolder». Это правильно или неправильно? Спасибо.
Это не очень целенаправленный вопрос, похоже, у вас довольно много вопросов. Многое из того, о чем вы спрашиваете, может быть обнаружено путем тестирования и/или чтения документации. Что касается получения сведений о запросе, я бы сказал, что это, вероятно, неправильно, потому что JwtDecoder не там, где происходит обработка на уровне запроса. Он просто проверяет/декодирует токен. Это зависит от того, что вы хотите делать с деталями запроса, где правильно разместить эту логику.
Мне также интересно, почему вы хотите добавить зависимость к Redis для проверки JWT, когда вместо этого вы можете включить разрешения/ограничения в JWT при его создании. Вы ожидаете много таких записей? Наконец, я не понимаю, зачем вам проверять Redis, если изначально данные уже присутствуют в MySQL. Я бы подумал, что использование MySQL для добавления разрешений/ограничений в JWT через OAuth2TokenCustomizer<JwtEncodingContext>
было бы подходящим способом, а не использование Redis вообще. Очевидно, мне не хватает части вашего варианта использования.
Привет @SteveRiesenberg, спасибо. Вот сценарий, таблица MySQL содержит шаблоны URL, для которых пользователю разрешен доступ к ресурсу. Пример: (ПОСТ: /клиент). Я хочу проверить JWT по этим данным. (JWT имеет «авторитет»: [ { «роль»: «ROLE_vinay» } ], а MySQL имеет «авторитет» таблицы с ROLE_vinay в качестве первичного ключа и его URL-адрес и сведения о методе в других полях). После того, как я получу входящий Jwt и декодирую его, он подаст «авторитет», и я получу данные Role_vinay из MySQL, он содержит URL-адрес и сведения о методе. Я хочу сравнить это с входящим запросом.
Это правильный путь или какие-либо другие стандартные способы, доступные для реализации, которую я делаю?
В своем последнем комментарии вы описали использование только MySQL, и я думаю, что это имеет смысл. Я не вижу, чтобы Redis вписывался в этот сценарий. Итак, поток:
authority
в JWT (например, ROLE_xyz
).authority
JWT с authentication.getAuthorities()
в Spring Security.Проблема заключается в том, что в вашей БД вы сопоставляете роли непосредственно с набором разрешенных URL-адресов (например, ROLE_xyz
=> POST /customer
, ...). Возможно, вы имеете дело с существующей схемой базы данных и не можете спроектировать данные или отношения с нуля. Я ожидаю сопоставления ролей с набором разрешений (например, ROLE_xyz
=> customer.write
, ...).
Если у вас есть такая схема разрешений, вы можете выполнить поиск в JwtGrantedAuthoritiesConverter
выше и вместо этого сопоставить эти разрешения как полномочия.
Однако, если данные в MySQL сопоставляют роли с шаблонами URL-адресов, лучше всего использовать AuthorizationManager
API для интеграции авторизации с вашей таблицей MySQL (для примера см. Настройка RequestMatcherDelegatingAuthorizationManager в разделе Авторизация запросов HttpServletRequests с помощью AuthorizationFilter).
Пользовательский AuthorizationManager
может быть реализован для поиска 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 для управления ролями) представляет собой довольно сложную настройку. API AuthorizationManager
на самом деле делает его проще, чем в более ранних версиях Spring Security.
Также обратите внимание, что в приведенном выше примере предполагается, что сопоставления ролей в базе данных могут изменяться во время выполнения, и поэтому их необходимо просматривать каждый раз. Если это не так, пример можно изменить, чтобы загружать данные из MySQL только при запуске. Производительность поиска MySQL также может быть улучшена с помощью кэширования, если это необходимо.
что ты уже испробовал?