微人事中的验证码实现

前言

  说到登录,我相信大家最常见的首先是输入用户名和密码,然后输入程序生成的验证码完成登录;其次就是通过JWT实现鉴权了。在我的Springboot整合Jwt实现用户认证中,详细地介绍了如何简要地实现JWT鉴权。本篇我会介绍微人事中的验证码登录实现以及实现流程。

1.实现流程

  1. 首先是创建验证码实体类,生成验证码图片、字符串,显示验证码图像
  2. 过滤验证码,验证用户输入验证码和存入session中验证码是否一致,如果相同放行
  3. 编写响应接口,传递给前端接口

2.验证码实体类

  1. 该类中会定义验证码图片的宽度、高度、字体、背景颜色、随机生成数、随机字符串验证码范围、以及输出的字符串
  2. 随机生成颜色、字体、字符
  3. 创建一个空白的BufferedImage对象,用来显示生成的验证码相关信息
  4. 生成显示的验证码图片对象
  5. 绘制验证码中的干扰线
  6. 获取字符文本,最后输出图片

    具体实现代码如下:

复制代码
public class VerificationCode{
    private int width=100;
    private int height=30;
    private String[] fontNames= {"宋体", "楷书", "隶书", "微软雅黑"}
    private Color bgColor = new Color(255, 255, 255);
    private Ramdom random = new Random();
    private codes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private String text;
    //生成随机颜色
    private Color randomColor(){
        int red = random.nextInt(150);
        int green = random.nextInt(150);
        int blue = random.nextInt(150);
        return new Color(red, green, blue);
    }
    //生成随机字体
    private Font randomFont(){
        int name = fontNames[random.nextInt(fontNames.lengt)];
        int style = random.nextInt(4);
        int size = random.nextInt(5)+24;
        return new Font(name, style, size);
    }
    //生成随机字符
    private chat randomChar(){
        return codes.charAt(random.nextInt(codes, length));
    }
    //声称要一个空白的BufferedImage对象
    private BufferedImage createImage(){
    BufferedImage image = new BufferedeImage(width, height, BufferedImage.Type_INT_RGB);
        Graphics2D g2 = (Graphics2D)image.getGraphics();
        g2.setColor(bgColor);
        //fillRect(x, y, width, height)绘制直方图
        g2.fillRect(0, 0, width, height);
        return image;
    }
     //生成验证码BufferedImage对象
    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, y, height - 8);
        }
        this.text = sb.toString();
        //调用绘制干扰线的方法
        drawLine(image);
        return image;
    }
    //绘制干扰线
    private void draw(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 our) throws IOException{
        ImageIO.write(image, "JPEG", out);
    }
}
生成验证码实体类
复制代码

3.登录过滤

  1. 在这个登录过滤类LoginFilter中,我们继承UsernamePasswordAuthenticationFiletr类,并重写该类中的attempAuthentication()方法
  2. 首先判断这次登录的方法是不是POST方法,如果是放行,不是报错AuthenticationException,并显示不支持除POST方法以外的方法
  3. 从session中获取verify_code验证码
  4. 再判断请求的浏览的是内容格式是不是MediaType.APPLICATION_JSON_VALUE和MediaType.APPLICATION_JSON_UTF8_VALUE其中一种,如果是,进行下面操作
  5. 接着定义一个loginData集合用于存放用户信息,并使用ObjectMappper对象将请求的用户信息反序列化为Java对象存放于loginData集合中
  6. 从loginData集合中获取验证码与用户输入的验证码核对,如果相同,放行;再获取用户的用户名和密码(如果为空设置为空),将其作为UsernamePasswordAuthenticationToken的参数生成该类对象
  7. 最后根据登录用户的ID和用户信息赋值sessionRegistry管理session会话并发控制,返回认证信息

    具体实现代码如下:

复制代码
 1 public class LoginFilter extends UsernamePasswordAuthenticationFilter{
 2     @Autowried
 3     SessionRegistry sessionRegistry;
 4     public Authentication attempAuthentication(HttpServletRequest request, HttpServletResponse response){
 5         if(!request.getMethod.equals("POST")){
 6              throw new AuthenticationException("Authentication not support"+request.getMethod());
 7         }
 8         String verify_code = (String)request.getSession.getAttribute("verify_code"); 
 9   
10 if(request.contenType.equals(MediaType.APPLICATION_JSON_VALUE || MediaType.APPLICATION_JSON_VALUE)){
11              Map<String, String>loginData = new HashMap<>();
12              try{
13                      loginDta = new ObjectMapper().readValue(request.getInputStream(),Map.class);
14                      }catch(IOException e){
15                      }finally{
16                          String code = loginData.get("code");
17                          check(response, code, verify_code);
18                      }
19                      //从用户信息中获取用户名和密码
20                      String username = loginData.get("username");
21                      String password = loginData.get("password");
22                      if(username == null){
23                          username = null;
24                      }
25                      if(password == null){
26                          password = null;
27                      }
28                      username = username.trim();
29                      UsernamePasswordAuthenticationToken aythRequest = new UsernamePasswordAuthenticationToken(username, password);
30                     setDetails(request, authRequest);
31                     Hr principal = new Hr();
32                     principal.setUsername(username);
33                     sessionregistry.registerNewSession(request,getSession(true).getId(), principal);
34                     return this.getAuthenticationManager().authenticate(authRequest)
35         }
36     }esle{
37         checkCode(request.getParameter("code"), verify_code);
38         return super.attempAuthentication(request, response);
39     }
40 
41     public void checkCode(HttpServletResponse response, Strign code, String verify_code){
42         if(code == null || verify_code ==null || "".equals(code) || !verify_code.toLowerCase().equals(code.toLowerCase())){
43           throw new AuthenticationException("验证码不正确!");
44         }
45     }
46 
47 }
验证码登录过滤
复制代码

4.响应前端

  1. 该响应前端类,主要是通过controller方法响应数据给前端接口
  2. 首先我们通过验证码实体类VerificationCode来生成该类对象
  3. 再通过该类对象生成验证码图片对象,并获取验证码对象的验证码
  4. 最后显示验证码给用户界面,用户输入正确验证码完成登录

    具体实现代码如下:

复制代码
@RestController
public class LoginController{
    @GetMapping("/login")
    public RespBean login(){
        return RespBean("尚未登陆,请先登录!");
    }
//此处需要在securityConfig配置类的configure(WebSecurity web)方法中重写web.ignoring().antMatchers()放行"cerifyCode" @GetMapping("verifyCode") public verifuCode(HttpSerlvetRequest request, HttpServletResponse response){ VerifucationCode code = new VerificationCode(); image = code,getImage(); text = code.getText(); HttpSession session = new HttpSession(); session.setAttribute("verify_code", text); VerificationCode.output(image, response.getOuputStream()); } }
复制代码

 

posted @   求知律己  阅读(59)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!
点击右上角即可分享
微信分享提示