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 ...
最新文章
- HP-UX crontab: you are not authorized to use cron
- IT常说的协议指的是什么?—Vecloud微云
- GNS3 cloud 连接错误_远程桌面连接服务器身份验证错误要求的函数不受支持
- 敏捷开发的45个好习惯
- java导出excel文件名_怎么解决java导出excel时文件名乱码
- mysql中常见的几种索引
- windows IIS Web服务器 发布网站
- windows系统引导配置命令
- 第十六届中国研究生电子设计竞赛记录
- 微信公众号用秀米网插入视频
- 如何用Python快速优雅的批量修改Word文档样式?
- 520了,用32做个简单的小程序
- SpringDataRedis使用
- 客户端登录阿里云mysql数据库_Mysql数据库之数据库术语和客户端登陆
- 提升效率之如何打印出漂亮的带颜色的日志(输出高亮)
- tp5:为什么find()出来的数据有时候可以用toArray() 有时候会报错?
- C++ Primer Plus (第六版)编程练习记录(chapter14 C++中的代码重用)
- Linux聊天室项目知识整理(一)
- mysql 分销提成计算_销售人员工资计算表-2017销售人员工资提成计算表免费版-东坡下载...
- 安徽汽车网程序员删库跑路?不,真相是这样!