spring security的权限不生效

权限不生效,配置类如下:


```java
@Configuration
//@EnableGlobalMethodSecurity(prePostEnabled = true) //开启全局安全认证
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private UserDetailsService userDetailsService;

    @Resource
    private AuthenticationHandler authenticationHandler;

    @Resource
    private AuthenticationTokenFilter AuthenticationTokenFilter;

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(HttpMethod.OPTIONS,"/**");

    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
//        http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
        http

                // CSRF禁用,因为不使用session
                .csrf().disable()
                // 认证失败处理类,指定异常处理实现类
                .exceptionHandling().authenticationEntryPoint(authenticationHandler).and()
                // 基于token,所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                // 过滤请求
                .authorizeRequests()
//                .antMatchers("/admin/**")
//                //.hasRole("ADMIN")
//                .hasAnyRole("ADMIN")
                //.mvcMatchers("/admin/**").hasRole("admin")
                //.antMatchers("/admin/**").hasRole("ROLE_admin")   //访问/admin/**下的路径,必须具备admin身份
//                .antMatchers("/ordinary/**").hasRole("ordinary") //访问/ordinary/**下的路径,必须具备user身份
                //对于登录login 验证码 允许匿名访问
                .antMatchers("/user/getcode", "/user/login","/login/**").permitAll()
                .antMatchers("/admin/**").hasAnyAuthority("admin")
                //其他全部拦截认证
                .anyRequest()
                .authenticated();


        //将认证过滤器添加到security中
        http.addFilterBefore(AuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }

    /**
     * 设置加密方式
     *
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    //授权时去掉默认角色前缀"ROLE_"
    @Bean
    GrantedAuthorityDefaults grantedAuthorityDefaults() {
        return new GrantedAuthorityDefaults(""); // Remove the ROLE_ prefix
    }
}

接口:
@Slf4j
@RestController
@RequestMapping("/admin")
@CrossOrigin //关闭跨域验证
public class AdminTestController {

    //@PreAuthorize("hasAnyRole('ADMIN')")
    //@PreAuthorize("hasAuthority('PERMISSION_TEST')")
    //@Secured({"admin:select"})
    @GetMapping("/test")
    public R test() {
        return R.success("admin权限测试成功");
    }

}

权限:

```java
@AllArgsConstructor
@NoArgsConstructor
@Data
public class LoginUser implements UserDetails {


    private TUser tUser;

    private List<SimpleGrantedAuthority> roles;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return AuthorityUtils.commaSeparatedStringToAuthorityList("admin,nobks");
    }

    @Override
    public String getPassword() {
        String pass=tUser.getPassword();
        tUser.setPassword("禁止查看");
        return pass;
    }

    @Override
    public String getUsername() {
        return tUser.getUsername();
    }

    /**
     * 账户是否过期
     * @return
     */
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    /**
     * 账户是否锁定
     * @return
     */
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

登录后未设置权限的接口正常,但是有权限的就是403

img


从上下文中拿出的用户信息如下:

img

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 这个问题的回答你可以参考下: https://ask.csdn.net/questions/732801
  • 你也可以参考下这篇文章:Spring Security源码(七):设计模式在框架中的应用
  • 除此之外, 这篇博客: Spring Security 中,想在权限中使用通配符,怎么做?中的 3. 权限通配符 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:

    看明白了上面的逻辑,现在不用我说,大家也知道权限通配符在 Spring Security 中是不支持的(无论你在 @PreAuthorize 注解中写的 SpEL 是哪个,调用的是哪个方法,都是不支持权限通配符的)。

    例如我现在这样描述我的用户权限:

    @Bean
    UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager m = new InMemoryUserDetailsManager();
        m.createUser(User.withUsername("javaboy").password("{noop}123").authorities("system:user:*").build());
        return m;
    }
    

    我想用 system:user:* 字符串表示 javaboy 具有针对用户的所有权限。

    直接这样写肯定是不行的,最终字符串比较一定是不会通过的。

    那么怎么办呢?用正则似乎也不太行,因为 * 在正则中不代表所有字符,如果拆解字符串去比较,功能虽然也行得通,但是比较麻烦。

    想来想去,想到一个办法,不知道小伙伴们是否还记得我们之前在 vhr 中用过的 AntPathMatcher,用这个不就行了!

    修改后的 CustomPermissionEvaluator 如下:

    @Component
    public class CustomPermissionEvaluator implements PermissionEvaluator {
    
        AntPathMatcher antPathMatcher = new AntPathMatcher();
    
        @Override
        public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
            Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
            for (GrantedAuthority authority : authorities) {
                if (antPathMatcher.match(authority.getAuthority(), (String) permission)) {
                    return true;
                }
            }
            return false;
        }
    
        @Override
        public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
            return false;
        }
    }
    

    修改之后,现在只要用户具备 system:user:* 权限,就四个接口都能访问了。

  • 您还可以看一下 银文杰老师的Spring Security 实战精讲——基础篇课程中的 代码详细解读:自定义投票者(1)小节, 巩固相关知识点
  • 以下回答来自chatgpt:

    解决方案:

    在这个配置中,您设置了一些接口需要特定的角色才能访问。但是,您提到即使在登录后,您从上下文中获取的用户信息也没有角色信息。这可能意味着您没有正确设置用户的角色信息,也可能是您的角色信息源并未工作。

    以下是您可以采取的措施:

    1.验证用户角色信息源是否起作用

    在您的配置中,您指定了一个MyUserDetailsService来从数据库中获取用户信息。您需要确保该服务正确设置了用户角色信息。您可以测试该角色源是否工作,方法是从数据库中获取具有适当权限的用户并尝试登录到应用程序中。如果您登录成功并且能够访问受限制的接口,那么可以确认该角色源工作正常。

    2.使用内存角色存储

    另一种方法是将角色信息存储在内存中。以下是一个示例(仅供参考):

    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .antMatchers("/user/**").hasRole("USER")
                .anyRequest().permitAll()
                .and().formLogin();
        }
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication()
                .withUser("user1").password("{noop}password").roles("USER")
                .and()
                .withUser("admin1").password("{noop}password").roles("ADMIN");
        }
    
    }
    

    上述代码将在内存中配置两个用户:user1和admin1。它们都有一个密码password和相应的角色USER和ADMIN。请注意,这在生产环境中是不安全的,仅用于测试目的。

    3.排除Spring Boot自动配置

    如果您使用了Spring Boot,并且您的配置类文件位于应用程序的主包下,则可能会发生Spring Boot自动配置的冲突。为了解决这个问题,请在您的配置类上使用@EnableWebSecurity(debug = true)查看执行链。

    4.添加Spring Security依赖关系

    请更新您的项目依赖关系以包含所需版本的Spring Security。

    最后,我建议您仔细查看Spring Security文档,特别是有关提供角色信息源的部分。他们提供了许多示例和最佳实践,这有助于您更好地理解并解决这个问题。如果我无法提供有用的解决方案,请不要犹豫联系我。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^