SpringSecurity 增加Filter过滤器
配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | package com.imooc.security.browser; import com.imooc.security.core.properties.SecurityProperties; import com.imooc.security.core.validate.code.ValidateCodeFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private AuthenticationSuccessHandler imoocAuthenticationSuccessHandler; @Autowired private AuthenticationFailureHandler imoocAuthenctiationFailureHandler; @Bean public PasswordEncoder passwordEncoder() { return new SCryptPasswordEncoder(); } @Autowired private SecurityProperties securityProperties; @Override public void configure(HttpSecurity http) throws Exception { // 验证码过滤器 ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter(); validateCodeFilter.setAuthenticationFailureHandler(imoocAuthenctiationFailureHandler); validateCodeFilter.setSecurityProperties(securityProperties); validateCodeFilter.afterPropertiesSet(); // 添加一个图片验证filter, 在UsernamePasswordAuthenticationFilter之前执行 http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter. class ) // .httpBasic() // 默认方式 .formLogin() // 设置认证的登录方式 表单方式 .loginPage( "/authentication/require" ) // 自定义登录页面 .loginProcessingUrl( "/authentication/form" ) // 自定义表单url, 默认是login .successHandler(imoocAuthenticationSuccessHandler) // 不适用默认的认证成功处理器 .failureHandler(imoocAuthenctiationFailureHandler) // 登录失败处理器 // .failureForwardUrl("/authentication/require") // .failureUrl("/authentication/require") .and() .authorizeRequests() // 需要授权 // 当匹配到这个页面时,不需要授权 .antMatchers( "/authentication/require" , securityProperties.getBrowser().getLoginPage(), "/code/image" ).permitAll() .anyRequest() // 所有请求 .authenticated() .and() // 关闭csrf .csrf() .disable(); } } |
Filter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | package com.imooc.security.core.validate.code; import com.imooc.security.core.properties.SecurityProperties; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.InitializingBean; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.social.connect.web.HttpSessionSessionStrategy; import org.springframework.social.connect.web.SessionStrategy; import org.springframework.util.AntPathMatcher; import org.springframework.web.bind.ServletRequestBindingException; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.HashSet; import java.util.Set; /** * OncePerRequestFilter 只会调用一次Filter */ public class ValidateCodeFilter extends OncePerRequestFilter implements InitializingBean { private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); private Set<String> urls = new HashSet<>(); private SecurityProperties securityProperties; public void setSecurityProperties(SecurityProperties securityProperties) { this .securityProperties = securityProperties; } private AuthenticationFailureHandler authenticationFailureHandler; private AntPathMatcher pathMatcher = new AntPathMatcher(); // 加载完配置文件之后,获取所有需要使用验证码的url @Override public void afterPropertiesSet() throws ServletException { super .afterPropertiesSet(); String[] configUrls = StringUtils.splitByWholeSeparatorPreserveAllTokens(securityProperties.getCode().getImage().getUrl(), "," ); for (String url : configUrls) { urls.add(url); } urls.add( "/authentication/form" ); } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { boolean action = false ; for (String url : urls) { if (pathMatcher.match(url, request.getRequestURI())) action = true ; } if (action) { try { validate( new ServletWebRequest(request)); } catch (ValidateCodeException e) { authenticationFailureHandler.onAuthenticationFailure(request, response, e); return ; } } filterChain.doFilter(request, response); } public void validate(ServletWebRequest request) throws ServletRequestBindingException { ImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(request, ValidateCodeController.SESSION_KEY); String codeInRequest = ServletRequestUtils.getStringParameter(request.getRequest(), "imageCode" ); if (StringUtils.isBlank(codeInRequest)) { throw new ValidateCodeException( "验证码的值不能为空" ); } if (codeInRequest == null ) { throw new ValidateCodeException( "验证码不存在" ); } if (codeInSession.isExpried()) { sessionStrategy.removeAttribute(request, ValidateCodeController.SESSION_KEY); throw new ValidateCodeException( "验证码已过期" ); } if (!StringUtils.equals(codeInSession.getCode(), codeInRequest)) { throw new ValidateCodeException( "验证码不匹配" ); } sessionStrategy.removeAttribute(request, ValidateCodeController.SESSION_KEY); } public void setAuthenticationFailureHandler(AuthenticationFailureHandler authenticationFailureHandler) { this .authenticationFailureHandler = authenticationFailureHandler; } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义