Получение Spring Security «Образец входа JWT» для работы с ролями

Я пытаюсь переписать предыдущий пример с JWT, созданным с помощью пользовательского фильтра JWT, в упрощенную версию, основанную на новом сервере авторизации Springs, и этот пример:https://github.com/spring-projects/spring-security-samples/tree /главный/сервлет/весенняя загрузка/java/jwt/логин

В примере настраивается InMemoryUserDetailsManager с одним пользователем → пользователем, паролем и полномочиями «приложения», поэтому я предполагаю, что он предназначен для обработки ролей/полномочий?

Все работает нормально (как объяснено в примерах README), если я использую предоставленный SecurityFilterChain. Но если я изменю это:

      ...
http.authorizeHttpRequests((authorize) -> authorize
    .anyRequest().authenticated()
)

В это

      ...
http.authorizeHttpRequests((authorize) -> authorize
    .antMatchers("/").hasRole("app")
    //.antMatchers("/").hasAuthority("app")
    .anyRequest().authenticated()
)

Я получаю статус 403. Полномочия добавляются в JWT, как и ожидалось, следующим образом:

        ..
  "scope": "app"
}

Помимо приведенных выше antMatchers, мой код точно такой же, как клон из примера Spring Security.

Что мне здесь не хватает?

2 ответа

ИспользоватьhasRole, вам нужны полномочия, начинающиеся сROLE_. Что вы можете сделать, так это зарегистрировать конвертер , который будет считывать роли из JWT и добавлять их какGrantedAuthority.

      public class RolesClaimConverter implements Converter<Jwt, AbstractAuthenticationToken> {

    private final JwtGrantedAuthoritiesConverter wrappedConverter;

    public RolesClaimConverter(JwtGrantedAuthoritiesConverter conv) {
        wrappedConverter = conv;
    }

    @Override
    public AbstractAuthenticationToken convert(@NonNull Jwt jwt) {
        // get authorities from wrapped converter
        var grantedAuthorities = new ArrayList<>(wrappedConverter.convert(jwt));
        // get role authorities
        var roles = (List<String>) jwt.getClaims().get("roles");
        if (roles != null) {
            for (String role : roles) {
                grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_" + role));
            }
        }

        return new JwtAuthenticationToken(jwt, grantedAuthorities);
    }
}

Затем зарегистрируйте конвертер в конфигурации безопасности.

      @Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .oauth2ResourceServer(resourceServer -> resourceServer
            .jwt()
            .jwtAuthenticationConverter(
                 new RolesClaimConverter(
                     new JwtGrantedAuthoritiesConverter()
                 )
            )
        )
        // other configuration
    ;
    return http.build();
}

Вот и все. Все, что вам нужно сделать сейчас, это передать список ролей в качестве утверждения при создании JWT, и вы можете использовать.antMatchers("/").hasRole("app")и@PreAuthorize("hasRole('app')")в вашем коде.

ОК, прочитайте спецификации ;-) В соответствии с https://docs.spring.io/spring-security/reference/reactive/oauth2/resource-server/jwt.htmlAuthorities получает префикс SCOPE_

Так что это частично решает проблему .antMatchers("/").hasAuthority("SCOPE_app")

Я до сих пор не понял, как использовать hasRoles?

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