前言
在spring boot security自定义认证一文,基本给出了一个完整的自定义的用户登录认证的示例,但是未涉及到验证的使用,本文介绍登录的时候如何使用验证码。
本文介绍一个验证码生成工具,比较老的一个库了,仅作demo使用,不太建议生产用了,因为如果你的代码需要进行安全扫描,这个库已经不再维护了,如果扫出漏洞,也没法升级修复了。
但是如果没有安全扫描的要求,还是可以用的。
github: https://github.com/penggle/kaptcha
代码示例
引入依赖
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
定义验证码生成器
@Configuration
public class CaptchaConfiguration {
@Bean
public Producer defaultKaptcha() {
Properties properties = new Properties();
// 还有一些其它属性,可以进行源码自己看相关配置,比较清楚了,根据变量名也能猜出来什么意思了
properties.setProperty(Constants.KAPTCHA_IMAGE_WIDTH, "150");
properties.setProperty(Constants.KAPTCHA_IMAGE_HEIGHT, "50");
properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_STRING, "0123456789abcdefghigklmnopqrstuvwxyz");
properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
Config config = new Config(properties);
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}
示例是作为spring 的bean注册到spring 容器了,当然也可以作为一个单例对象放到一个静态类里。
定义获取验证码及认证接口
这个接口在前面的文章里已经提到过了,这里只是完善验证码的部分.
@RequestMapping("/login")
@RestController
public class LoginController {
private final AuthenticationManager authenticationManager;
private final Producer producer;
public LoginController(AuthenticationManager authenticationManager, Producer producer) {
this.authenticationManager = authenticationManager;
this.producer = producer;
}
@PostMapping()
public Object login(@RequestBody User user, HttpSession session) {
Object captcha = session.getAttribute(Constants.KAPTCHA_SESSION_KEY);
if (captcha == null || !captcha.toString().equalsIgnoreCase(user.getCaptcha())) {
return "captcha is not correct.";
}
try {
// 使用定义的AuthenticationManager进行认证处理
Authentication authenticate = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword()));
// 认证通过,设置到当前上下文,如果当前认证过程后续还有处理的逻辑需要的话。这个示例是没有必要了
SecurityContextHolder.getContext().setAuthentication(authenticate);
return "login success";
} catch (Exception e) {
return "login failed";
}
}
/**
* 获取验证码,需要的话,可以提供一个验证码获取的接口,在上面的login里把验证码传进来进行比对
*/
@GetMapping("/captcha")
public void captcha(HttpServletResponse response, HttpSession session) throws IOException {
response.setContentType("image/jpeg");
String text = producer.createText();
session.setAttribute(Constants.KAPTCHA_SESSION_KEY, text);
BufferedImage image = producer.createImage(text);
try (ServletOutputStream out = response.getOutputStream()) {
ImageIO.write(image, "jpg", out);
}
}
}
测试
看一下效果,