You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot Security @RolesAllowed搭配自定义UserDetailsService报AccessDeniedException

问题根源

你自定义的User类在实现UserDetails接口时,getAuthorities()方法没有正确返回对应用户的权限列表,或是权限标识和@RolesAllowed注解配置的角色不匹配(Spring Security默认会给角色加上ROLE_前缀,和你配置的角色名对应不上就会抛出权限不足异常)。

修复方案

方案1:保留默认前缀,修改对应配置

直接使用Spring Security自带的User构建器构造用户,同时调整@RolesAllowed注解的参数匹配前缀:

  1. 修改UserServiceImpl构造方法:
public UserServiceImpl() {
    BCryptPasswordEncoder encoder=new BCryptPasswordEncoder();
    // 使用Spring Security自带的User构建器,roles方法会自动给角色加ROLE_前缀
    UserDetails user1 = User.withUsername("user1")
            .password(encoder.encode("2005"))
            .roles("DEVELOPER")
            .build();
    UserDetails user2 = User.withUsername("user2")
            .password(encoder.encode("2005"))
            .roles("ADMINISTRATOR")
            .build();
    mapUsers.put(user1.getUsername(), user1);
    mapUsers.put(user2.getUsername(), user2);
}
  1. 调整控制器的权限注解:
@GetMapping("/admin")   
@RolesAllowed("ROLE_ADMINISTRATOR")
public ResponseEntity<?> getWelcomeMsgAdmin(){
    return ResponseEntity.ok("hello admin");
}

@GetMapping("/developer")   
@RolesAllowed("ROLE_DEVELOPER")
public ResponseEntity<?> getWelcomeMsgDeveloper(){
    return ResponseEntity.ok("hello dev");
}

方案2:移除默认前缀,保留原有写法

如果你不想修改现有的@RolesAllowed注解配置,可以新增配置关闭Spring Security默认的ROLE_前缀:

  1. 在安全配置类中新增Bean移除前缀:
@Bean
public GrantedAuthorityDefaults grantedAuthorityDefaults() {
    return new GrantedAuthorityDefaults(""); // 清空默认的角色前缀
}
  1. 修改UserServiceImpl构造方法,直接传入自定义的角色名作为权限:
public UserServiceImpl() {
    BCryptPasswordEncoder encoder=new BCryptPasswordEncoder();
    UserDetails user1 = User.withUsername("user1")
            .password(encoder.encode("2005"))
            .authorities(new SimpleGrantedAuthority("DEVELOPER"))
            .build();
    UserDetails user2 = User.withUsername("user2")
            .password(encoder.encode("2005"))
            .authorities(new SimpleGrantedAuthority("ADMINISTRATOR"))
            .build();
    mapUsers.put(user1.getUsername(), user1);
    mapUsers.put(user2.getUsername(), user2);
}

如果你要继续使用自定义User类

请确保自定义User类的getAuthorities()方法正确返回权限集合,示例实现如下:

public class User implements UserDetails {
    private String username;
    private String password;
    private String role;

    // 构造方法、普通getter省略

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return Collections.singletonList(new SimpleGrantedAuthority(role));
    }

    // 以下四个状态方法全部返回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;}
}

配合方案2的移除前缀配置即可正常使用。

内容的提问来源于stack exchange,提问作者Loga Nathan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 16:36:03