Spring Security 6授权失效:ROLE前缀重复引发403错误排查
我在使用Spring Boot 3和Spring Security 6配置授权规则时遇到了异常,始终无法正常生效:
配置与初始问题
我通过以下代码配置授权规则:
http.authorizeHttpRequests(authorize -> authorize.requestMatchers("/hello/**").hasRole("USER"));
登录后访问/hello/**接口时,始终收到403 Forbidden错误。
查看Spring Security DEBUG日志,发现认证后的权限信息如下:
2024-06-15T06:55:20.123+05:30 DEBUG 15236 --- [spring-authn-authz] [nio-8080-exec-4] w.c.HttpSessionSecurityContextRepository : Retrieved SecurityContextImpl [Authentication=UsernamePasswordAuthenticationToken [Principal=com.nagpal.spring_authn_authz.config.EmployeeUserDetails@2af776cf, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=846F84FABBD0F9B98EFEF4DAAE047AA4], Granted Authorities=[USER]]]
日志明确显示已授予USER权限,但依然返回403。
尝试修复后的异常行为
根据资料查询,Spring Security的角色权限需要添加ROLE_前缀,于是我修改了EmployeeUserDetails的getAuthorities方法:
@Override public Collection<? extends GrantedAuthority> getAuthorities() { List<GrantedAuthority> authorities = new ArrayList<>(); log.info("Adding role with ROLE_ appended"); GrantedAuthority role = new SimpleGrantedAuthority("ROLE_" + employee.getRole()); authorities.add(role); return authorities; }
修改后访问接口仍返回403,且日志显示权限前缀被重复添加:
2024-06-15T06:59:28.747+05:30 DEBUG 15236 --- [spring-authn-authz] [nio-8080-exec-4] w.c.HttpSessionSecurityContextRepository : Retrieved SecurityContextImpl [Authentication=UsernamePasswordAuthenticationToken [Principal=com.nagpal.spring_authn_authz.config.EmployeeUserDetails@2af776cf, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=846F84FABBD0F9B98EFEF4DAAE047AA4], Granted Authorities=[ROLE_ROLE_USER]]]
相关代码
EmployeeUserDetails类
public class EmployeeUserDetails implements UserDetails { private Employee employee; public EmployeeUserDetails(Employee employee) { this.employee = employee; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { List<GrantedAuthority> authorities = new ArrayList<>(); // log.info("Adding role with ROLE_ appended"); GrantedAuthority role = new SimpleGrantedAuthority(/*"ROLE_" + */ employee.getRole()); authorities.add(role); return authorities; } @Override public String getPassword() { return employee.getPassword(); } @Override public String getUsername() { return employee.getEmail(); } // 省略UserDetails接口其他默认实现方法 }
Employee实体类
@Entity @Data public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "employee_id") private int id; @Column private String email; @Column private String password; @Column private String role; }
用户初始化代码
public void customUsers(UserDetailsManager detailsManager) { Employee employee1 = new Employee(); employee1.setEmail("user1@email.com"); employee1.setPassword(passwordEncoder().encode("password")); employee1.setRole("USER"); EmployeeUserDetails user1 = new EmployeeUserDetails(employee1); detailsManager.createUser(user1); }
数据库数据
启动后Employee表中的数据如下:
我无法理解这种行为:不在UserDetails中添加ROLE_前缀时,权限中完全没有该前缀;添加后却出现重复的ROLE_ROLE_前缀,导致授权始终失败,希望能得到解惑。
内容的提问来源于stack exchange,提问作者Bagira

