Помогите инициализировать и авторизовать админа Spring Boot

не минусуйте плиз, сам искал инфу долго, не могу разобраться.

Есть проект на спринге, пока просто таблица юзеров, репозиторий, подключенная аутентификация. Есть класс DataInitializer, наследуется от ApplicationRunner, методом run делает начального пользователя

    @Override
    public void run(ApplicationArguments args) throws Exception {
        var email = "[email protected]";
        var userData = new User();
        userData.setEmail(email);
        userData.setPasswordDigest("qwerty");
        userData.setRole("ADMIN");
        userService.createUser(userData);
    }

Проблема! В том, что я установил такой доступ к ресурсам в конфиг-классе SecurityConfig

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http, HandlerMappingIntrospector introspector)
            throws Exception {
        // По умолчанию все запрещено
        return http
                .csrf(csrf -> csrf.disable())
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/api/login").permitAll()
                        .requestMatchers("/api/pages/*").permitAll()
                        .requestMatchers("/api/pages").permitAll()
                        .requestMatchers("/").permitAll()
                        .requestMatchers("/index.html").permitAll()
                        .requestMatchers("/assets/**").permitAll()
                        .requestMatchers("/api/users/**").hasRole("ADMIN")
                        .anyRequest().authenticated())
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .oauth2ResourceServer((rs) -> rs.jwt((jwt) -> jwt.decoder(jwtDecoder)))
                .httpBasic(Customizer.withDefaults())
                .build();
    }

то есть окно авторизации - доступно всем, а все апишки после users - только авторизованным.

Пробую через postman тестировать - результат такой - post-запрос на аутентификацию с дефолтными параметрами проходит и я получаю назад свой JWT-токен, но не выставляется роль админа и из-за этого получать доступ к crud-операциям над юзерами я не могу.

Мой класс модели выглядит так

@Getter
@Setter
@Entity
@Table(name = "users")
@EntityListeners(AuditingEntityListener.class)
public class User implements BaseEntity, UserDetails {
    @Id
    @GeneratedValue(strategy = IDENTITY)
    private Long id;

    @Column(nullable = true)
    private String firstName;

    @Column(nullable = true)
    private String lastName;
    // EMAIL
    @Column(unique = true)
    @Email
    @ToString.Include
    private String email;

    @Column(nullable = false)
    private String passwordDigest;

    private String role;

    @CreatedDate
    private LocalDate createdAt;

    @LastModifiedDate
    private LocalDate updatedAt;

   @Override
    public String getPassword() {
        return passwordDigest;
    }

    @Override
    public String getUsername() {
        return email;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return List.of();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

Как и где я вижу затуп. В инициализации первого юзера(первый кусок кода я приводил) я передаю данные типа User в инстанс userService класса (бина) CustomUserDetailsService, его код такой

    @Override
    public void createUser(UserDetails userData) {
        var user = new User();
        user.setEmail(userData.getUsername());
        var hashedPassword = passwordEncoder.encode(userData.getPassword());
        user.setPasswordDigest(hashedPassword);
        user.setRole(userData.getAuthorities().toString());
        userRepository.save(user);
    }

То есть он уже принимает и работае объект типа UserDetails и у него нет полей класса User.. Соотвественно, когда я чекаю на постмане(отключив обязательность авторизации для просмотра гет-запросов) данные о 1ом юзере поле role = null

Необходимо мне , понять как давать роли разным юзерам(в частности первому дать админку), и исходя из этого уже мочь 1ым юзером совершать crud-операции.

Уважаемые знатоки, направьте подскажите плиз, я читал про секьюрити немного, но пока слишком сложно и непонятно...

репо на всякий случий


Ответы (1 шт):

Автор решения: Qwer

Думаю можно начать с того, чтобы присваивать юзерам роль в формате "ROLE_ADMIN". По умолчанию, если предоставленная методу hasRole() роль не начинается с ROLE_, она добавляется самим методом. Т.е. у юзера роль "ADMIN", а сравнивается она с "ROLE_ADMIN". Крейг Уоллс хорошо описал этот момент:

Когда использовать или не использовать префикс «ROLE_»


В Spring Security поддерживается несколько форм привилегий, включая роли,разрешения и (как мы увидим позже) области действия OAuth2. Роли, в частности, – это особая форма привилегий, названия которых начинаются с префикса "ROLE_". При использовании методов или выражений SpEL, имеющих дело с ролями, таких как hasRole(), префикс "ROLE_" подразумевается по умолчанию. Поэтому вызов hasRole("ADMIN") фактически выполнит проверку привилегий с именем "ROLE_ADMIN". При вызове таких методов и функций не нужно использовать префикс "ROLE_" (иначе это приведет к дублированию префикса "ROLE_"). Другие методы и функции в Spring Security, не зависящие от конкретного типа полномочий, тоже можно использовать для проверки ролей, но в подобных случаях необходимо явно добавить префикс "ROLE_". Например, если вы решите использовать hasAuthority() вместо hasRole(), то вам нужно будет передать в вызов "ROLE_ADMIN" вместо "ADMIN".

Так же при написании фильтров доступа к определенным страницам важен порядок. Первыми пишутся самые строгие правила, после менее строгие. Попробуй поставить .requestMatchers("/api/users/**").hasRole("ADMIN") первой строкой.

→ Ссылка