SpringBoot整合Spring Security,使用Session方式的验证码(六)

╰半夏微凉° 2022-12-10 02:28 241阅读 0赞

一、导入验证码库的依赖

  1. <dependency>
  2. <groupId>com.github.penggle</groupId>
  3. <artifactId>kaptcha</artifactId>
  4. <version>2.3.2</version>
  5. <exclusions>
  6. <exclusion>
  7. <artifactId>javax.servlet-api</artifactId>
  8. <groupId>javax.servlet</groupId>
  9. </exclusion>
  10. </exclusions>
  11. </dependency>

二、然后写一个kaptcha.properties配置文件:

  1. kaptcha.border=no
  2. kaptcha.border.color=105,179,90
  3. kaptcha.image.width=100
  4. kaptcha.image.height=45
  5. kaptcha.session.key=code
  6. kaptcha.textproducer.font.color=blue
  7. kaptcha.textproducer.font.size=35
  8. kaptcha.textproducer.char.length=4
  9. kaptcha.textproducer.font.names=宋体,楷体,微软雅黑

需要注意的是这里的中文可能是乱码,改下文件格式即可:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2JhaWt1bmxvbmc_size_16_color_FFFFFF_t_70

三、配置验证码生成类

  1. package com.example.securityzimug.config.auth.imagecode;
  2. import com.google.code.kaptcha.impl.DefaultKaptcha;
  3. import com.google.code.kaptcha.util.Config;
  4. import org.springframework.beans.factory.annotation.Value;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.context.annotation.Configuration;
  7. import org.springframework.context.annotation.PropertySource;
  8. import java.util.Properties;
  9. /**
  10. * @author baikunlong
  11. * @date 2020/9/23 15:34
  12. */
  13. @Configuration
  14. @PropertySource(value = {"classpath:kaptcha.properties"})
  15. public class CaptchaConfig {
  16. @Value("${kaptcha.border}")
  17. private String border;
  18. @Value("${kaptcha.border.color}")
  19. private String borderColor;
  20. @Value("${kaptcha.textproducer.font.color}")
  21. private String fontColor;
  22. @Value("${kaptcha.image.width}")
  23. private String imageWidth;
  24. @Value("${kaptcha.image.height}")
  25. private String imageHeight;
  26. @Value("${kaptcha.session.key}")
  27. private String sessionKey;
  28. @Value("${kaptcha.textproducer.char.length}")
  29. private String charLength;
  30. @Value("${kaptcha.textproducer.font.names}")
  31. private String fontNames;
  32. @Value("${kaptcha.textproducer.font.size}")
  33. private String fontSize;
  34. @Bean
  35. public DefaultKaptcha getKaptchaBean(){
  36. DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
  37. Properties properties = new Properties();
  38. properties.setProperty("kaptcha.border", border);
  39. properties.setProperty("kaptcha.border.color", borderColor);
  40. properties.setProperty("kaptcha.textproducer.font.color", fontColor);
  41. properties.setProperty("kaptcha.image.width", imageWidth);
  42. properties.setProperty("kaptcha.image.height", imageHeight);
  43. properties.setProperty("kaptcha.session.key", sessionKey);
  44. properties.setProperty("kaptcha.textproducer.char.length", charLength);
  45. properties.setProperty("kaptcha.textproducer.font.names", fontNames);
  46. properties.setProperty("kaptcha.textproducer.font.size",fontSize);
  47. defaultKaptcha.setConfig(new Config(properties));
  48. return defaultKaptcha;
  49. }
  50. }

四、编写验证码vo

  1. package com.example.securityzimug.config.auth.imagecode;
  2. import java.time.LocalDateTime;
  3. public class CaptchaCode {
  4. /**
  5. * 验证码
  6. */
  7. private String code;
  8. /**
  9. * 过期时间
  10. */
  11. private LocalDateTime expireTime;
  12. public CaptchaCode(String code, int expireAfterSeconds){
  13. this.code = code;
  14. this.expireTime = LocalDateTime.now().plusSeconds(expireAfterSeconds);
  15. }
  16. /**
  17. * 是否过期
  18. * @return
  19. */
  20. public boolean isExpired(){
  21. return LocalDateTime.now().isAfter(expireTime);
  22. }
  23. public String getCode() {
  24. return code;
  25. }
  26. }

五、编写控制器

  1. package com.example.securityzimug.controller;
  2. import com.example.securityzimug.config.auth.imagecode.CaptchaCode;
  3. import com.google.code.kaptcha.impl.DefaultKaptcha;
  4. import org.springframework.web.bind.annotation.RequestMapping;
  5. import org.springframework.web.bind.annotation.RequestMethod;
  6. import org.springframework.web.bind.annotation.RestController;
  7. import javax.annotation.Resource;
  8. import javax.imageio.ImageIO;
  9. import javax.servlet.ServletOutputStream;
  10. import javax.servlet.http.HttpServletResponse;
  11. import javax.servlet.http.HttpSession;
  12. import java.awt.image.BufferedImage;
  13. import java.io.IOException;
  14. @RestController
  15. public class CaptchaController {
  16. @Resource
  17. DefaultKaptcha captchaProducer;
  18. @RequestMapping(value="/kaptcha",method = RequestMethod.GET)
  19. public void kaptcha(HttpSession session, HttpServletResponse response) throws IOException {
  20. response.setDateHeader("Expires", 0);
  21. response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
  22. response.addHeader("Cache-Control", "post-check=0, pre-check=0");
  23. response.setHeader("Pragma", "no-cache");
  24. response.setContentType("image/jpeg");
  25. String capText = captchaProducer.createText();
  26. session.setAttribute(MyContants.CAPTCHA_SESSION_KEY,new CaptchaCode(capText,60));
  27. try(ServletOutputStream out = response.getOutputStream()){
  28. BufferedImage bufferedImage = captchaProducer.createImage(capText);
  29. ImageIO.write(bufferedImage,"jpg",out);
  30. out.flush();
  31. }
  32. }
  33. }

这里用到了一个常量类,到时候做验证码判断时用的比较多:

  1. package com.example.securityzimug.utils;
  2. public class MyContants {
  3. public static final String CAPTCHA_SESSION_KEY = "captcha_key";
  4. public static final String SMS_SESSION_KEY = "sms_key";
  5. }

六、开放验证码接口权限

20200923155708521.png

七、修改登录页

  1. <form action="/login" method="post">
  2. <span>用户名称</span><input type="text" name="uname" id="username"/> <br>
  3. <span>用户密码</span><input type="password" name="pword" id="password"/> <br>
  4. <span>验证码</span><input type="text" name="captchaCode" id="captchaCode"/>
  5. <img src="/kaptcha" id="kaptcha" width="110px" height="40px"/> <br>
  6. <input type="button" onclick="login()" value="登陆">
  7. <!-- <input type="submit" value="登陆">-->
  8. <label><input type="checkbox" name="remember-me" id="remember-me"/>记住密码</label>
  9. </form>

编写点击验证码刷新

  1. window.onload = function () {
  2. var kaptchaImg = document.getElementById("kaptcha");
  3. kaptchaImg.onclick = function () {
  4. kaptchaImg.src = "/kaptcha?" + Math.floor(Math.random() * 100)
  5. }
  6. };

到这里我们已经实现了验证码的刷新了:

20200923161619483.png

八、编写验证码过滤器

  1. package com.example.securityzimug.config.auth.imagecode;
  2. import com.example.securityzimug.config.auth.MyAuthenticationFailureHandler;
  3. import com.example.securityzimug.utils.MyContants;
  4. import org.springframework.security.core.AuthenticationException;
  5. import org.springframework.security.web.authentication.session.SessionAuthenticationException;
  6. import org.springframework.stereotype.Component;
  7. import org.springframework.util.StringUtils;
  8. import org.springframework.web.filter.OncePerRequestFilter;
  9. import javax.annotation.Resource;
  10. import javax.servlet.FilterChain;
  11. import javax.servlet.ServletException;
  12. import javax.servlet.http.HttpServletRequest;
  13. import javax.servlet.http.HttpServletResponse;
  14. import java.io.IOException;
  15. /**
  16. * @author baikunlong
  17. * @date 2020/9/23 16:17
  18. */
  19. @Component
  20. public class CaptchaCodeFilter extends OncePerRequestFilter {
  21. @Resource
  22. MyAuthenticationFailureHandler myAuthenticationFailureHandler;
  23. @Override
  24. protected void doFilterInternal(HttpServletRequest request, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
  25. if("/login".equals(request.getRequestURI())&&request.getMethod().equalsIgnoreCase("post")){
  26. try {
  27. validate(request);
  28. } catch (AuthenticationException e) {
  29. //交给自定义处理器处理
  30. myAuthenticationFailureHandler.onAuthenticationFailure(request,httpServletResponse,e);
  31. //直接返回,过滤器链不再往下执行
  32. return;
  33. }
  34. }
  35. filterChain.doFilter(request,httpServletResponse);
  36. }
  37. private void validate(HttpServletRequest request) {
  38. //用户输入的验证码
  39. String captchaInRequest = request.getParameter("captchaCode");
  40. //session里的验证码对象
  41. CaptchaCode captchaInSession = (CaptchaCode) request.getSession().getAttribute(MyContants.CAPTCHA_SESSION_KEY);
  42. if(StringUtils.isEmpty(captchaInRequest)){
  43. throw new SessionAuthenticationException("验证码不能为空");
  44. }
  45. if(captchaInSession==null){
  46. throw new SessionAuthenticationException("验证码不存在");
  47. }
  48. if(captchaInSession.isExpired()){
  49. request.getSession().removeAttribute(MyContants.CAPTCHA_SESSION_KEY);
  50. throw new SessionAuthenticationException("验证码已经过期");
  51. }
  52. if(!captchaInSession.getCode().equalsIgnoreCase(captchaInRequest)){
  53. throw new SessionAuthenticationException("验证码错误");
  54. }
  55. }
  56. }

然后在自定义的那个失败处理器里处理下验证码错误的信息:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2JhaWt1bmxvbmc_size_16_color_FFFFFF_t_70 1

然后在配置类里注入过滤器:

  1. @Resource
  2. CaptchaCodeFilter captchaCodeFilter;

然后配置过滤器执行顺序:

  1. //配置验证码过滤器执行时间,设置在用户名密码校验之前
  2. http.addFilterBefore(captchaCodeFilter, UsernamePasswordAuthenticationFilter.class);

最后在登录页面加入验证码的提交就行了:

  1. function login() {
  2. var username = $("#username").val();
  3. var password = $("#password").val();
  4. var captchaCode = $("#captchaCode").val();
  5. var rememberMe = $("#remember-me").is(":checked");
  6. if (username === "" || password === "") {
  7. alert('用户名或密码不能为空');
  8. return;
  9. }
  10. $.ajax({
  11. type: "POST",
  12. url: "/login",
  13. data: {
  14. "uname": username,
  15. "pword": password,
  16. "captchaCode": captchaCode,
  17. "remember-me-new": rememberMe
  18. },
  19. success: function (json) {
  20. if(json.isok){
  21. location.href = json.data;
  22. }else{
  23. alert(json.message)
  24. }
  25. },
  26. error: function (e) {
  27. console.log(e.responseText);
  28. }
  29. });
  30. }

发表评论

表情:
评论列表 (有 0 条评论,241人围观)

还没有评论,来说两句吧...

相关阅读