前言
在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 {@Beanpublic 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);}}
}
测试
看一下效果,