spring security自定义授权,权限校验总为false

spring security自定义授权,权限校验总为false

@Component("rbacService")
public class RBACService {
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        Object principal = authentication.getPrincipal();
        if (principal instanceof LoginUser) {//instanceof编译器会检查 obj 是否能转换成右边的class类型
            LoginUser LoginUser = (LoginUser) principal;
            //req.getRequestURI() 当前请求的路径
            SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(request.getRequestURI());
            //userDetails.getAuthorities() // 用户所拥有的所有资源
            Collection<? extends GrantedAuthority> authorities = LoginUser.getAuthorities();

            System.out.println(simpleGrantedAuthority);
            // 输出:/api/test1
            System.out.println(authorities);
            // 输出:[{"authority":"/api/test1"}, {"authority":"/api/test2"}, {"authority":"/api/test3"}, {"authority":"/api/test4"}]
            boolean contains = authorities.contains(simpleGrantedAuthority);
            System.out.println(contains);
            // 输出:false(问题1:存在权限也为false?)
            return contains;
        }
        return false;
    }
}

问题2:一次请求RBACService却被调用两次,这是为何?
第二次被调用的截图:

img

security配置类如下:

@Configuration
 @EnableWebSecurity
public class SecurityConfiguration {
     @Autowired
     private JwtAuthenticationFilter jwtAuthenticationFilter;
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
        return http
                // 跨域配置
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                // 配置路径是否需要认证
                // .authorizeHttpRequests()
                .authorizeRequests()
                // 允许匿名访问
                .antMatchers("/api/auth/**").permitAll()
                // 注意:.anyRequest()只能出现一次,否则报错:Caused by: java.lang.IllegalStateException: Can't configure anyRequest after itself
                .anyRequest().access("@rbacService.hasPermission(request,authentication)")
                .and()
                //关闭csrf (注意:允许匿名访问,但不关闭csrf访问也是报403)
                .cors().configurationSource(this.corsConfigurationSource())
                .and()
                // 禁用缓存,使用无状态session,即不使用session缓存数据
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                // 添加JWT过滤器
                .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
                .build();
    }

    /**
     *跨域资源配置
     */
    @Bean
    public CorsConfigurationSource corsConfigurationSource(){
        CorsConfiguration cors = new CorsConfiguration();
        cors.addAllowedOriginPattern("*");
        // TODO 正式项目为保安全须设置cors
        // cors.setAllowedOriginPatterns(List.of("http://192.168.1.6:8887"));
        cors.setAllowCredentials(true);
        cors.addAllowedHeader("*");
        cors.addAllowedMethod("*");
        cors.addExposedHeader("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", cors);
        return source;
    }

     @Bean
     public PasswordEncoder passwordEncoder(){
         return new BCryptPasswordEncoder();
     }

     /**
      * TODO 四 4.4 基于用户名和密码或使用用户名和密码进行身份验证
      * @param config
      * @return
      * @throws Exception
      */
     @Bean
     public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
         return config.getAuthenticationManager();
     }
}
Spring Security 中的自定义授权权限校验总为 false 时,需要确保权限字符串格式正确,权限控制器绑定正确,自定义权限校验器能够正确地进行权限校验。
可能有以下几个原因:
1. 权限字符串格式问题

首先,我们需要确保权限字符串的格式正确。在授权时,我们可以将角色和权限都表示成字符串,Spring Security 需要通过这些字符串来判断用户是否具有某些角色或权限。例如,我们可以将管理员设定为 `ROLE_ADMIN` 这样的字符串,然后将 `hasRole('ROLE_ADMIN')` 作为表达式来进行校验。

如果权限字符串的格式不正确,那么就会导致授权校验失败。请检查权限字符串的格式是否正确。

2. 权限控制器绑定问题

其次,我们需要确保自定义的权限控制器被正确地绑定到了 Spring Security 中。为了在 Spring Security 中生效,我们需要将自定义的权限控制器进行注册,例如,我们可以在 `WebSecurityConfig` 中进行注册:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 
    @Autowired
    private CustomPermissionEvaluator permissionEvaluator;
 
    @Override
    public void configure(WebSecurity web) throws Exception {
        // 注册自定义的权限控制器
        DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
        handler.setPermissionEvaluator(permissionEvaluator);
        web.expressionHandler(handler);
    }
    
    // ... 其它配置代码
}

在上述代码中,我们通过 `DefaultWebSecurityExpressionHandler` 将自定义的权限控制器绑定到了 Spring Security 中。

3. 自定义权限校验器问题

最后,我们需要确保自定义的权限校验器能够正确地进行权限校验。在 Spring Security 中,我们可以通过自定义的 PermissionEvaluator 来对权限进行校验。在校验过程中,会调用 `hasPermission()` 方法,如果该方法返回 false,那么就会导致授权校验失败。

一种可能的情况是,我们在自定义的 PermissionEvaluator 中实现了 `hasPermission()` 方法,但是没有正确地将其注册到了 Spring Security 中。为了使自定义的 PermissionEvaluator 生效,我们需要在 `WebSecurityConfig` 中完成如下配置:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 
    @Autowired
    private CustomPermissionEvaluator permissionEvaluator;
 
    @Override
    public void configure(WebSecurity web) throws Exception {
        // 注册自定义的权限控制器
        DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
        handler.setPermissionEvaluator(permissionEvaluator);
        web.expressionHandler(handler);
    }
    
    // 注册自定义的 PermissionEvaluator
    @Bean
    public DefaultMethodSecurityExpressionHandler createExpressionHandler() {
        DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
        expressionHandler.setPermissionEvaluator(permissionEvaluator);
        return expressionHandler;
    }
    
    // ... 其它配置代码
}
在上述代码中,通过 `DefaultMethodSecurityExpressionHandler` 来注册自定义的 PermissionEvaluator