Spring Security添加图形验证码
Spring Security添加图形验证码
大致思路:
1.根据随机数生成验证码图片
2.将验证码图片显示到登录页面
3.认证流程中加入验证码校验
依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.social</groupId><artifactId>spring-social-config</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.7</version></dependency>
首先定义一个验证码对象
package com.DNYDYS.validate.code;import java.awt.image.BufferedImage;
import java.time.LocalDateTime;public class ImageCode {//image图片private BufferedImage image;//code验证码private String code;//expireTime过期时间private LocalDateTime expireTime;public ImageCode(BufferedImage image, String code, int expireIn) {this.image = image;this.code = code;this.expireTime = LocalDateTime.now().plusSeconds(expireIn);}public ImageCode(BufferedImage image, String code, LocalDateTime expireTime) {this.image = image;this.code = code;this.expireTime = expireTime;}//判断验证码是否已过期boolean isExpire() {return LocalDateTime.now().isAfter(expireTime);}public BufferedImage getImage() {return image;}public void setImage(BufferedImage image) {this.image = image;}public String getCode() {return code;}public void setCode(String code) {this.code = code;}public LocalDateTime getExpireTime() {return expireTime;}public void setExpireTime(LocalDateTime expireTime) {this.expireTime = expireTime;}
}
处理生成验证码请求
package com.DNYDYS.controller;import com.DNYDYS.validate.code.ImageCode;
import org.springframework.social.connect.web.HttpSessionSessionStrategy;
import org.springframework.social.connect.web.SessionStrategy;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.ServletWebRequest;import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;@RestController
public class ValidateController {public final static String SESSION_KEY_IMAGE_CODE = "SESSION_KEY_IMAGE_CODE";private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();//生成验证码对象@GetMapping("/code/image")public void createCode(HttpServletRequest request, HttpServletResponse response) throws IOException {ImageCode imageCode = createImageCode();sessionStrategy.setAttribute(new ServletWebRequest(request), SESSION_KEY_IMAGE_CODE, imageCode);ImageIO.write(imageCode.getImage(), "jpeg", response.getOutputStream());}private ImageCode createImageCode() {int width = 100; // 验证码图片宽度int height = 36; // 验证码图片长度int length = 4; // 验证码位数int expireIn = 60; // 验证码有效时间 60sBufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);Graphics g = image.getGraphics();Random random = new Random();g.setColor(getRandColor(200, 250));g.fillRect(0, 0, width, height);g.setFont(new Font("Times New Roman", Font.ITALIC, 20));g.setColor(getRandColor(160, 200));for (int i = 0; i < 155; i++) {int x = random.nextInt(width);int y = random.nextInt(height);int xl = random.nextInt(12);int yl = random.nextInt(12);g.drawLine(x, y, x + xl, y + yl);}StringBuilder sRand = new StringBuilder();for (int i = 0; i < length; i++) {String rand = String.valueOf(random.nextInt(10));sRand.append(rand);g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));g.drawString(rand, 13 * i + 6, 16);}g.dispose();return new ImageCode(image, sRand.toString(), expireIn);}private Color getRandColor(int fc, int bc) {Random random = new Random();if (fc > 255)fc = 255;if (bc > 255)bc = 255;int r = fc + random.nextInt(bc - fc);int g = fc + random.nextInt(bc - fc);int b = fc + random.nextInt(bc - fc);return new Color(r, g, b);}}
不被拦截
package com.DNYDYS.security.browser;import com.DNYDYS.handler.MyAuthenticationFailureHandler;
import com.DNYDYS.handler.MyAuthenticationSucessHandler;
import com.DNYDYS.validate.code.ValidateCodeFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate MyAuthenticationSucessHandler authenticationSucessHandler;@Autowiredprivate MyAuthenticationFailureHandler authenticationFailureHandler;@Autowiredprivate ValidateCodeFilter validateCodeFilter;@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加验证码校验过滤器.formLogin() // 表单登录// http.httpBasic() // HTTP Basic.loginPage("/authentication/require") // 登录跳转 URL.loginProcessingUrl("/login") // 处理表单登录 URL.successHandler(authenticationSucessHandler) // 处理登录成功.failureHandler(authenticationFailureHandler) // 处理登录失败.and().authorizeRequests() // 授权配置.antMatchers("/authentication/require","/login.html","/code/image").permitAll() // 无需认证的请求路径.anyRequest() // 所有请求.authenticated() // 都需要认证.and().csrf().disable();}
}
认证流程添加验证码校验
package com.DNYDYS.validate.code;import org.springframework.security.core.AuthenticationException;public class ValidateCodeException extends AuthenticationException {private static final long serialVersionUID = 5022575393500654458L;ValidateCodeException(String message) {super(message);}
}
由于Spring Security并没有直接提供验证码校验相关的过滤器接口,所以我们需要自己定义一个验证码校验的过滤器ValidateCodeFilter
package com.DNYDYS.validate.code;import com.DNYDYS.controller.ValidateController;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.social.connect.web.HttpSessionSessionStrategy;
import org.springframework.social.connect.web.SessionStrategy;
import org.springframework.stereotype.Component;
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;@Component
public class ValidateCodeFilter extends OncePerRequestFilter {@Autowiredprivate AuthenticationFailureHandler authenticationFailureHandler;private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();@Overrideprotected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {if (StringUtils.equalsIgnoreCase("/login", httpServletRequest.getRequestURI())&& StringUtils.equalsIgnoreCase(httpServletRequest.getMethod(), "post")) {try {validateCode(new ServletWebRequest(httpServletRequest));} catch (ValidateCodeException e) {authenticationFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, e);return;}}filterChain.doFilter(httpServletRequest, httpServletResponse);}private void validateCode(ServletWebRequest servletWebRequest) throws ServletRequestBindingException {ImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE);String codeInRequest = ServletRequestUtils.getStringParameter(servletWebRequest.getRequest(), "imageCode");if (StringUtils.isBlank(codeInRequest)) {throw new ValidateCodeException("验证码不能为空!");}if (codeInSession == null) {throw new ValidateCodeException("验证码不存在!");}if (codeInSession.isExpire()) {sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE);throw new ValidateCodeException("验证码已过期!");}if (!StringUtils.equalsIgnoreCase(codeInSession.getCode(), codeInRequest)) {throw new ValidateCodeException("验证码不正确!");}sessionStrategy.removeAttribute(servletWebRequest, ValidateController.SESSION_KEY_IMAGE_CODE);}}
拦截登录接口
package com.DNYDYS.security.browser;import com.DNYDYS.handler.MyAuthenticationFailureHandler;
import com.DNYDYS.handler.MyAuthenticationSucessHandler;
import com.DNYDYS.validate.code.ValidateCodeFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate MyAuthenticationSucessHandler authenticationSucessHandler;@Autowiredprivate MyAuthenticationFailureHandler authenticationFailureHandler;@Autowiredprivate ValidateCodeFilter validateCodeFilter;@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class) // 添加验证码校验过滤器.formLogin() // 表单登录// http.httpBasic() // HTTP Basic.loginPage("/authentication/require") // 登录跳转 URL.loginProcessingUrl("/login") // 处理表单登录 URL.successHandler(authenticationSucessHandler) // 处理登录成功.failureHandler(authenticationFailureHandler) // 处理登录失败.and().authorizeRequests() // 授权配置.antMatchers("/authentication/require","/login.html","/code/image").permitAll() // 无需认证的请求路径.anyRequest() // 所有请求.authenticated() // 都需要认证.and().csrf().disable();}
}
前端页面
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>登录</title>
</head>
<body>
<form class="login-page" action="/login" method="post"><h3>账户登录</h3>用户名:<input type="text" name="username" required="required"/><br>密 码:<input type="password" name="password" required="required"/><br><span style="display: inline">验证码: <input type="text" name="imageCode" /><img src="/code/image"/></span><br><button type="submit">登录</button>
</form>
</body>
</html>
ok 基本齐活
访问页面(真low)
http://localhost:8080/login.html
用户名随便,密码在代码里直接写死了 admin
登录成功
等一分钟,等验证码过期
输入错误的验证码
ok 齐活儿
浮世万千不得有三
水中月镜中花梦中你
月可求花可得
唯你求而不得
Spring Security添加图形验证码相关推荐
- 4.Spring Security 添加图形验证码
添加验证码大致可以分为三个步骤:根据随机数生成验证码图片:将验证码图片显示到登录页面:认证流程中加入验证码校验.Spring Security的认证校验是由UsernamePasswordAuthen ...
- 9.Spring Security添加记住我功能
在网站的登录页面中,记住我选项是一个很常见的功能,勾选记住我后在一段时间内,用户无需进行登录操作就可以访问系统资源.在Spring Security中添加记住我功能很简单,大致过程是:当用户勾选了记住 ...
- 5.Spring Security 短信验证码登录
Spring Security 短信验证码登录 在 Spring Security 添加图形验证码一节中,我们已经实现了基于 Spring Boot + Spring Security 的账号密码登录 ...
- Spring Security 短信验证码登录(5)
在Spring Security添加图形验证码中,我们已经实现了基于Spring Boot + Spring Security的账号密码登录,并集成了图形验证码功能.时下另一种非常常见的网站登录方式为 ...
- SpringSecurity添加图形验证码认证功能
SpringSecurity添加图形验证码认证功能 第一步:图形验证码接口 1.使用第三方的验证码生成工具Kaptcha https://github.com/penggle/kaptcha @Con ...
- spring security 短信验证码登录
短信登录过滤器 SmsAuthenticationFilter import org.springframework.lang.Nullable; import org.springframewo ...
- Spring boot+ Spring security 实现图片验证码验证
springboot+security实现用户权限管理后,登陆要求增加图片验证码 pring security使用众多的过滤器对url进行拦截,以此来进行权限管理.Spring security不允许 ...
- 使用Spring Security添加RememberMe身份验证
我在" 将社交登录添加到Jiwhiz博客"中提到,RememberMe功能不适用于Spring Social Security. 好吧,这是因为该应用程序现在不通过用户名和密码对用 ...
- vue添加图形验证码功能
上图看功能,每点击一次切换验证码!前端判断验证码是否输入,后端判断验证码是否正确! html <el-form-item label="验证码" prop="cod ...
最新文章
- os.system() 和 os.popen()
- html兼容不同屏幕 代码,rem的正确使用姿势 -- 完美解决H5页面不同尺寸屏幕的适配问题...
- Isolation Forest
- 关于Lucene的自定义Sort排序
- RandomizedSearchCV 和GridSearchCV
- shell命令之---LVM文件系统
- java调用python库pyd_Java调用Python的两种方式
- flash加xml图片叠加焦点图,左右箭头翻页
- LeetCode 65. 有效数字(逻辑题,难)
- Web Hacking 101 中文版 十五、代码执行
- VS2008源代码管理软件组合-visualSVN Server+TortoiseSVN+AnkhSvn
- vue store的值刷新就被覆盖解决方案
- 如何为我们的程序编写开发文档——Java文档注释
- hbase mysql hdfs_Alex的Hadoop菜鸟教程:第8课Sqoop1导入Hbase以及Hive
- 整理农行面试软开最常问到的题---------框架
- Jmeter链接MySQL读写数据
- excel减法函数_电子表格减法公式
- Linux I2C 核心、总线、与设备驱动
- php如何把word转图片
- 学习OpenCV3 面阵相机标定方法
热门文章
- 百度语音接口api调用
- Lastpass——密码管理工具
- HTML5/CSS3基础——div盒子水平垂直居中的三种方案
- 基于SpringBoot+Gradle+Zxing+JQuery(原生JS)开发条形码/二维码扫描工具,且采用原生JS调用浏览器摄像头
- excel 宏 加1的计算机,巧用宏命令来为Excel工作表公式加密码 -电脑资料
- createfile 无权限_Microsoft Windows CreateFile API命名管道权限提升漏洞 | 学步园
- 解读《今日头条2018手机行业白皮书》:手机品牌们如何逆周期生长
- ‘堆’出你的洪荒之力
- css和js用哪个,yepnope(相对路径,css和js)的使用
- 【独家】华为OD机试 - 基站维修工程师(C 语言解题)