| | |
| | | import com.walker.web.security.DefaultSecurityMetadataSource; |
| | | import com.walker.web.security.ResourceLoadProvider; |
| | | import com.walker.web.token.JwtTokenGenerator; |
| | | import org.apache.commons.collections4.CollectionUtils; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.boot.web.servlet.FilterRegistrationBean; |
| | | import org.springframework.context.annotation.Bean; |
| | |
| | | import org.springframework.security.access.AccessDecisionManager; |
| | | import org.springframework.security.authentication.AuthenticationManager; |
| | | import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; |
| | | import org.springframework.security.config.annotation.web.ExceptionHandlingDsl; |
| | | import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
| | | import org.springframework.security.config.http.SessionCreationPolicy; |
| | | import org.springframework.security.core.userdetails.UserDetailsService; |
| | |
| | | } |
| | | |
| | | /** |
| | | * HttpSecurity:忽略 antMatchers 中使用的端点的身份验证,其他安全功能将生效。<br></br> |
| | | * WebSecurity:直接忽略也不会进行 CSRF xss等攻击保护。 |
| | | * @param http |
| | | * @return |
| | | * @throws Exception |
| | | */ |
| | | /** |
| | | * HttpSecurity:忽略 antMatchers 中使用的端点的身份验证,其他安全功能将生效。<br></br> |
| | | * WebSecurity:直接忽略也不会进行 CSRF xss等攻击保护。 |
| | | * @param http |
| | |
| | | */ |
| | | @Bean |
| | | public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { |
| | | // 缓存 securityProperties 的结果,避免重复调用 |
| | | SecurityProperties securityProperties = this.securityProperties(); |
| | | |
| | | DefaultUserDetailsService userDetailsService = userDetailsService(this.securityProperties(), this.userCacheProvider); |
| | | DefaultUserDetailsService userDetailsService = userDetailsService(securityProperties, this.userCacheProvider); |
| | | http.userDetailsService(userDetailsService); |
| | | |
| | | // CSRF禁用,因为不使用session |
| | | http.csrf().disable(); |
| | | // ??? |
| | | http.headers().frameOptions().disable(); |
| | | // 注意:禁用CSRF需确保所有接口已通过其他方式保护 |
| | | http.csrf(csrf -> csrf.disable()); |
| | | |
| | | // 登录行为由自己实现,参考 AuthController#login |
| | | http.formLogin().disable().httpBasic().disable(); |
| | | // 禁用frameOptions以支持iframe嵌套 |
| | | // 替换弃用的 headers() 方法 |
| | | http.headers(headers -> headers.frameOptions(frameOptions -> frameOptions.disable())); |
| | | |
| | | // 匿名资源访问权限,返回无权限提示接口 |
| | | http.exceptionHandling().authenticationEntryPoint(failedAuthenticationEntryPoint()) |
| | | // 已认证用户无权限访问配置 |
| | | .accessDeniedHandler(this.accessDeniedHandler()) |
| | | .and() |
| | | // 基于token,所以不需要session |
| | | .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); |
| | | // 禁用默认登录和HTTP Basic认证 |
| | | http.formLogin(formLogin -> formLogin.disable()); |
| | | |
| | | // http.formLogin().loginProcessingUrl("/login") |
| | | // .failureHandler(this.authenticationFailureHandler()); |
| | | // 注意:这里不能配置上面的登录,否则就不会执行自己实现的/login方法。2022-11-11 |
| | | http.logout().logoutUrl("/logout").logoutSuccessHandler(this.logoutSuccessHandler()).permitAll(); |
| | | // 异常处理配置 |
| | | http.exceptionHandling(exceptionHandling -> exceptionHandling |
| | | .authenticationEntryPoint(failedAuthenticationEntryPoint()) |
| | | .accessDeniedHandler(this.accessDeniedHandler())); |
| | | |
| | | // 匿名访问集合,2022-11-07 |
| | | List<String> anonymousList = this.securityProperties().getAnonymousList(); |
| | | if(!StringUtils.isEmptyList(anonymousList)){ |
| | | http.authorizeHttpRequests().antMatchers(anonymousList.toArray(new String[]{})).permitAll(); |
| | | } |
| | | // http.authorizeHttpRequests().antMatchers("/login", "/register", "/captchaImage", "/test/**").permitAll(); |
| | | // http.authorizeHttpRequests().antMatchers("/static/**", "/test/**").permitAll(); |
| | | // http.authorizeHttpRequests().antMatchers("/security/**").hasAuthority("query_user"); |
| | | // 基于token,所以不需要session |
| | | http.sessionManagement(sessionManagement -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); |
| | | |
| | | // 2023-03-21 注释掉,调试activiti7时发现和下面重复, |
| | | // http.addFilterBefore(securityInterceptor(), FilterSecurityInterceptor.class); |
| | | /*http.authorizeHttpRequests().withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>(){ |
| | | @Override |
| | | public <O extends FilterSecurityInterceptor> O postProcess(O object) { |
| | | object.setAccessDecisionManager(accessDecisionManager());//决策管理器 |
| | | object.setSecurityMetadataSource(securityMetadataSource());//安全元数据源 |
| | | return object; |
| | | } |
| | | });*/ |
| | | // 登出配置 |
| | | http.logout(logout -> logout |
| | | .logoutUrl("/logout") |
| | | .logoutSuccessHandler(this.logoutSuccessHandler()) |
| | | .permitAll()); |
| | | |
| | | // 2023-01-28 配置自定义认证提供者(密码验证用) |
| | | http.authenticationProvider(this.authenticationProvider(userDetailsService, securityProperties())); |
| | | // 配置匿名访问权限 |
| | | configureAnonymousAccess(http, securityProperties); |
| | | |
| | | // 配置自定义认证提供者 |
| | | http.authenticationProvider(this.authenticationProvider(userDetailsService, securityProperties)); |
| | | |
| | | // 所有请求都需要认证 |
| | | http.authorizeHttpRequests().anyRequest().authenticated(); |
| | | // 使用自定义动态拦截器,拦截所有权限请求,2022-11-02 |
| | | http.authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests.anyRequest().authenticated()); |
| | | |
| | | // 添加自定义动态拦截器 |
| | | http.addFilterBefore(securityInterceptor(), FilterSecurityInterceptor.class); |
| | | |
| | | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | // token拦截过滤器,2022-11-02 |
| | | // 必须在这里添加拦截,不能放在'FilterSecurityInterceptor'之后,因为如果放在之后,那么就无法获得用户信息,从而无法 |
| | | // 获得用户所具有的权限角色集合:roleIdList。2022-11-14(2) |
| | | // 添加JWT认证过滤器 |
| | | http.addFilterBefore(jwtAuthenticationTokenFilter(userDetailsService), UsernamePasswordAuthenticationFilter.class); |
| | | // http.addFilterBefore(jwtAuthenticationTokenFilter(), DefaultAuthenticationFilter.class); |
| | | // 尝试让jwt在URL权限之后才拦截, 2022-11-14(1) |
| | | // 注意:以上 UsernamePasswordAuthenticationFilter 需要去掉才能生效 |
| | | // http.addFilterAfter(jwtAuthenticationTokenFilter(), FilterSecurityInterceptor.class); |
| | | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | if(this.securityProperties().isCorsEnabled()){ |
| | | // 解决跨域过滤器,2022-11-06 |
| | | http.addFilterBefore(this.corsFilter().getFilter(), JwtAuthenticationTokenFilter.class); |
| | | // 未知?2022-11-11 |
| | | http.addFilterBefore(this.corsFilter().getFilter(), LogoutFilter.class); |
| | | } else { |
| | | System.out.println("不添加跨域过滤器: "); |
| | | } |
| | | // 配置跨域过滤器 |
| | | configureCorsFilter(http, securityProperties); |
| | | |
| | | return http.build(); |
| | | } |
| | | |
| | | /** |
| | | * 配置匿名访问权限 |
| | | */ |
| | | private void configureAnonymousAccess(HttpSecurity http, SecurityProperties securityProperties) throws Exception { |
| | | List<String> anonymousList = securityProperties.getAnonymousList(); |
| | | if (!CollectionUtils.isEmpty(anonymousList)) { |
| | | http.authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests |
| | | .requestMatchers(anonymousList.toArray(new String[0])).permitAll()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 配置跨域过滤器 |
| | | */ |
| | | private void configureCorsFilter(HttpSecurity http, SecurityProperties securityProperties) throws Exception { |
| | | if (securityProperties.isCorsEnabled()) { |
| | | CorsFilter corsFilter = this.corsFilter().getFilter(); |
| | | if (corsFilter != null) { |
| | | http.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class) |
| | | .addFilterBefore(corsFilter, LogoutFilter.class); |
| | | logger.info("跨域过滤器已启用"); |
| | | } else { |
| | | logger.warn("跨域过滤器未正确初始化"); |
| | | } |
| | | } else { |
| | | logger.info("跨域过滤器未启用"); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取AuthenticationManager(认证管理器),登录时认证使用 |
| | | * @param authenticationConfiguration |
| | | * @return |