图片验证码

在登录界面图形添加验证码

  • 开发生成图像验证码接口
  • 在认证流程中加入图像验证码校验
  • 重构代码

开发生成图像验证码接口

思路:
* 根据随机数生成图片
* 将随机数存到session中
* 将生成的图片写入响应中

这里相当于功能,生成图片什么的不记录了。网上一大堆,记录下这里的一些代码思路

由于是公用的,把该服务写在core中

图片验证码信息类

package cn.mrcode.imooc.springsecurity.securitycore.validate.code;import java.awt.image.BufferedImage;
import java.time.LocalDateTime;/*** 图形验证码* @author : zhuqiang* @version : V1.0* @date : 2018/8/3 22:44*/
public class ImageCode {private BufferedImage image;private String code;private LocalDateTime expireTime; // 过期时间/*** @param image* @param code* @param expireIn 过期时间,单位秒*/public ImageCode(BufferedImage image, String code, int expireIn) {this.image = image;this.code = code;this.expireTime = LocalDateTime.now().plusSeconds(expireIn);}// 是否过期public boolean isExpried() {return this.expireTime.isBefore(LocalDateTime.now());}

验证码服务

package cn.mrcode.imooc.springsecurity.securitycore.validate.code;
/*** 验证码服务* @author : zhuqiang* @version : V1.0* @date : 2018/8/3 22:48*/
@RestController
public class ValidateCodeController {private static final String SESSION_KEY = "SESSION_KEY_IMAGE_CODE";// 这里又使用了spring的工具类来操作sessionprivate SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();@GetMapping("/code/image")public void createCode(HttpServletRequest request, HttpServletResponse response) throws IOException {ImageCode imageCode = createImageCode(request);sessionStrategy.setAttribute(new ServletWebRequest(request), SESSION_KEY, imageCode);response.setContentType("image/jpeg");//禁止图像缓存。response.setHeader("Pragma", "no-cache");response.setHeader("Cache-Control", "no-cache");ImageIO.write(imageCode.getImage(), "JPEG", response.getOutputStream());}private ImageCode createImageCode(HttpServletRequest request) throws IOException {String code = RandomStringUtils.randomAlphanumeric(4);BufferedImage image = createImageCode(80, 40, code);return new ImageCode(image, code, 60);}

需要把该服务路径在 cn.mrcode.imooc.springsecurity.securitybrowser.BrowserSecurityConfig 中配置放行。

在认证流程中加入图像验证码校验

步骤:
由之前的源码的探索发现,只要把过滤器添加到spring现有的过滤器链上就可以了;

  1. 编写验证码过滤器
  2. 放在UsernamePasswordAuthenticationFilter过滤器之前
package cn.mrcode.imooc.springsecurity.securitycore.validate.code;import org.apache.commons.lang3.StringUtils;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.social.connect.web.HttpSessionSessionStrategy;
import org.springframework.social.connect.web.SessionStrategy;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.context.request.ServletWebRequest;
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;/*** 图片验证码验证过滤器* OncePerRequestFilter spring提供的,保证在一个请求中只会被调用一次* @author : zhuqiang* @version : V1.0* @date : 2018/8/3 23:24*/
public class ValidateCodeFilter extends OncePerRequestFilter {// 在初始化本类的地方进行注入// 一般在配置security http的地方进行添加过滤器private AuthenticationFailureHandler failureHandler;private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {// 为登录请求,并且为post请求if (StringUtils.equals("/authentication/form", request.getRequestURI())&& StringUtils.equalsAnyIgnoreCase(request.getMethod(), "post")) {try {validate(request);} catch (ValidateCodeException e) {failureHandler.onAuthenticationFailure(request, response, e);return;}}filterChain.doFilter(request, response);}private void validate(HttpServletRequest request) throws ServletRequestBindingException {// 拿到之前存储的imageCode信息ServletWebRequest swr = new ServletWebRequest(request);ImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(swr, ValidateCodeController.SESSION_KEY);// 又是一个spring中的工具类,// 试问一下,如果不看源码怎么可能知道有这些工具类可用?String codeInRequest = ServletRequestUtils.getStringParameter(request, "imageCode");if (StringUtils.isBlank(codeInRequest)) {throw new ValidateCodeException("验证码的值不能为空");}if (codeInSession == null) {throw new ValidateCodeException("验证码不存在");}if (codeInSession.isExpried()) {sessionStrategy.removeAttribute(swr, ValidateCodeController.SESSION_KEY);throw new ValidateCodeException("验证码已过期");}if (!StringUtils.equals(codeInSession.getCode(), codeInRequest)) {throw new ValidateCodeException("验证码不匹配");}sessionStrategy.removeAttribute(swr, ValidateCodeController.SESSION_KEY);}public AuthenticationFailureHandler getFailureHandler() {return failureHandler;}public void setFailureHandler(AuthenticationFailureHandler failureHandler) {this.failureHandler = failureHandler;}
}

把过滤器添加到现有认证流程中

ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
validateCodeFilter.setFailureHandler(myAuthenticationFailureHandler);
http// 由源码得知,在最前面的是UsernamePasswordAuthenticationFilter.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)// 定义表单登录 - 身份认证的方式.formLogin().loginPage("/authentication/require").loginProcessingUrl("/authentication/form")

还需要注意的一个地方就是myAuthenticationFailureHandler中。因为失败会调用这个处理器;
这里和视频中演示的不一样。不会再把异常信息打印到前段页面了。

后补:视频中不知道什么时候把LoginType变成了json类型,所以会抛出异常

if (securityProperties.getBrowser().getLoginType() == LoginType.JSON) {response.setContentType("application/json;charset=UTF-8");response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());response.getWriter().write(objectMapper.writeValueAsString(exception));
} else {// 在这里失败跳转不回去了。而且异常信息也没有打印出来。父类默认打印了死的一句话// 在这里就不往上面扔了,这里就先当做 defaultFailureUrl 不存在吧// 模拟打印异常信息response.setContentType("text/html;charset=UTF-8");response.sendError(HttpStatus.UNAUTHORIZED.value(),exception.getLocalizedMessage());
//            super.onAuthenticationFailure(request, response, exception);
}

注意: 之前我一直在说,异常了但是不会显示,不知道去哪里了。
这几次调试发现日志不断访问 /error ,好像这个在自己设置了BrowserSecurityConfig的拦截放行路径后,就一致这样了

【Spring Security OAuth2笔记系列】- spring security - 图片验证码相关推荐

  1. 【Spring Security OAuth2笔记系列】- Spring Social第三方登录 - QQ登录下

    qq登录下 前面把所有的代码组件都弄好了.现在可以开启调试了 在这之前你需要有一个qq互联的应用:也就是为了拿到appid和appSecret:自己去qq互联创建一个应用即可 这里讲下本地怎么调试应用 ...

  2. Spring Cloud学习笔记—网关Spring Cloud Gateway官网教程实操练习

    Spring Cloud学习笔记-网关Spring Cloud Gateway官网教程实操练习 1.Spring Cloud Gateway介绍 2.在Spring Tool Suite4或者IDEA ...

  3. Spring Security OAuth2 优雅的集成短信验证码登录以及第三方登录

    基于SpringCloud做微服务架构分布式系统时,OAuth2.0作为认证的业内标准,Spring Security OAuth2也提供了全套的解决方案来支持在Spring Cloud/Spring ...

  4. Spring框架学习笔记(1) ---[spring框架概念 , 初步上手使用Spring , 控制反转 依赖注入初步理解 ]

    spring官网 -->spring官网 spring5.3.12–>spring-framework 在线文档 --> Spring 5.3.12 文章目录 1.Spring概论 ...

  5. Spring Security OAuth2.0_总结_Spring Security OAuth2.0认证授权---springcloud工作笔记157

    技术交流QQ群[JAVA,C++,Python,.NET,BigData,AI]:170933152 开通了个人技术微信公众号:credream,有需要的朋友可以添加相互学习

  6. security工作笔记006---oauth2(spring security)报错method_not_allowed(Request method 'GET' not supported)解决

    JAVA技术交流QQ群:170933152 最近做智慧城市项目,太恶心了...各种不会,个人负责权限验证中心服务,...唉,慢慢研究吧.. 报错信息 <MethodNotAllowed> ...

  7. .NetCore源码阅读笔记系列之Security (一) Authentication AddCookie

    如果你使用过.NetCore开发过程序,你会很清楚,在其中我们经常会用到一些如下的代码 services.AddAuthentication(options =>{options.Default ...

  8. spring boot 2.x 系列 —— spring boot 整合 kafka

    文章目录 一.kafka的相关概念: 1.主题和分区 2.分区复制 3. 生产者 4. 消费者 5.broker和集群 二.项目说明 1.1 项目结构说明 1.2 主要依赖 二. 整合 kafka 2 ...

  9. Spring Boot学习笔记:Spring Boot的Web功能

    文章目录 一.Spring Boot的Web支持 二.Thymeleaf模板引擎 (一)Thymeleaf基础知识 1.引入Thymeleaf 2.访问Model数据 3.Model中的数据迭代 4. ...

最新文章

  1. 如何用python编写一个绘制马赛克图像的自写程序mask = np.zeros
  2. 单机redis 主从实例
  3. orange软件_Orange和戴尔技术公司合作 联合测试和开发5G和商业模式
  4. SQL注入学习——sqli-labs闯关(Basic Challenges)
  5. ImportError: libcublas.so.10.0: cannot open shared object file: No such file or directory
  6. LeetCode OJ - Populating Next Right Pointers in Each Node II
  7. 渗透测试-验证码的爆破与绕过
  8. 广州驾校考试实际道路考试注意事项(图)
  9. activereports_报表 ActiveReports 迎来 .Net Core 时代!一键创建 .Net Core 项目
  10. MYSQL中什么是规范化_数据库设计 - 什么是规范化(或规范化)?
  11. lisp语言与python_5种语言混合编程:C 、JS、python、Lisp、汇编
  12. 城市的灵魂——记董敬明教授讲座
  13. 【初赛】计算机操作系统
  14. Java+Selenium+Chrome、Firefox自动化测试环境搭建
  15. 《数字集成电路物理设计——陈春章》学习笔记
  16. python形态选股_用Python选一个自己的股票池!堪比资深的炒股选手!
  17. 一张图搞懂FreeModbus
  18. MCC 移动设备国家代码 (Mobile country code) 概述 MCC 国家/地区代码 注释 概述 移动设备国家代码 ( Mobile country code / MCC ) 定义于国际
  19. 金融科技企业PingPong发布3.0新产品
  20. 公司局域网无线AP测试方法

热门文章

  1. 在未提供官方驱动的Windows平板上安装Win10且完美驱动的解决方案
  2. xmanager5连接CENTOS6
  3. android 系统相册 多远,【系统相册】Android 保存图片到系统相册
  4. H3C-S5560交换机设置
  5. Modbus RTU笔记总结
  6. 【六更完结!由于字数限制开新文章继续】零基础信号与系统学习笔记:复指数信号、傅里叶级数的系数推导、三角函数正交性、离散傅里叶变换、相位补偿、z变换表、逆变换表、常见序列及其作用
  7. Linux weblogic日志查看tail -f nohup.out
  8. 2020东南大学网络空间安全保研夏令营(预推免)经验
  9. 大学生活质量指北,高考毕业生填报志愿参考必备
  10. torch.bmm(a,b)