1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > SpringBoot 实现登录验证码(附集成SpringSecurity)

SpringBoot 实现登录验证码(附集成SpringSecurity)

时间:2024-03-11 22:29:04

相关推荐

SpringBoot 实现登录验证码(附集成SpringSecurity)

SpringBoot 实现登录验证码

1. 生成验证码的工具类2. 验证码测试接口3. 验证码过滤器4. Spring Security配置类引入验证码过滤器5. 效果图

1. 生成验证码的工具类

这个工具类很常见,网上也有很多,就是画一个简单的验证码,通过流将验证码写到前端页面。

import javax.imageio.ImageIO;import java.awt.*;import java.awt.image.BufferedImage;import java.io.IOException;import java.io.OutputStream;import java.util.Random;/*** @Author: gaoyang* @Date: /7/8 14:20* @Description: 生成验证码的工具类*/public class VerificationCode {private int width = 100;// 生成验证码图片的宽度private int height = 30;// 生成验证码图片的高度private String[] fontNames = {"宋体", "楷体", "隶书", "微软雅黑" };private Color bgColor = new Color(255, 255, 255);// 定义验证码图片的背景颜色为白色private Random random = new Random();private String codes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";private String text;// 记录随机字符串/*** 获取一个随意颜色** @return*/private Color randomColor() {int red = random.nextInt(150);int green = random.nextInt(150);int blue = random.nextInt(150);return new Color(red, green, blue);}/*** 获取一个随机字体** @return*/private Font randomFont() {String name = fontNames[random.nextInt(fontNames.length)];int style = random.nextInt(4);int size = random.nextInt(5) + 24;return new Font(name, style, size);}/*** 获取一个随机字符** @return*/private char randomChar() {return codes.charAt(random.nextInt(codes.length()));}/*** 创建一个空白的BufferedImage对象** @return*/private BufferedImage createImage() {BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);Graphics2D g2 = (Graphics2D) image.getGraphics();g2.setColor(bgColor);// 设置验证码图片的背景颜色g2.fillRect(0, 0, width, height);return image;}public BufferedImage getImage() {BufferedImage image = createImage();Graphics2D g2 = (Graphics2D) image.getGraphics();StringBuffer sb = new StringBuffer();for (int i = 0; i < 4; i++) {String s = randomChar() + "";sb.append(s);g2.setColor(randomColor());g2.setFont(randomFont());float x = i * width * 1.0f / 4;g2.drawString(s, x, height - 8);}this.text = sb.toString();drawLine(image);return image;}/*** 绘制干扰线** @param image*/private void drawLine(BufferedImage image) {Graphics2D g2 = (Graphics2D) image.getGraphics();int num = 5;for (int i = 0; i < num; i++) {int x1 = random.nextInt(width);int y1 = random.nextInt(height);int x2 = random.nextInt(width);int y2 = random.nextInt(height);g2.setColor(randomColor());g2.setStroke(new BasicStroke(1.5f));g2.drawLine(x1, y1, x2, y2);}}public String getText() {return text;}public static void output(BufferedImage image, OutputStream out) throws IOException {ImageIO.write(image, "JPEG", out);}}

2. 验证码测试接口

import com.javaboy.vhr.utils.RespBean;import com.javaboy.vhr.utils.VerificationCode;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import java.awt.image.BufferedImage;import java.io.IOException;/*** @Author: gaoyang* @Date: /10/24 15:05* @Description:*/@Api(tags = "未登录API")@RestControllerpublic class LoginController {@ApiOperation(value = "生成验证码图片")@GetMapping("/verifyCode")public void verifyCode(HttpServletRequest request, HttpServletResponse resp) throws IOException {VerificationCode code = new VerificationCode();BufferedImage image = code.getImage();String text = code.getText();HttpSession session = request.getSession(true);session.setAttribute("verify_code", text);VerificationCode.output(image,resp.getOutputStream());}}

到这验证码生成已经实现,下面是集成到SpringSecurity需要做的事情。

3. 验证码过滤器

import com.fasterxml.jackson.databind.ObjectMapper;import com.javaboy.vhr.utils.RespBean;import org.ponent;import javax.servlet.*;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;/*** @author: gaoyang* @date: -12-27 14:20* @description: 验证码过滤器*/@Componentpublic class VerificationCodeFilter extends GenericFilter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest) servletRequest;HttpServletResponse resp = (HttpServletResponse) servletResponse;if ("POST".equals(req.getMethod()) && "/doLogin".equals(req.getServletPath())) {//登录请求String code = req.getParameter("code");String verify_code = (String) req.getSession().getAttribute("verify_code");if (code == null || "".equals(code) || !verify_code.toLowerCase().equals(code.toLowerCase())) {//验证码不正确resp.setContentType("application/json;charset=utf-8");PrintWriter out = resp.getWriter();out.write(new ObjectMapper().writeValueAsString(RespBean.error("验证码错误!")));out.flush();out.close();return;} else {filterChain.doFilter(req, resp);}} else {filterChain.doFilter(req, resp);}}}

自定义过滤器继承自 GenericFilterBean,并实现其中的 doFilter 方法,在 doFilter 方法中,当请求方法是 POST,并且请求地址是 /doLogin 时,获取参数中的 code 字段值,该字段保存了用户从前端页面传来的验证码,然后获取 session 中保存的验证码,如果用户没有传来验证码,则抛出验证码不能为空异常,如果用户传入了验证码,则判断验证码是否正确,如果不正确则抛出异常,否则执行 chain.doFilter(request, response); 使请求继续向下走。

4. Spring Security配置类引入验证码过滤器

@Configurationpublic class SecurityConfig extends WebSecurityConfigurerAdapter {@Resourceprivate VerificationCodeFilter verificationCodeFilter;@Overridepublic void configure(WebSecurity web) throws Exception {web.ignoring().antMatchers("/verifyCode");}@Overrideprotected void configure(HttpSecurity http) throws Exception {// 验证码拦截器http.addFilterBefore(verificationCodeFilter, UsernamePasswordAuthenticationFilter.class);http.authorizeRequests().antMatchers("/admin/**").hasRole("admin").......permitAll().and().csrf().disable();}}

这里只贴出了部分核心代码,即http.addFilterBefore(verifyCodeFilter, UsernamePasswordAuthenticationFilter.class);,如此之后,整个配置就算完成了。

接下来在登录中,就需要传入验证码了,如果不传或者传错,都会抛出异常,例如不传的话,抛出如下异常:

5. 效果图

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。