验证码生成工具可以使用hutool依赖库进行。
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.captcha.generator.MathGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
@Controller
public class CaptchaController {
@GetMapping(value = "code/getCaptchaCode")
public void getCaptchaCode(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse) throws IOException {
//ShearCaptcha shearCaptcha = CaptchaUtil.createShearCaptcha(200, 100, 4, 5);
CircleCaptcha circleCaptcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 1000);
circleCaptcha.setGenerator(new MathGenerator());
String code = circleCaptcha.getCode();
log.info("生成的图片验证码为:{}",code);
//将验证码存储到session中
httpServletRequest.getSession().setAttribute("CAPTCHA CODE",code);
httpServletResponse.setContentType("image/png");
//将图片写到响应流里
ImageIO.write(circleCaptcha.getImage(),"PNG",httpServletResponse.getOutputStream());
}
}
写好验证码之后即可在WebSecurity实现配置类中将验证码接口放开:
import com.example.springsecuritystudy4.filter.ValidateCodeFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.annotation.Resource;
@Slf4j
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.mvcMatchers("/code/getCaptchaCode") //将验证码接口放开
.permitAll()
.anyRequest()
.authenticated();
http.formLogin()
.loginPage("/toLogin") // 配置登录页面
.usernameParameter("uname") // 用户名参数
.passwordParameter("pwd") // 密码参数
.loginProcessingUrl("/login/doLogin") //单击登录后进入url
.failureForwardUrl("/toLogin") // 登录失败
.successForwardUrl("/toIndex") //登录成功
.permitAll(); //放开
http.logout().logoutSuccessUrl("/toLogin"); //配置退出成功登录页面
http.csrf().disable(); //关闭跨域请求保护
}
}
过滤器需要继承实现OncePerRequestFilter接口。以下为实现例子
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
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;
@Slf4j
@Component
public class ValidateCodeFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// TODO 判断路径 是否是/login/doLogin
String requestURL = request.getRequestURI();
if(!requestURL.equals("/login/doLogin")){ //不是登录请求,直接放行
doFilter(request,response,filterChain);
}
}
private void validateCode(HttpServletRequest request,HttpServletResponse response,FilterChain filterChain) throws ServletException, IOException {
//TODO 1、从前端获取验证码
String code = request.getParameter("code");
//TODO 2、从session中获取验证码
String captchaCode = (String) request.getSession().getAttribute("CAPTCHA_CODE");
//TODO 3、判断二者是否相等
if(StringUtils.isEmpty(code)){
request.getSession().setAttribute("captcha_code_error","请输入验证码");
return;
}
if(StringUtils.isEmpty(captchaCode)){
request.getSession().setAttribute("captcha_code_error","验证码错误");
}
request.getSession().setAttribute("CAPTCHA_CODE","");
this.doFilter(request,response,filterChain);
}
}
写好过滤器后即可在配置类里面使用过滤器:
import com.example.springsecuritystudy4.filter.ValidateCodeFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.annotation.Resource;
@Slf4j
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
ValidateCodeFilter validateCodeFilter;
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//在用户名密码认证过滤器前添加验证码过滤器
http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class);
http.authorizeRequests()
.mvcMatchers("/code/getCaptchaCode")
.permitAll()
.anyRequest()
.authenticated();
http.formLogin()
.loginPage("/toLogin") // 配置登录页面
.usernameParameter("uname") // 用户名参数
.passwordParameter("pwd") // 密码参数
.loginProcessingUrl("/login/doLogin") //单击登录后进入url
.failureForwardUrl("/toLogin") // 登录失败
.successForwardUrl("/toIndex") //登录成功
.permitAll(); //放开
http.logout().logoutSuccessUrl("/toLogin"); //配置退出成功登录页面
http.csrf().disable(); //关闭跨域请求保护
}
}