web-dev-qa-db-ja.com

アプリケーションがSpring Securityのロールを表示しない理由(禁止)

Spring-MVC 3種類のユーザーが存在するプロジェクト:CustomerAdminCook。それらはすべてクラスUserから継承されます。役割はENUMなしで作成され、静的文字列定数を介して作成されます(Userクラスに表示されます)。追加した後Spring Security、認証は成功しましたが、クラス(Customer、Admin、またはCook)のいずれかのメソッドを実行しようとすると、jsonエラー403が発生します。

{
  "timestamp": "2020-05-08T19:48:43.999+0000",
  "status": 403,
  "error": "Forbidden",
  "message": "Forbidden",
  "path": "/admin/cooks"
}

私が間違ったことを教えてください。どこが間違いでしたか。

ユーザー:

package com.tinychiefdelights.model;

import io.swagger.annotations.ApiModel;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import javax.persistence.*;
import javax.validation.constraints.Size;
import Java.util.Collection;
import Java.util.Collections;

@ApiModel
@Data
@Entity
@Table(name = "pg_user", schema = "public")
public class User implements UserDetails {

    // Roles
    //
    public static final String ROLE_ADMIN = "ADMIN";
    public static final String ROLE_CUSTOMER = "CUSTOMER";
    public static final String ROLE_COOK = "COOK";
    //


    public User() { // Пустой конструктор для Hibernate

    }


    // Поля
    private @Id
    @GeneratedValue
    Long id;

    @Column(name = "login")
    private String login;

    @Size(min = 5, max = 30)
    @Column(name = "password")
    private String password;

    @Column(name = "role")
    private String role;

    @Column(name = "name")
    private String name;

    @Column(name = "last_name")
    private String lastName;


    // Методы
    //
    // GrantedAuthority
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return Collections.singletonList(new SimpleGrantedAuthority("ROLE_" + role));
    }


    // userName == login (одно и тоже)
    @Override
    public String getUsername() {
        return login;
    }


    // Во всех флагах стоит TRUE, так как они не используются
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }


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


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


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

たとえば、クラスAdminを1つだけ追加します。

管理:

package com.tinychiefdelights.model;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import javax.persistence.*;

@ApiModel
@Data
@Entity
@Table(name = "pg_user", schema = "public")
public class Admin {

    public Admin() { // Пустой конструктор для Hibernate

    }

    // Поля

    // name, lastName, login, password берем от класса User через связи;

    @ApiModelProperty
    private @Id
    @GeneratedValue
    Long id;


    // Relationships
    //
    @ApiModelProperty
    @OneToOne
    @JoinColumn(name = "id") // Join without Admin in User class
    private User user;
}

AdminService:

@Service
public class AdminService extends UserService {

    // Поля
    //
    // Injects in setters
    private AdminRepository adminRepository; // Администратор

    private OrderRepository orderRepository; // Заказ

    private CookRepository cookRepository; // Повар

    private CustomerRepository customerRepository; // Заказчик


    // Getters and Setters
    //
    // Делаем inject через сеттеры
    @Autowired
    public void setAdminRepository(AdminRepository adminRepository) {
        this.adminRepository = adminRepository;
    }

    @Autowired
    public void setOrderRepository(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }

    @Autowired
    public void setCookRepository(CookRepository cookRepository) {
        this.cookRepository = cookRepository;
    }

    @Autowired
    public void setCustomerRepository(CustomerRepository customerRepository) {
        this.customerRepository = customerRepository;
    }


    // Методы
    //
    // Вывод списка всех заказов
    public List<Order> getAllOrders() {
        return orderRepository.findAll();
    }


    // Вывод информации по конкретному заказу
    public Order getOrderInfo(Long id) {
        try {
            return orderRepository.getById(id);
        } catch (NotFoundException e) {
            throw new NotFoundException(id);
        }
    }


    // Вывод Повара по ID
    public Cook getCook(Long id) {
        try {
            return cookRepository.getByIdAndUserRole(id, "COOK");
        } catch (NotFoundException e) {
            throw new NotFoundException(id);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException();
        }
    }


    // Изменить карту повара
    public void editCook(Long id, User user, float rating, String aboutCook) {
        Cook cook = cookRepository.getByIdAndUserRole(id, "COOK");
        try {
            cook.setUser(user);
            cook.setRating(rating);
            cook.setAboutCook(aboutCook);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException();
        } catch (NotFoundException e) {
            throw new NotFoundException(id);
        }
    }


    // Вывод всех поваров
    public List<Cook> getAllCooks() {
        return cookRepository.findByUserRole("COOK");
    }


    // Удалить Повара
    public void deleteCook(Long id) {
        Cook cook = cookRepository.getByIdAndUserRole(id, "COOK");
        try {
            cookRepository.delete(cook);
        } catch (Exception e) {
            throw new NotFoundException(id);
        }
    }


    // Вывод всех Заказчиков
    public List<Customer> getAllCustomers() {
        return customerRepository.findByUserRole("CUSTOMER");
    }


    // Вывод Заказчика по ID
    public Customer getCustomer(Long id) {
        try {
            return customerRepository.getByIdAndUserRole(id, "CUSTOMER");
        } catch (NotFoundException e) {
            throw new NotFoundException(id);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException();
        }
    }
}

AdminController:

@Api(value = "Работа с Админом", tags = {"Администратор"})
@RestController
@RequestMapping("/admin")
@RolesAllowed("ADMIN")
public class AdminController {

    // Constructor
    //
    // Inject через конструктор
    @Autowired
    public AdminController(AdminRepository adminRepository, AdminService adminService, UserService userService) {
        this.adminRepository = adminRepository;
        this.adminService = adminService;
        this.userService = userService;
    }


    // Поля
    // All injects into constructor
    private final AdminRepository adminRepository;

    private final AdminService adminService;

    private final UserService userService;


    // Методы
    //
    // GET MAPPING
    //
    // Вывод списка всех заказов
    @GetMapping("/orders")
    List<Order> getAllOrders() {
        return adminService.getAllOrders();
    }


    // Вывод информации по конкретному заказу по ID
    @GetMapping("/order/{id}")
    Order getOrderInfo(@PathVariable Long id) {
        return adminService.getOrderInfo(id);
    }


    // Вывод всех Поваров
    @GetMapping("/cooks")
    List<Cook> getAllCooks() {
        return adminService.getAllCooks();
    }


    // Вывод Повара по ID
    @GetMapping("/cook/{id}")
    Cook getCook(@PathVariable Long id) {
        return adminService.getCook(id);
    }


    // Вывод всех пользователей
    @GetMapping("/customers")
    List<Customer> getAllCustomer() {
        return adminService.getAllCustomers();
    }


    // Вывод Заказчика по ID
    @GetMapping("/customer/{id}")
    Customer getCustomer(@PathVariable Long id) {
        return adminService.getCustomer(id);
    }


    // POST MAPPING
    //


    // PUT MAPPING
    //
    // Изменяем Повара по ID
    @PutMapping("/edit/cook/{id}")
    void editCook(@PathVariable Long id, User user, @PathVariable float rating, String aboutCook) {
        adminService.editCook(id, user, rating, aboutCook);
    }

    // Поменять пароль
    @PutMapping("/change/password")
    void changePassword(@RequestParam String login, @RequestParam String newPass) {
        userService.changePassword(login, newPass);
    }


    // DELETE MAPPING
    //
    // Удалить конкретного Повара по ID
    @DeleteMapping("/delete/cook/{id}")
    void removeCook(@PathVariable Long id) {
        adminService.deleteCook(id);
    }
}

注釈@ RolesAllowedを使用しています。

SpringWebConfig:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


    // Поля
    //
    private UserService userService;

    private PasswordEncoder passwordEncoder;



    // Injects in SETTERS
    //
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    @Autowired
    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }



    // Methods
    //
    // Тут мы переопределяем метод конфигураций
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/", "/home").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
                .logout()
                .permitAll();
    }


    // Тут мы переопределяем для работы с внешней БД
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService).passwordEncoder(passwordEncoder);
    }


    // Beans
    //
    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(userService);
        authenticationProvider.setPasswordEncoder(passwordEncoder);
        return authenticationProvider;
    }


    @Bean
    public static PasswordEncoder getPasswordEncoder() {
        return new BCryptPasswordEncoder(8);
    }


    // Возвращаем сервис пользовател для userDetService
    @Bean
    public UserDetailsService userDetailsService() {
        return userService;
    }
}

enter image description here

6
Artur Vartanyan

ロール名の従来のプレフィックス(_User::getAuthorities_で使用したもの)と一致させるには、@RolesAllowed("ADMIN")@RolesAllowed("ROLE_ADMIN")に変更する必要があります。

0
Dmitrii Abramov