Следует ли обновлять полномочия хранилища токенов при обновлении токена?

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

       @Bean
 fun jwtCustomizer(): OAuth2TokenCustomizer<JwtEncodingContext> {
   return OAuth2TokenCustomizer { context: JwtEncodingContext ->
     val principal: Authentication = context.getPrincipal() // <-- this won't change 
     val user: UserDetailsImpl = principal.principal as UserDetailsImpl
     context.claims.claim("userId", user.getUserId())
     context.claims.claim("authorities", user.getAuthorities())
   }
 }

Однако полномочия пользователя могут регулярно изменяться, например, полномочия пользователя изменились с «ADMIN» на «USER», но, поскольку JwtEncodingContext не будет изменен, он по-прежнему получает полномочия «ADMIN» всякий раз, когда он обновляет токен. Так что я не совсем уверен, как правильно с этим справиться, одна вещь, о которой я могу думать, это заставить пользователя повторно войти в систему, отменив его токен, но это решение, вероятно, дает пользователю очень плохой опыт из-за того, что власти могут регулярно меняться в моей системе. или, может быть, немного грязное решение заключается в том, чтобы вместо этого запрашивать данные из сведений о пользователе и помещать их в такие утверждения.

       @Bean
 fun jwtCustomizer(): OAuth2TokenCustomizer<JwtEncodingContext> {
   return OAuth2TokenCustomizer { context: JwtEncodingContext ->
     val principal: Authentication = context.getPrincipal() // <-- this won't change 
     val user: UserDetailsImpl = userDetailsRepository.findById(principal.getUserId())
     context.claims.claim("userId", user.getUserId())
     context.claims.claim("authorities", user.getAuthorities())
   }
 }

Любые идеи, как справиться с этим?

1 ответ

Решение, которое вы изложили, является одним из возможных вариантов, и мне кажется, что это хорошее начало. Обсуждая в комментариях, я бы не согласился с тем, что это «грязное» решение, потому что вы фактически используете встроенные компоненты, а именноOAuth2TokenCustomizerиUserDetailsService. Встроенные компоненты в Spring Security предназначены для того, чтобы позволить вам интегрировать ваши правила и требования авторизации в структуру, которую вы пытаетесь сделать. Если у вас есть работающее решение для этого, я бы сказал, что вам есть на что опираться, и вы всегда можете улучшить его позже или поэкспериментировать с другими способами, если это необходимо.

Другим вариантом было бы включить толькоrolesпретензия (например"roles": ["ROLE_ADMIN"]) в маркере доступа и выполните сопоставление полномочий на сервере ресурсов. Преимущество этого заключается в постоянном обновлении, но недостатком является масштабируемость, поскольку требуется, чтобы многие серверы ресурсов запрашивали базу данных, где хранятся сопоставления ролей и полномочий. Если это представляет интерес, вы могли бы использоватьJwtGrantedAuthoritiesMapperотspring-security-oauth2-resource-serverна стороне сервера ресурсов.

Я бы также рекомендовал непрозрачные токены вместо JWT, если требуется немедленный отзыв. Аналогичная поддержка существует при использовании непрозрачных токенов, хотя в этом случае было бы лучше настроить утверждения на сервере авторизации.

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