- 修改CustomAuthenticationFailureHandler类和CustomAuthenticationSuccessHandler
# 将实现接口AuthenticationSuccessHandler修改为SavedRequestAwareAuthenticationSuccessHandler
@Component("customAuthenticationSuccessHandler")
public class CustomAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
System.out.println("CustomAuthenticationSuccessHandler ---> 认证成功");
}
}
@Component("customAuthenticationFailureHandler")
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
System.out.println("CustomAuthenticationFailureHandler ---> 认证失败");
}
}
# core模块导入依赖
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
</dependency>
# core模块编写配置类KaptchaImageCodeConfig
@Configuration
public class KaptchaImageCodeConfig {
@Bean
public DefaultKaptcha getDefaultKaptcha(){
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
properties.setProperty(Constants.KAPTCHA_BORDER, "yes");
properties.setProperty(Constants.KAPTCHA_BORDER_COLOR, "192,192,192");
properties.setProperty(Constants.KAPTCHA_IMAGE_WIDTH, "110");
properties.setProperty(Constants.KAPTCHA_IMAGE_HEIGHT, "36");
properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE, "28");
properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_NAMES, "宋体");
properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
// 图片效果
properties.setProperty(Constants.KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}
# 编写CustomLoginController获取验证码
@Controller
public class CustomLoginController {
Logger logger = LoggerFactory.getLogger(getClass());
public static final String SESSION_KEY = "SESSION_KEY_IMAGE_CODE";
@Autowired
private DefaultKaptcha defaultKaptcha;
// 获取图形验证码
@RequestMapping("/code/image")
public void imageCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 1. 获取验证码字符串
String code = defaultKaptcha.createText();
logger.info("生成的图形验证码是:" + code);
// 2. 字符串把它放到session中
request.getSession().setAttribute(SESSION_KEY , code);
// 3. 获取验证码图片
BufferedImage image = defaultKaptcha.createImage(code);
// 4. 将验证码图片把它写出去
ServletOutputStream out = response.getOutputStream();
ImageIO.write(image, "jpg", out);
}
}
# 前端获取发送请求获取
GET http://localhost:8080/code/image HTTP/1.1
# core模块的SpringSecurityConfig中放行获取图形验证码的接口
# code模块编写ImageCodeValidateFilter、ValidateCodeException
@Component("imageCodeValidateFilter")
public class ImageCodeValidateFilter extends OncePerRequestFilter {
Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String sessionCode =
(String)request.getSession().getAttribute(CustomLoginController.SESSION_KEY);
// 获取用户输入的验证码
String inpuCode = request.getParameter("code");
logger.info("session中的验证码为:" + sessionCode);
logger.info("登录时输入的验证码为:" + inpuCode);
// 认证路径
String loginUrl = "/login";
// 1. 如果是post方式 的登录请求,则校验输入的验证码是否正确
if(loginUrl.equals(request.getRequestURI())
&& request.getMethod().equalsIgnoreCase("post")) {
try {
// 校验验证码合法性
validate(request);
}catch (AuthenticationException e) {
// 交给失败处理器进行处理异常
customAuthenticationFailureHandler.onAuthenticationFailure(request, response, e);
// 一定要记得结束
return;
}
}
// 放行请求
filterChain.doFilter(request, response);
}
private void validate(HttpServletRequest request) {
// 先获取seesion中的验证码
String sessionCode =
(String)request.getSession().getAttribute(CustomLoginController.SESSION_KEY);
// 获取用户输入的验证码
String inpuCode = request.getParameter("code");
logger.info("session中的验证码为:" + sessionCode);
logger.info("登录时输入的验证码为:" + inpuCode);
// 判断是否正确
if(StringUtils.isBlank(inpuCode)) {
throw new ValidateCodeException("验证码不能为空");
}
if(!inpuCode.equalsIgnoreCase(sessionCode)) {
throw new ValidateCodeException("验证码输入错误");
}
}
}
# code模块的SpringSecurityConfig中添加如下:注入过滤器,并添加到UsernamePasswordAuthenticationFilter过滤器前
@Autowired
private ImageCodeValidateFilter imageCodeValidateFilter;
.addFilterBefore(imageCodeValidateFilter, UsernamePasswordAuthenticationFilter.class)
# 测试:使用用户名 + 密码 + 图形验证码进行认证
POST http://localhost:8080/login?username=admin&password=admin&code=b2bf HTTP/1.1