Эх сурвалжийг харах

fix:图片验证码调整

wangmh 7 жил өмнө
parent
commit
fb9f683037

+ 119 - 79
sso-server/src/main/java/com/uas/sso/util/CaptchaUtil.java

@@ -1,14 +1,8 @@
 package com.uas.sso.util;
 
-import com.uas.sso.exception.VisibleError;
-import org.springframework.util.StringUtils;
-
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.Graphics2D;
+import java.awt.*;
 import java.awt.image.BufferedImage;
 import java.io.IOException;
-import java.util.Date;
 import java.util.Random;
 import javax.imageio.ImageIO;
 import javax.servlet.ServletOutputStream;
@@ -28,9 +22,11 @@ public class CaptchaUtil {
     /**
      * 随机字符字典
      */
-    private static final char[] CHARS = { '2', '3', '4', '5', '6', '7', '8',
-            '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M',
-            'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
+    private static final String codes = "23456789abcdefghjkmnopqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ";    //验证码数组
+
+    private static BufferedImage buffImg;
+
+    private static String textCode;
 
     /**
      * 随机数
@@ -38,33 +34,31 @@ public class CaptchaUtil {
     private static Random random = new Random();
 
     /**
-     * 获取6位随机数
+     * 生成4位随机验证码
+     *
+     * @return 验证码
      */
-    private static String getRandomString()
-    {
-        StringBuilder buffer = new StringBuilder();
-        for(int i = 0; i < 4; i++)
-        {
-            buffer.append(CHARS[random.nextInt(CHARS.length)]);
-        }
-        return buffer.toString();
-    }
+    private static String getRandomCode() {
+        StringBuilder sb = new StringBuilder();
 
-    /**
-     * 获取随机数颜色
-     */
-    private static Color getRandomColor()
-    {
-        return new Color(255,255,255);
+        int i = 0;
+        while (i++ < 4) {
+            int index = random.nextInt(codes.length());
+            sb.append(codes.charAt(index));
+        }
+        return sb.toString();
     }
 
     /**
-     * 返回某颜色的反色
+     * 生成随机颜色(深色)
+     * @return 颜色
      */
-    private static Color getReverseColor(Color c)
-    {
-        return new Color(255 - c.getRed(), 255 - c.getGreen(),
-                255 - c.getBlue());
+    private static Color getRandomColor() {
+        // 产生随机的颜色值,让输出的每个字符的颜色值都将不同。
+        int red = random.nextInt(200);
+        int green = random.nextInt(200);
+        int blue = random.nextInt(200);
+        return new Color(red, green, blue);
     }
 
     /**
@@ -80,69 +74,115 @@ public class CaptchaUtil {
 
         response.setContentType("image/jpeg");
 
-        String randomString = getRandomString();
-        request.getSession(true).setAttribute(key, randomString);
+        drawImage(new Color(255, 255, 255), new Color(200, 200, 200));
+        request.getSession().setAttribute(key, textCode);
+
+        // 转成JPEG格式
+        ServletOutputStream out = response.getOutputStream();
+        ImageIO.write(buffImg, "jpeg", out);
+        out.flush();
+    }
+
 
+    /**
+     * 绘制图片
+     * @param backColor 背景颜色
+     * @param lineColor 线条颜色
+     */
+    private static void drawImage(Color backColor, Color lineColor) {
         int width = 100;
         int height = 30;
-        int lines = 10;
+        int interLine = 10;
+        textCode = getRandomCode();
+        buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+        Graphics g = buffImg.getGraphics();
 
-        Color color = getRandomColor();
-        Color reverse = getReverseColor(color);
-
-        BufferedImage bi = new BufferedImage(width, height,
-                BufferedImage.TYPE_INT_RGB);
-        Graphics2D g = bi.createGraphics();
-        g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 18));
-        g.setColor(color);
+        // 设置背景颜色
+        g.setColor(backColor == null ? getRandomColor() : backColor);
         g.fillRect(0, 0, width, height);
-        g.setColor(reverse);
-        Random r = new Random(new Date().getTime());
-
-        // 生成验证码
-        char[] randomChars = randomString.toCharArray();
-        for (int i = 0; i < randomChars.length; i++) {
-            int y = 10 + r.nextInt(20);// 10~30范围内的一个整数,作为y坐标
-            Color c = new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255));
-            g.setColor(c);
-            g.drawString("" + randomChars[i], 5 + i * width / 4, y);
-        }
 
-        /**
-         * 加圆点
-         */
-        for (int i = 0, n = random.nextInt(100); i < n; i++) {
-            g.drawOval(random.nextInt(width), random.nextInt(height), 1, 1);
+        // 绘制线条
+        int x = random.nextInt(4), y;
+        int x1 = width - random.nextInt(4), y1;
+        for (int i = 0; i < interLine; i++) {
+            g.setColor(lineColor == null ? getRandomColor() : lineColor);
+            y = random.nextInt(height - random.nextInt(4));
+            y1 = random.nextInt(height - random.nextInt(4));
+            g.drawLine(x, y, x1, y1);
         }
 
-        // 干扰线
-        for (int i = 0; i < lines; i++) {
-            Color c = new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255));
-            g.setColor(c);
-            g.drawLine(r.nextInt(width), r.nextInt(height), r.nextInt(width), r.nextInt(height));
+        int fsize = (int) (height * 0.8);//字体大小为图片高度的80%
+        int fx = (int) ((width / textCode.length()) * (Math.random() * 0.3 + 0.2));
+        int fy;
+        g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, fsize));
+        //写字符
+        for (int i = 0; i < textCode.length(); i++) {
+            fy = fsize;//每个字符高低是否随机
+            g.setColor(getRandomColor());
+            g.drawString(textCode.charAt(i) + "", fx, fy);
+            fx += (width / textCode.length()) * (Math.random() * 0.3 + 0.8); //依据宽度浮动
         }
 
-        // 转成JPEG格式
-        ServletOutputStream out = response.getOutputStream();
-        ImageIO.write(bi, "jpeg", out);
-        out.flush();
+        //扭曲图片
+        shearX(g, width, height, backColor);
+        shearY(g, width, height, backColor);
+
+        // 添加噪点
+        float yawpRate = 0.05f;// 噪声率
+        int area = (int) (yawpRate * width * height);//噪点数量
+        for (int i = 0; i < area; i++) {
+            int xxx = random.nextInt(width);
+            int yyy = random.nextInt(height);
+            int rgb = getRandomColor().getRGB();
+            buffImg.setRGB(xxx, yyy, rgb);
+        }
+        g.dispose();
     }
 
     /**
-     * 校验图片验证码
-     * @param request
-     * @param key 获取图片验证码存session的key
-     * @param code 校验的验证码
+     * 横向扭曲图片
+     * @param g 画布
+     * @param w1 宽度
+     * @param h1 高度
+     * @param color 背景颜色
      */
-    public static void checkCode(HttpServletRequest request, String key, String code) {
-        String captcha = (String) request.getSession().getAttribute(key);
-        if (StringUtils.isEmpty(captcha)) {
-            throw new VisibleError("图片验证码过期");
-        }
-        if (code != null && !code.equalsIgnoreCase(captcha)) {
-            throw new VisibleError("请输入正确的验证码");
+    private static void shearX(Graphics g, int w1, int h1, Color color) {
+        Random random = new Random();
+        int period = 2;
+
+        int frames = 1;
+        int phase = random.nextInt(2);
+
+        for (int i = 0; i < h1; i++) {
+            double d = (double) (period >> 1) * Math.sin((double) i / (double) period + (2.2831853071795862D * (double) phase) / (double) frames);
+            g.copyArea(0, i, w1, 1, (int) d, 0);
+            g.setColor(color);
+            g.drawLine((int) d, i, 0, i);
+            g.drawLine((int) d + w1, i, w1, i);
         }
+    }
 
-        request.getSession().removeAttribute(key);
+    /**
+     * 纵向扭曲图片
+     * @param g 画布
+     * @param w1 宽度
+     * @param h1 高度
+     * @param color 背景颜色
+     */
+    private static void shearY(Graphics g, int w1, int h1, Color color) {
+        Random random = new Random();
+        int period = random.nextInt(10) + 10; // 50;
+
+        int frames = 20;
+        int phase = 1;
+        for (int i = 0; i < w1; i++) {
+            double d = (double) (period >> 1)
+                    * Math.sin((double) i / (double) period
+                    + (2.2831853071795862D * (double) phase) / (double) frames);
+            g.copyArea(i, 0, 1, h1, 0, (int) d);
+            g.setColor(color);
+            g.drawLine(i, (int) d, i, 0);
+            g.drawLine(i, (int) d + h1, i, h1);
+        }
     }
 }