前言
说到登录,我相信大家最常见的首先是输入用户名和密码,然后输入程序生成的验证码完成登录;其次就是通过JWT实现鉴权了。在我的Springboot整合Jwt实现用户认证中,详细地介绍了如何简要地实现JWT鉴权。本篇我会介绍微人事中的验证码登录实现以及实现流程。
1.实现流程
- 首先是创建验证码实体类,生成验证码图片、字符串,显示验证码图像
- 过滤验证码,验证用户输入验证码和存入session中验证码是否一致,如果相同放行
- 编写响应接口,传递给前端接口
2.验证码实体类
- 该类中会定义验证码图片的宽度、高度、字体、背景颜色、随机生成数、随机字符串验证码范围、以及输出的字符串
- 随机生成颜色、字体、字符
- 创建一个空白的BufferedImage对象,用来显示生成的验证码相关信息
- 生成显示的验证码图片对象
- 绘制验证码中的干扰线
- 获取字符文本,最后输出图片
具体实现代码如下:
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.登录过滤
- 在这个登录过滤类LoginFilter中,我们继承UsernamePasswordAuthenticationFiletr类,并重写该类中的attempAuthentication()方法
- 首先判断这次登录的方法是不是POST方法,如果是放行,不是报错AuthenticationException,并显示不支持除POST方法以外的方法
- 从session中获取verify_code验证码
- 再判断请求的浏览的是内容格式是不是MediaType.APPLICATION_JSON_VALUE和MediaType.APPLICATION_JSON_UTF8_VALUE其中一种,如果是,进行下面操作
- 接着定义一个loginData集合用于存放用户信息,并使用ObjectMappper对象将请求的用户信息反序列化为Java对象存放于loginData集合中
- 从loginData集合中获取验证码与用户输入的验证码核对,如果相同,放行;再获取用户的用户名和密码(如果为空设置为空),将其作为UsernamePasswordAuthenticationToken的参数生成该类对象
- 最后根据登录用户的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.响应前端
- 该响应前端类,主要是通过controller方法响应数据给前端接口
- 首先我们通过验证码实体类VerificationCode来生成该类对象
- 再通过该类对象生成验证码图片对象,并获取验证码对象的验证码
- 最后显示验证码给用户界面,用户输入正确验证码完成登录
具体实现代码如下:
@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()); } }
标签:code,人事,实现,image,验证码,private,int,new From: https://www.cnblogs.com/kzf-99/p/17018123.html