I’m trying to secure an endpoint .requestMatchers("/user/players").hasAuthority("ADMIN")
so that only User
with role = 'ADMIN'
can access it.
Problem I’m facing is when using hasRole(“ADMIN”),it doesn’t really work because every authenticated user can reach the "/user/players"
endpoint (it just displays a list of players I have in my db).
I’m using MySQL db, Spring Security 3.3.1, Spring Boot 3.2.5
I have an Entity User which has a filed Role(custom Enum class) I’m thinking that that’s the problem, because somehow it can’t see which role it has.
I printed out the logged in user username and role and it’s okay.
I got:
Current logged in user is *mario*
Current logged in user role is *[ROLE_ADMIN]*
This is code I have so far..
SecurityConfig.java:
package com.example.kickoff.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
/* private final CustomUserDetailsService customUserDetailsService;
public SecurityConfig(CustomUserDetailsService customUserDetailsService) {
this.customUserDetailsService = customUserDetailsService;
}*/
@Bean
public static PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable);
return http
.authorizeHttpRequests(request -> request
.requestMatchers("/user/home", "/user/hello").permitAll()
.requestMatchers("/user/hello").authenticated()
.requestMatchers("/user/players").hasRole("ADMIN")
.anyRequest().authenticated()
)
.formLogin(login -> login.permitAll())
.logout(logout -> logout.permitAll())
.build();
}
}
Role.java
package com.example.kickoff.model;
public enum Role {
ADMIN, ORGANIZER, TEAM_REPRESENTATIVE
}
User.java
package com.example.kickoff.model;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "users")
public class User{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "username", unique = true)
private String username;
@Column(name = "pwd")
private String password;
@Enumerated(EnumType.STRING)
@Column(name = "user_role")
private Role role;
}
I have tried using hasAuthority("ADMIN")
instead hasRole, but also failed as every user gets There was an unexpected error (type=Forbidden, status=403).
I’ve also tried using @PreAuthorize like so:
@GetMapping("/players")
@PreAuthorize("hasRole('ROLE_ADMIN')")
public String getPlayers(Model model) {
model.addAttribute("playersList", playerService.getAllPlayers());
return "players";
}
What am I missing out?