代码地址如下:
http://www.demodashi.com/demo/14280.html
Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
Spring Security的核心功能就是对用户进行身份认证和授权。而他的认证机制就是通过Spring Security一系列的过滤器链,当一个请求来的时候,首先要通过过滤器链的校验,校验通过之后才会访问用户各种信息
。
但是在进行一些登录,注册等操作的时候,往往还需要使用验证码来进行校验。本案例采用的面向接口编程,将自定义的验证码过滤器添加到Spring Security的过滤器链上来实现灵活的,可扩展,可重用,可配置的验证码验证。
public class ImageCode{
private BufferedImage image;
//失效时间
private LocalDateTime expireTime;
//验证码
private String code;
public ImageCode(BufferedImage image, String code, int expireIn){
this.code = code;
this.expireTime = LocalDateTime.now().plusSeconds(expireIn);
this.image = image;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public LocalDateTime getExpireTime() {
return expireTime;
}
public void setExpireTime(LocalDateTime expireTime) {
this.expireTime = expireTime;
}
public BufferedImage getImage() {
return image;
}
public void setImage(BufferedImage image) {
this.image = image;
}
public boolean isExpried() {
return LocalDateTime.now().isAfter(expireTime);
}
}
@ConfigurationProperties(prefix = "jcohy.security")
public class SecurityProperties {
/**
* 验证码配置
*/
private ValidateCodeProperties validateCode = new ValidateCodeProperties();
public ValidateCodeProperties getValidateCode() {
return validateCode;
}
public void setValidateCode(ValidateCodeProperties validateCode) {
this.validateCode = validateCode;
}
}
public class ValidateCodeProperties {
/**
* 图片验证码选项
*/
private ImageCodeProperties imageCode = new ImageCodeProperties();
public ImageCodeProperties getImageCode() {
return imageCode;
}
public void setImageCode(ImageCodeProperties imageCode) {
this.imageCode = imageCode;
}
}
public class ImageCodeProperties{
private int length = 4;
private int expireIn = 60;
/**
* 验证码的宽
*/
private int width = 67;
/**
* 验证码的高
*/
private int height = 23;
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public int getExpireIn() {
return expireIn;
}
public void setExpireIn(int expireIn) {
this.expireIn = expireIn;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
@Configuration
@EnableConfigurationProperties(SecurityProperties.class)
public class PropertiesConfig {
}
其优先级如下:请求级配置>应用级配置>默认配置。当前一个存在时,会覆盖后面的配置。
public interface ValidateCodeGenerator {
/**
* 图形验证码实现方法接口
* @param request
* @return
*/
ImageCode generate(ServletWebRequest request);
}
public class ImageCodeGenerator implements ValidateCodeGenerator{
/**
* 系统配置
*/
@Autowired
private SecurityProperties securityProperties;
@Override
public ImageCode generate(ServletWebRequest request) {
....
....
//绘制并生成图片验证码过程
....
....
}
public SecurityProperties getSecurityProperties() {
return securityProperties;
}
public void setSecurityProperties(SecurityProperties securityProperties) {
this.securityProperties = securityProperties;
}
}
@Component("validateCodeFilter")
public class ValidateCodeFilter extends OncePerRequestFilter implements InitializingBean {
/**
* 验证码校验失败处理器
*/
private AuthenticationFailureHandler authenticationFailureHandler;
private SecurityProperties securityProperties;
private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
//需要进行验证的的请求地址。
private Set<String> urls = new HashSet<>();
/**
* 验证请求url与配置的url是否匹配的工具类
*/
private AntPathMatcher pathMatcher = new AntPathMatcher();
@Override
public void afterPropertiesSet() throws ServletException {
super.afterPropertiesSet();
//“/authentication/form”为登录请求。
urls.add("/authentication/form");
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
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;
}
}
chain.doFilter(request, response);
}
private void validate(ServletWebRequest request) throws ServletRequestBindingException {
ImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(request, UserController.SESSION_KEY);
String codeInRequest;
try {
codeInRequest = ServletRequestUtils.getStringParameter(request.getRequest(),
"imageCode");
} catch (ServletRequestBindingException e) {
throw new ValidateCodeException("获取验证码的值失败");
}
if (StringUtils.isBlank(codeInRequest)) {
throw new ValidateCodeException("imageCode:验证码的值不能为空");
}
if (codeInSession == null) {
throw new ValidateCodeException("imageCode:验证码不存在");
}
if (codeInSession.isExpried()) {
sessionStrategy.removeAttribute(request,UserController.SESSION_KEY);
throw new ValidateCodeException("imageCode: 验证码已过期");
}
if (!StringUtils.equals(codeInSession.getCode(), codeInRequest)) {
throw new ValidateCodeException("imageCode:验证码不匹配");
}
sessionStrategy.removeAttribute(request,UserController.SESSION_KEY);
}
public AuthenticationFailureHandler getAuthenticationFailureHandler() {
return authenticationFailureHandler;
}
public void setAuthenticationFailureHandler(AuthenticationFailureHandler authenticationFailureHandler) {
this.authenticationFailureHandler = authenticationFailureHandler;
}
public SecurityProperties getSecurityProperties() {
return securityProperties;
}
public void setSecurityProperties(SecurityProperties securityProperties) {
this.securityProperties = securityProperties;
}
}
@Configuration
public class ValidateCodeBeanConfig {
@Autowired
private SecurityProperties securityProperties;
//条件匹配。此处可扩展其他的验证条件和相应生成器
@Bean
@ConditionalOnMissingBean(name = "imageCodeGenerator")
public ValidateCodeGenerator imageCodeGenerator(){
ImageCodeGenerator imageCodeGenerator = new ImageCodeGenerator();
imageCodeGenerator.setSecurityProperties(securityProperties);
return imageCodeGenerator;
}
}
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 验证码校验失败处理器
*/
@Autowired
private AuthenticationFailureHandler authenticationFailureHandler;
@Autowired
private AuthenticationSuccessHandler JcohyAuthenticationSuccessHandler;
/**
* 系统配置信息
*/
@Autowired
private SecurityProperties securityProperties;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
validateCodeFilter.setAuthenticationFailureHandler(authenticationFailureHandler);
validateCodeFilter.setSecurityProperties(securityProperties);
validateCodeFilter.afterPropertiesSet();
http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
.formLogin()
.loginPage("/signIn.html")
.loginProcessingUrl("/authentication/form")
.successHandler(JcohyAuthenticationSuccessHandler)
.and()
.authorizeRequests()
.antMatchers("/signIn.html"
,"/code/image").permitAll()
.anyRequest()
.authenticated()
.and()
.csrf().disable();
}
}
代码地址如下:
http://www.demodashi.com/demo/14280.html
注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权
原文:https://www.cnblogs.com/demodashi/p/10474061.html