There is a Spring-MVC
project in which there are three types of users: Customer
, Admin
, Cook
. All of them are inherited from the class User
. Roles are created without ENUM
, simply through static String constants (shown in the User
class). After I added Spring Security
, authorization is successful, but when I try to execute a method of one of the classes(Customer, Admin or Cook), it gives json error 403:
{
"timestamp": "2020-05-08T19:48:43.999+0000",
"status": 403,
"error": "Forbidden",
"message": "Forbidden",
"path": "/admin/cooks"
}
Please tell me what I did wrong. Where was the mistake.
User:
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;
}
//
}
For example I add only one class Admin:
Admin:
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);
}
}
I use annotation @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;
}
}
To fix this problem, add the following to the WebSecurityConfig
class in the configure
method at the very beginning:
http
.cors().disable()
.csrf().disable()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With