SpringSecurity 增加Filter过滤器
配置类
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
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;
}
}

浙公网安备 33010602011771号