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