I made a simple api rest application with role based authentication. When I text the endpoints in postman or swagger if I put role restrictions I get the 403 error even if I log in with the user that has the appropriate role.
Class SecurityConfig
@Configuration
@EnableMethodSecurity
public class SecurityConfig {
private UserDetailsService userDetailsService;
public SecurityConfig(UserDetailsService userDetailsService){
this.userDetailsService = userDetailsService;
}
@Bean
public static PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager(
AuthenticationConfiguration configuration) throws Exception {
return configuration.getAuthenticationManager();
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.cors().disable()
.authorizeHttpRequests((authorize) ->
authorize.requestMatchers("/api/admin/**").hasAuthority("ROLE_ADMIN")
.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/swagger-ui/**").permitAll()
.requestMatchers("/v3/api-docs/**").permitAll()
//.requestMatchers("/api/admin/**").hasRole("ADMIN")
//.requestMatchers("/api/user/**").hasRole("USER")
.anyRequest().authenticated()
);
return http.build();
}
}
Class AuthController
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserRepository userRepository;
@Autowired
private RoleRepository roleRepository;
@Autowired
private PasswordEncoder passwordEncoder;
/**
*
* @param loginDto
* @return
*/
@PostMapping("/v1/signin")
public ResponseEntity<String> authenticateUser(@RequestBody LoginDto loginDto){
Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(
loginDto.getEmail(), loginDto.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
return new ResponseEntity<>("User signed-in successfully!.", HttpStatus.OK);
}
/**
*
* @param signUpDto
* @return
*/
@PostMapping("/v1/signup")
public ResponseEntity<?> registerUser(@RequestBody @Validated SignUpDto signUpDto){
// add check for email exists in DB
if(userRepository.existsByEmail(signUpDto.getEmail())){
return new ResponseEntity<>("Email già in uso scegli una mail diversa!", HttpStatus.BAD_REQUEST);
}
// create user object
User user = new User();
user.setName(signUpDto.getName());
user.setSurname(signUpDto.getSurname());
user.setEmail(signUpDto.getEmail());
user.setPassword(passwordEncoder.encode(signUpDto.getPassword()));
user.setEnabled(true);
Role roles = roleRepository.findByName("ROLE_USER").get();
user.setRoles(Collections.singleton(roles));
userRepository.save(user);
return new ResponseEntity<>("Nuovo utente registrato correttamente!", HttpStatus.OK);
}
}
Class CustomUserDetailService
@Service
public class CustomUserDetailsService implements UserDetailsService {
private UserRepository userRepository;
public CustomUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userRepository.findByEmail(email)
.orElseThrow(() ->
new UsernameNotFoundException("User not found with email: "+ email));
Set<GrantedAuthority> authorities = user
.getRoles()
.stream()
.map((role) -> new SimpleGrantedAuthority(role.getName())).collect(Collectors.toSet());
return new org.springframework.security.core.userdetails.User(user.getEmail(),
user.getPassword(),
authorities);
}
}
Class User
@Table(name = "User")
public class User {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 20)
private String name;
@Column(nullable = false, length = 20)
private String surname;
@Column(nullable = false, unique = true, length = 45)
private String email;
@Column(nullable = false, length = 64)
private String password;
@Column(nullable = false, length = 1)
private boolean enabled;
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(name = "user_roles",
joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"))
private Set<Role> roles;
/* @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(name = "Booking",
joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "booking_id", referencedColumnName = "id"))
private Set<Booking> bookings;*/
}
Class Role
@Table(name = "roles")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(length = 60)
private String name;
}
Only with permitAll() I'm able to access the endpoints.
[Login ok][1]