spring-security源码阅读-总结(二十六)

spring-security很重?

身边一提到spring-security,都觉得很重,宁愿自己写个filter快速实现认证,确实如此吗,spring-security本质也是基于servlet-filter作为切入点。作为框架,把正常验证流程差异化的地方都封装抽象出来了。

我们只需要根据他的每个差异化的地方完成我们自己的配置就行了。但是学习成本会高一点。

spring-security的配置是如何实现的?

HttpSecurity内部存储了一个List config接口 比如

    public CorsConfigurer<HttpSecurity> cors() throws Exception {
        return getOrApply(new CorsConfigurer<>());
    }

getOrApply会找结合里面有没有定义过这个元素,如果没定义则new一个并添加,定义了则返回集合里面存在的。

然后我们基于CorsConfigurer就可以自己这个过滤器的自定义配置了。当调用and 就返回HttpSecurity当前对象,继续.其他配置设置。最后HttpSecurity的build方法会遍历这些config的config方法,生成Filter

spring security每个filter都有自己的抽象,所以每个config都有自己的.配置

   @Bean
    protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
        // 登出
        httpSecurity
                // 开启跨域
                .cors().and()
                // CSRF 禁用,因为不使用 Session
                .csrf().disable()
                // 基于 token 机制,所以不需要 Session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .headers().frameOptions().disable().and()
                // 一堆自定义的 Spring Security 处理器
                .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
                .accessDeniedHandler(accessDeniedHandler);
   
        // 获得 @PermitAll 带来的 URL 列表,免登录
        Multimap<HttpMethod, String> permitAllUrls = getPermitAllUrlsFromAnnotations();
        // 设置每个请求的权限
        httpSecurity
                // ①:全局共享规则
                //
                .authorizeRequests()
                // 1.1 静态资源,可匿名访问
                .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
                // 1.2 设置 @PermitAll 无需认证
                //FilterSecurityInterceptor 拦截处理 封装spel,root对象为SecurityExpressionOperations对象 交给el执行permitAll表达式就是调用方法
                .antMatchers(HttpMethod.GET, permitAllUrls.get(HttpMethod.GET).toArray(new String[0])).permitAll()
                .antMatchers(HttpMethod.POST, permitAllUrls.get(HttpMethod.POST).toArray(new String[0])).permitAll()
                .antMatchers(HttpMethod.PUT, permitAllUrls.get(HttpMethod.PUT).toArray(new String[0])).permitAll()
                .antMatchers(HttpMethod.DELETE, permitAllUrls.get(HttpMethod.DELETE).toArray(new String[0])).permitAll()
                // 1.3 基于 yudao.security.permit-all-urls 无需认证
                .antMatchers(securityProperties.getPermitAllUrls().toArray(new String[0])).permitAll()
                // 1.4 设置 App API 无需认证
                .antMatchers(buildAppApi("/**")).permitAll()
                // ②:每个项目的自定义规则
                .and().authorizeRequests(registry -> // 下面,循环设置自定义规则
                        authorizeRequestsCustomizers.forEach(customizer -> customizer.customize(registry)))
                // ③:兜底规则,必须认证
                .authorizeRequests()
                .anyRequest().authenticated()
        ;

        // 添加 Token Filter
        httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        return httpSecurity.build();
    }

WebSecurity和HttpSecurty的关系?

WebSecurity就是WebSecurityConfigurerAdapter的父类,HttpSecurty由WebSecurity构建。我们重写WebSecurityConfigurerAdapter的configure可以拿到HttpSecurty,就可以手动添加filter或者基于现有的filter做一些定制化配置

spring-security如何实现身份认证的?

 1.首先根据我们的配置看走哪个filter链,httpsecurity是支持配置针对哪些url生效的比如(默认**/**),一个httpSecurity代表一个链路,

 httpSecurity.antMatcher("/product/*")
                // 开启跨域
                .cors().and()
                // CSRF 禁用,因为不使用 Session
                .csrf().disable()
                // 基于 token 机制,所以不需要 Session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .headers().frameOptions().disable().and()
                // 一堆自定义的 Spring Security 处理器
                .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
                .accessDeniedHandler(accessDeniedHandler);

2.然后是我们配置的哪些接口无需认证,走ExpressionUrlAuthorizationConfigurer的构建filter。

   httpSecurity
                // ①:全局共享规则
                //
                .authorizeRequests()
                // 1.1 静态资源,可匿名访问
                .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
                // 1.2 设置 @PermitAll 无需认证
                //FilterSecurityInterceptor 拦截处理 封装spel,root对象为SecurityExpressionOperations对象 交给el执行permitAll表达式就是调用方法
                .antMatchers(HttpMethod.GET, permitAllUrls.get(HttpMethod.GET).toArray(new String[0])).permitAll()
                .antMatchers(HttpMethod.POST, permitAllUrls.get(HttpMethod.POST).toArray(new String[0])).permitAll()
                .antMatchers(HttpMethod.PUT, permitAllUrls.get(HttpMethod.PUT).toArray(new String[0])).permitAll()
                .antMatchers(HttpMethod.DELETE, permitAllUrls.get(HttpMethod.DELETE).toArray(new String[0])).permitAll()
                // 1.3 基于 yudao.security.permit-all-urls 无需认证
                .antMatchers(securityProperties.getPermitAllUrls().toArray(new String[0])).permitAll()
                // 1.4 设置 App API 无需认证
                .antMatchers(buildAppApi("/**")).permitAll()
                // ②:每个项目的自定义规则
                .and().authorizeRequests(registry -> // 下面,循环设置自定义规则
                        authorizeRequestsCustomizers.forEach(customizer -> customizer.customize(registry)))
                // ③:兜底规则,必须认证
                .authorizeRequests()
                .anyRequest().authenticated()
        ;

支持多个配置,其实后面对应的filter是完成url匹配调用一个实体的方法

3.然后走我们后续的认证filter

posted @ 2024-03-10 11:45  意犹未尽  阅读(41)  评论(0编辑  收藏  举报