java 服务端生成图片验证码及验证

需求是发送短信验证码时,加上一个图片验证码。

1.代码实现

生成验证码图片的工具类--VerifyUtils.java

package com.lmc.utils;

import java.awt.Color;
import java.awt.Font;  
import java.awt.Graphics2D;  
import java.awt.LinearGradientPaint;  
import java.awt.Paint;  
import java.awt.geom.AffineTransform;  
import java.awt.image.BufferedImage;  
import java.io.File;  
import java.io.FileOutputStream;  
import java.io.IOException;  
import java.io.OutputStream;  
import java.util.Arrays;  
import java.util.Random;  
  
import javax.imageio.ImageIO;  
  
public class VerifyCodeUtils{  
    // 可自定义验证码字符源
    public static final String VERIFY_CODES = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";  
  
  
    /** 
     * 使用系统默认字符源生成验证码 
     * @param verifySize 验证码长度 
     * @return 
     */  
    public static String generateVerifyCode(int verifySize){  
        return generateVerifyCode(verifySize, VERIFY_CODES);  
    }  
    /** 
     * 使用指定源生成验证码 
     * @param verifySize 验证码长度 
     * @param sources   验证码字符源 
     * @return 
     */  
    public static String generateVerifyCode(int verifySize, String sources){  
        if(sources == null || sources.length() == 0){  
            sources = VERIFY_CODES;  
        }  
        int codesLen = sources.length();  
        Random rand = new Random(System.currentTimeMillis());  
        StringBuilder verifyCode = new StringBuilder(verifySize);  
        for(int i = 0; i < verifySize; i++){  
            verifyCode.append(sources.charAt(rand.nextInt(codesLen-1)));  
        }  
        return verifyCode.toString();  
    }  
      
    /** 
     * 生成随机验证码文件,并返回验证码值 
     * @param w 图片宽(像素)
     * @param h 图片高(像素)
     * @param outputFile 
     * @param verifySize 
     * @return 
     * @throws IOException 
     */  
    public static String outputVerifyImage(int w, int h, File outputFile, int verifySize) throws IOException{  
        String verifyCode = generateVerifyCode(verifySize);  
        outputImage(w, h, outputFile, verifyCode);  
        return verifyCode;  
    }  
      
    /** 
     * 输出随机验证码图片流,并返回验证码值 
     * @param w 
     * @param h 
     * @param os 
     * @param verifySize 
     * @return 
     * @throws IOException 
     */  
    public static String outputVerifyImage(int w, int h, OutputStream os, int verifySize) throws IOException{  
        String verifyCode = generateVerifyCode(verifySize);  
        outputImage(w, h, os, verifyCode);  
        return verifyCode;  
    }  
      
    /** 
     * 生成指定验证码图像文件 
     * @param w 
     * @param h 
     * @param outputFile 
     * @param code 
     * @throws IOException 
     */  
    public static void outputImage(int w, int h, File outputFile, String code) throws IOException{  
        if(outputFile == null){  
            return;  
        }  
        File dir = outputFile.getParentFile();  
        if(!dir.exists()){  
            dir.mkdirs();  
        }  
        try{  
            outputFile.createNewFile();  
            FileOutputStream fos = new FileOutputStream(outputFile);  
            outputImage(w, h, fos, code);  
            fos.close();  
        } catch(IOException e){  
            throw e;  
        }  
    }  
      
    /** 
     * 输出指定验证码图片流 
     * @param w 
     * @param h 
     * @param os 
     * @param code 
     * @throws IOException 
     */  
    public static void outputImage(int w,  
                            int h,  
                            OutputStream os,  
                            String code) throws IOException{  
        int verifySize = code.length();  
        BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);  
        Random rand = new Random();  
        Graphics2D g2 = image.createGraphics();  
        Color[] colors = new Color[5];  
        Color[] colorSpaces = new Color[] { Color.WHITE, Color.CYAN,  
                Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE,  
                Color.PINK, Color.YELLOW };  
        float[] fractions = new float[colors.length];  
        for(int i = 0; i < colors.length; i++){  
            colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];  
            fractions[i] = rand.nextFloat();  
        }  
        Arrays.sort(fractions);  
        Paint linearPaint = new LinearGradientPaint(0, 0, w, h, fractions, colors);  
        Paint linearPaint2 = new LinearGradientPaint(0, 0, w, h, new float[]{0.3f, .6f, .8f, .9f}, new Color[]{Color.BLUE, Color.BLACK, Color.GREEN, Color.BLUE});  
        //设置图片背景为白色  
        g2.setPaint(Color.WHITE);  
        g2.fillRect(0, 0, w, h);  
        //设置图片渐变背景  
        g2.setPaint(linearPaint);  
        g2.fillRoundRect(0, 0, w, h, 5, 5);  
          
        g2.setPaint(linearPaint2);  
        int fontSize = (int) (Math.min(w/verifySize, h));  
        Font font = new Font("微软雅黑", Font.BOLD, fontSize);  
        g2.setFont(font);  
        char[] chars = code.toCharArray();  
        for(int i = 0; i < verifySize; i++){  
            AffineTransform affine = new AffineTransform();  
            affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize/2, h/2);  
            g2.setTransform(affine);  
            g2.drawChars(chars, i, 1, (w / verifySize) * i, h/2 + fontSize /2);  
        }  
        g2.dispose();  
        ImageIO.write(image, "jpg", os);  
    }  
  
    public static void main(String[] args) throws IOException{  
        File dir = new File("F:/verifies");  
        int w = 200, h = 80;  
        for(int i = 0; i < 100; i++){  
            String verifyCode = generateVerifyCode(4);  
            File file = new File(dir, verifyCode + ".jpg");  
            outputImage(w, h, file, verifyCode);  
        }  
    }  
}  

生成图片验证码接口和验证接口demo

package com.lmc.controllr;

import com.lmc.utils.VerifyCodeUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @description:
 * @Author: lmc
 * @date: 2022/1/1 10:52
 */
@RestController
@RequestMapping("/test")
public class TestController {

    @RequestMapping("/authCode")
    public void getAuthCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //req.setCharacterEncoding("utf-8");
        //res.setContentType("text/html;charset=utf-8");
        // 设置http响应的文件MIME类型为图片
        response.setContentType("image/jpeg");
        // 不让浏览器记录此图片的缓存
        response.setDateHeader("expries", -1);
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");
        // 这里调用了一个工具类VerifyCodeUtils来生成指定位数(也可指定内容)的验证码字符串
        String verifyCode = VerifyCodeUtils.generateVerifyCode(4);
        // 将生成验证码字符串保存到session域中,方面进行表单验证
        request.getSession().setAttribute("verifyCode", verifyCode);
        VerifyCodeUtils.outputImage(60, 30, response.getOutputStream(), verifyCode);
    }

    @RequestMapping("/verifyCode")
    public void verifyCode(String inputVerify, HttpServletRequest request){
        String verifyCode = (String) request.getSession().getAttribute("verifyCode");
        if (inputVerify.equals(verifyCode)){
            System.out.println("您输入的验证码正确!");
        }else{
            System.out.println("您输入的验证码有误");
        }
    }
}

测试:

第一步:调用接口获取图片验证码。

java 服务端生成图片验证码及验证

 第二步:调用验证接口

java 服务端生成图片验证码及验证

 后台的输出为:

java 服务端生成图片验证码及验证

 为什么获取短信验证码需要图片验证码?(其他登录操作同理)

注册企业会员、申请游戏账号,人们发现在获取关键的短信验证码以前有时会遇到图形验证码,表面看上去这好像让注册步骤变得更加麻烦了,而事实上这种验证十分受企业青睐,与短信验证码配合使用,大有好处。接下来一起看看原因吧。

大家知道图形验证码的主要作用是用来区别注册行为是人为还是机器的,例如注册淘宝账号或者购买火车票提交订单以前,常常都要先通过图形验证以后才可以获取短信验证码,加入这个步骤的主要目的是为了防止有网络黑客或是不法分子使用轰炸软件恶意攻击,无节制获取短信验证码,造成企业成本浪费,产生非人为注册的烂数据。而图片验证码的加入,让短信验证码变得更加安全。

除了在短信验证码前加入图形验证机制以外,一些专业有经验的短信验证码接口服务商还会建议企业采用一些其他的安全防范机制,比如以下这三种:

1.注册时流量限定

网站可以允许用户不必申请短信验证码就完成注册,可是必须通过手机短信验证码验证身份真实性后才可以进行其他操作,这样就能够将注册步骤跟获取短信验证码分开,避免人为的批量轰炸获取。

2.增加触发限制

一般注册的时候常常需要填写用户名、密码、验证码,不过申请短信验证码以前,可以再增加一些其他的限制,比如如果注册时资料填写的不够完整或是有不按规定要求填写的,将无法获取短信验证码。

3.设置请求时间间隔(同一个手机号一天限制可以发送多少次)

这种短信验证码防范措施很多网站也都在用,一般就是在初次请求短信验证码以后,第二次请求时需要隔一分钟或是两分钟,甚至是更长的时间才可以再次发送请求。此外除了时间限制,还可以增加IP限制、同一手机号码请求次数限制等。

增加图形验证、时间限制、条件限定都是为了让短信验证码使用更加安全、更加合理,让真实用户获得更好的体验,而这些安全防范措施,一般正规的短信验证码服务商都会提前提醒企业做好。

原文链接:

https://www.smshx.com/zixun259.html

https://blog.csdn.net/weixin_34195142/article/details/88923744

上一篇:SendMail.java


下一篇:图的两种遍历方式--深度优先与广度优先