Java验证器

验证码的作用

1. 可以防止机器疯狂注册
2. 可以防止邮箱和短信被刷

极限验证器

参考网址

geetestjava部署文档

jar包

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.47</version>
</dependency>

SDK类

import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;

/**
 * Java SDK
 *
 */
public class GeetestLib {

    protected static final org.slf4j.Logger logger = LoggerFactory.getLogger(GeetestLib.class);

    protected final String verName = "4.0";
    protected final String sdkLang = "java";

    protected final String apiUrl = "http://api.geetest.com";

    protected final String registerUrl = "/register.php";
    protected final String validateUrl = "/validate.php";

    protected final String json_format = "1";

    /**
     * 极验验证二次验证表单数据 chllenge
     */
    public static final String fn_geetest_challenge = "geetest_challenge";

    /**
     * 极验验证二次验证表单数据 validate
     */
    public static final String fn_geetest_validate = "geetest_validate";

    /**
     * 极验验证二次验证表单数据 seccode
     */
    public static final String fn_geetest_seccode = "geetest_seccode";

    /**
     * 公钥
     */
    private String captchaId = "";

    /**
     * 私钥
     */
    private String privateKey = "";

    /**
     * 是否开启新的failback
     */
    private boolean newFailback = false;

    /**
     * 返回字符串
     */
    private String responseStr = "";

    /**
     * 调试开关,是否输出调试日志
     */
    public boolean debugCode = true;

    /**
     * 极验验证API服务状态Session Key
     */
    public String gtServerStatusSessionKey = "gt_server_status";

    /**
     * 带参数构造函数
     *
     * @param captchaId
     * @param privateKey
     */
    public GeetestLib(String captchaId, String privateKey, boolean newFailback) {

        this.captchaId = captchaId;
        this.privateKey = privateKey;
        this.newFailback = newFailback;
    }

    /**
     * 获取本次验证初始化返回字符串
     *
     * @return 初始化结果
     */
    public String getResponseStr() {

        return responseStr;

    }

    public String getVersionInfo() {

        return verName;

    }

    /**
     * 预处理失败后的返回格式串
     *
     * @return
     */
    private String getFailPreProcessRes() {

        Long rnd1 = Math.round(Math.random() * 100);
        Long rnd2 = Math.round(Math.random() * 100);
        String md5Str1 = md5Encode(rnd1 + "");
        String md5Str2 = md5Encode(rnd2 + "");
        String challenge = md5Str1 + md5Str2.substring(0, 2);

        JSONObject jsonObject = new JSONObject();
        try {

            jsonObject.put("success", 0);
            jsonObject.put("gt", this.captchaId);
            jsonObject.put("challenge", challenge);
            jsonObject.put("new_captcha", this.newFailback);

        } catch (JSONException e) {

            gtlog("json dumps error");

        }

        return jsonObject.toString();

    }

    /**
     * 预处理成功后的标准串
     *
     */
    private String getSuccessPreProcessRes(String challenge) {

        gtlog("challenge:" + challenge);

        JSONObject jsonObject = new JSONObject();
        try {

            jsonObject.put("success", 1);
            jsonObject.put("gt", this.captchaId);
            jsonObject.put("challenge", challenge);

        } catch (JSONException e) {

            gtlog("json dumps error");

        }

        return jsonObject.toString();

    }

    /**
     * 验证初始化预处理
     *
     * @return 1表示初始化成功,0表示初始化失败
     */
    public int preProcess(HashMap<String, String> data) {

        if (registerChallenge(data) != 1) {

            this.responseStr = this.getFailPreProcessRes();
            return 0;

        }

        return 1;

    }

    /**
     * 用captchaID进行注册,更新challenge
     *
     * @return 1表示注册成功,0表示注册失败
     */
    private int registerChallenge(HashMap<String, String>data) {

        try {
            String userId = data.get("user_id");
            String clientType = data.get("client_type");
            String ipAddress = data.get("ip_address");

            String getUrl = apiUrl + registerUrl + "?";
            String param = "gt=" + this.captchaId + "&json_format=" + this.json_format;

            if (userId != null){
                param = param + "&user_id=" + userId;
            }
            if (clientType != null){
                param = param + "&client_type=" + clientType;
            }
            if (ipAddress != null){
                param = param + "&ip_address=" + ipAddress;
            }

            gtlog("GET_URL:" + getUrl + param);
            String result_str = readContentFromGet(getUrl + param);
            if (result_str == "fail"){

                gtlog("gtServer register challenge failed");
                return 0;

            }

            gtlog("result:" + result_str);
            JSONObject jsonObject = JSONObject.parseObject(result_str);
            String return_challenge = jsonObject.getString("challenge");

            gtlog("return_challenge:" + return_challenge);

            if (return_challenge.length() == 32) {

                this.responseStr = this.getSuccessPreProcessRes(this.md5Encode(return_challenge + this.privateKey));

                return 1;

            }
            else {

                gtlog("gtServer register challenge error");

                return 0;

            }
        } catch (Exception e) {

            gtlog(e.toString());
            gtlog("exception:register api");

        }
        return 0;
    }

    /**
     * 判断一个表单对象值是否为空
     *
     * @param gtObj
     * @return
     */
    protected boolean objIsEmpty(Object gtObj) {

        if (gtObj == null) {

            return true;

        }

        if (gtObj.toString().trim().length() == 0) {

            return true;

        }

        return false;
    }

    /**
     * 检查客户端的请求是否合法,三个只要有一个为空,则判断不合法
     *
     * @return
     */
    private boolean resquestIsLegal(String challenge, String validate, String seccode) {

        if (objIsEmpty(challenge)) {

            return false;

        }

        if (objIsEmpty(validate)) {

            return false;

        }

        if (objIsEmpty(seccode)) {

            return false;

        }

        return true;
    }


    /**
     * 服务正常的情况下使用的验证方式,向gt-server进行二次验证,获取验证结果
     *
     * @param challenge
     * @param validate
     * @param seccode
     * @return 验证结果,1表示验证成功0表示验证失败
     */
    public int enhencedValidateRequest(String challenge, String validate, String seccode, HashMap<String, String> data) {

        if (!resquestIsLegal(challenge, validate, seccode)) {

            return 0;

        }

        logger.info("request legitimate");

        String userId = data.get("user_id");
        String clientType = data.get("client_type");
        String ipAddress = data.get("ip_address");

        String postUrl = this.apiUrl + this.validateUrl;
        String param = String.format("challenge=%s&validate=%s&seccode=%s&json_format=%s",
                challenge, validate, seccode, this.json_format);

        if (userId != null){
            param = param + "&user_id=" + userId;
        }
        if (clientType != null){
            param = param + "&client_type=" + clientType;
        }
        if (ipAddress != null){
            param = param + "&ip_address=" + ipAddress;
        }

        logger.info("param:" + param);

        String response = "";
        try {

            if (validate.length() <= 0) {

                return 0;

            }

            if (!checkResultByPrivate(challenge, validate)) {

                return 0;

            }

            logger.info("checkResultByPrivate");

            response = readContentFromPost(postUrl, param);

            logger.info("response: " + response);

        } catch (Exception e) {

            e.printStackTrace();

        }

        String return_seccode = "";

        try {

            JSONObject return_map = JSONObject.parseObject(response);
            return_seccode = return_map.getString("seccode");
            logger.info("md5: " + md5Encode(return_seccode));

            if (return_seccode.equals(md5Encode(seccode))) {

                return 1;

            } else {

                return 0;

            }

        } catch (JSONException e) {


            logger.info("json load error");
            return 0;

        }

    }

    /**
     * failback使用的验证方式
     *
     * @param challenge
     * @param validate
     * @param seccode
     * @return 验证结果,1表示验证成功0表示验证失败
     */
    public int failbackValidateRequest(String challenge, String validate, String seccode) {

        gtlog("in failback validate");

        if (!resquestIsLegal(challenge, validate, seccode)) {
            return 0;
        }
        gtlog("request legitimate");

        return 1;
    }

    /**
     * 输出debug信息,需要开启debugCode
     *
     * @param message
     */
    public void gtlog(String message) {
        if (debugCode) {
            logger.info("gtlog: " + message);
        }
    }

    protected boolean checkResultByPrivate(String challenge, String validate) {
        String encodeStr = md5Encode(privateKey + "geetest" + challenge);
        return validate.equals(encodeStr);
    }

    /**
     * 发送GET请求,获取服务器返回结果
     *
     * @param URL
     * @return 服务器返回结果
     * @throws IOException
     */
    private String readContentFromGet(String URL) throws IOException {

        URL getUrl = new URL(URL);
        HttpURLConnection connection = (HttpURLConnection) getUrl
                .openConnection();

        connection.setConnectTimeout(2000);// 设置连接主机超时(单位:毫秒)
        connection.setReadTimeout(2000);// 设置从主机读取数据超时(单位:毫秒)

        // 建立与服务器的连接,并未发送数据
        connection.connect();

        if (connection.getResponseCode() == 200) {
            // 发送数据到服务器并使用Reader读取返回的数据
            StringBuffer sBuffer = new StringBuffer();

            InputStream inStream = null;
            byte[] buf = new byte[1024];
            inStream = connection.getInputStream();
            for (int n; (n = inStream.read(buf)) != -1;) {
                sBuffer.append(new String(buf, 0, n, "UTF-8"));
            }
            inStream.close();
            connection.disconnect();// 断开连接

            return sBuffer.toString();
        }
        else {

            return "fail";
        }
    }

    /**
     * 发送POST请求,获取服务器返回结果
     *
     * @param URL
     * @return 服务器返回结果
     * @throws IOException
     */
    private String readContentFromPost(String URL, String data) throws IOException {

        gtlog(data);
        URL postUrl = new URL(URL);
        HttpURLConnection connection = (HttpURLConnection) postUrl
                .openConnection();

        connection.setConnectTimeout(2000);// 设置连接主机超时(单位:毫秒)
        connection.setReadTimeout(2000);// 设置从主机读取数据超时(单位:毫秒)
        connection.setRequestMethod("POST");
        connection.setDoInput(true);
        connection.setDoOutput(true);
        connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

        // 建立与服务器的连接,并未发送数据
        connection.connect();

        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(connection.getOutputStream(), "utf-8");
        outputStreamWriter.write(data);
        outputStreamWriter.flush();
        outputStreamWriter.close();

        if (connection.getResponseCode() == 200) {
            // 发送数据到服务器并使用Reader读取返回的数据
            StringBuffer sBuffer = new StringBuffer();

            InputStream inStream = null;
            byte[] buf = new byte[1024];
            inStream = connection.getInputStream();
            for (int n; (n = inStream.read(buf)) != -1;) {
                sBuffer.append(new String(buf, 0, n, "UTF-8"));
            }
            inStream.close();
            connection.disconnect();// 断开连接

            return sBuffer.toString();
        }
        else {

            return "fail";
        }
    }

    /**
     * md5 加密
     *
     * @time 2014年7月10日 下午3:30:01
     * @param plainText
     * @return
     */
    private String md5Encode(String plainText) {
        String re_md5 = new String();
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(plainText.getBytes());
            byte b[] = md.digest();
            int i;
            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0){
                    i += 256;
                }
                if (i < 16){
                    buf.append("0");
                }
                buf.append(Integer.toHexString(i));
            }

            re_md5 = buf.toString();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return re_md5;
    }

}

公钥和私钥类(也可以配置在数据库读取)

/**
 * GeetestWeb配置文件
 * 
 *
 */
public class GeetestConfig {

	// 填入自己的captcha_id和private_key
	public static final String geetest_id = "48a6ebac4ebc6642d68c217fca33eb4d";
    public static final String geetest_key = "4f1c085290bec5afdc54df73535fc361";
    public static final boolean newfailback = true;

}

Servlet验证类

import lombok.extern.slf4j.Slf4j;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;

/**
 * @author wzh
 * @date 2019/6/5 - 14:03
 */
@Slf4j
public class StartCaptchaServlet extends HttpServlet {

    private static Integer errorNum = 0;

    /**
     * 滑动验证码初始化
     * @param userId
     * @param request
     * @param response
     * @return
     * @throws ServletException
     * @throws IOException
     */
    public static String captch1(String userId, HttpServletRequest request,
                                 HttpServletResponse response) throws ServletException, IOException {

        GeetestLib gtSdk = new GeetestLib(GeetestConfig.geetest_id,GeetestConfig.geetest_key,GeetestConfig.newfailback);
        String resStr = "{}";

        //自定义参数,可选择添加
        HashMap<String, String> param = new HashMap<String, String>();
        param.put("user_id", userId); //网站用户id
        param.put("client_type", "web"); //web:电脑上的浏览器;h5:手机上的浏览器,包括移动应用内完全内置的web_view;native:通过原生SDK植入APP应用的方式
        param.put("ip_address", request.getRemoteAddr()); //传输用户请求验证时所携带的IP


        //进行验证预处理
        int gtServerStatus = gtSdk.preProcess(param);
        //将服务器状态设置到session中
        request.getSession().setAttribute(gtSdk.gtServerStatusSessionKey, gtServerStatus);
        //将userid设置到session中
        request.getSession().setAttribute("userid", userId);

        if(gtServerStatus != 1){
            errorNum = errorNum + 1;
            log.error("geet error gtServerStatus:{} 验证码接口错误,当前错误次数:{},请及时更换验证类型",gtServerStatus,errorNum);
        }else{
            errorNum = 0;
        }

        resStr = gtSdk.getResponseStr();
        return resStr;

    }


    /**
     * 滑动验证码二次校验
     * @param geetest_challenge
     * @param geetest_validate
     * @param geetest_seccode
     * @param request
     * @param response
     * @return
     * @throws ServletException
     * @throws IOException
     */
    public static boolean checkCaptchaCode(String geetest_challenge,String geetest_validate,String geetest_seccode,HttpServletRequest request,
                                           HttpServletResponse response) throws ServletException, IOException {

        GeetestLib gtSdk = new GeetestLib(GeetestConfig.geetest_id,GeetestConfig.geetest_key,GeetestConfig.newfailback);

        String challenge = geetest_challenge; //request.getParameter(GeetestLib.fn_geetest_challenge);
        String validate = geetest_validate; //request.getParameter(GeetestLib.fn_geetest_validate);
        String seccode = geetest_seccode; //request.getParameter(GeetestLib.fn_geetest_seccode);

        log.info("challenge:{},validate:{},seccode:{},gt_server_status_code:{}",challenge,validate,seccode);

        //从session中获取userid
        String userid = (String)request.getSession().getAttribute("userid");

        //自定义参数,可选择添加
        HashMap<String, String> param = new HashMap<String, String>();
        param.put("user_id", userid); //网站用户id
        param.put("client_type", "web"); //web:电脑上的浏览器;h5:手机上的浏览器,包括移动应用内完全内置的web_view;native:通过原生SDK植入APP应用的方式
        param.put("ip_address", request.getRemoteAddr()); //传输用户请求验证时所携带的IP

        int gtResult = 0;

        //gt-server正常,向gt-server进行二次验证,强制校验
        gtResult = gtSdk.enhencedValidateRequest(challenge, validate, seccode, param);
        log.info("1:gtResult:{}",gtResult);

        if (gtResult == 1) {
            return true;
        }
        else {
            // 验证失败
            return false;
        }
    }
}

使用方式

1. 用户访问初始化接口,获取json字符串。例如
({"success":1,"challenge":"2bd9ffdd4607bdb055349be00095ea88","gt":"48a6ebac4ebc6642d68c217fca33eb4d"})
2. 页面根据challenge和gt生成指定的极限验证码
3. 用户点击极限验证码发送php请求,获取json字符串。例如
(geetest_1559789048175({"status": "success", "data": {"result": "success", "score": 2, "validate": "fc1c097e3b886735261833d01411dee9"}}))
4. 将challenge和validate传给后台,调用checkCaptchaCode方法检验是否成功

初始化接口

import com.alibaba.fastjson.JSONObject;
import com.shyb.util.StartCaptchaServlet;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author wzh
 * @date 2019/6/6 - 10:15
 */
@RestController
public class captcha {
    @GetMapping("/common/tartCaptcha")
    public JSONObject tartCaptcha(HttpServletRequest request, HttpServletResponse response) {
        try {
            JSONObject jsonStr = new JSONObject();
            JSONObject result = tartCaptcha("", request, response);
            jsonStr.put("captcha", result);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private JSONObject tartCaptcha(String userId, HttpServletRequest request,
                                   HttpServletResponse response){
        JSONObject data = new JSONObject();
        try {
            String result = StartCaptchaServlet.captch1(userId,request,response);
            data = JSONObject.parseObject(result);
            return data;
        } catch (ServletException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return data;
    }
}

谷歌验证器

jar包

<!-- google zxing QRCode 生成二维码-->
 <dependency>
     <groupId>com.google.zxing</groupId>
     <artifactId>core</artifactId>
     <version>3.3.0</version>
 </dependency>
 <!-- 密码加密 -->
<dependency>
	<groupId>commons-codec</groupId>
	<artifactId>commons-codec</artifactId>
	<version>1.8</version>
</dependency>

谷歌密钥生成类

public class GoogleAuthenticator {
	// 生成的key长度( Generate secret key length)
		public static final int SECRET_SIZE = 10;

		public static final String SEED = "g8GjEvTbW5oVSV7avL47357438reyhreyuryetredLDVKs2m0QN7vxRs2im5MDaNCWGmcD2rvcZx";
		// Java实现随机数算法
		public static final String RANDOM_NUMBER_ALGORITHM = "SHA1PRNG";
		// 最多可偏移的时间
		static int window_size = 3; // default 3 - max 17

		/**
		 * set the windows size. This is an integer value representing the number of
		 * 30 second windows we allow The bigger the window, the more tolerant of
		 * clock skew we are.
		 * 
		 * @param s
		 *            window size - must be >=1 and <=17. Other values are ignored
		 */
		public void setWindowSize(int s) {
			if (s >= 1 && s <= 17)
				window_size = s;
		}

		/**
		 * Generate a random secret key. This must be saved by the server and
		 * associated with the users account to verify the code displayed by Google
		 * Authenticator. The user must register this secret on their device.
		 * 生成一个随机秘钥
		 * 
		 * @return secret key
		 */
		public static String generateSecretKey() {
			SecureRandom sr = null;
			try {
				sr = SecureRandom.getInstance(RANDOM_NUMBER_ALGORITHM);
				sr.setSeed(Base64.decodeBase64(SEED));
				byte[] buffer = sr.generateSeed(SECRET_SIZE);
				Base32 codec = new Base32();
				byte[] bEncodedKey = codec.encode(buffer);
				String encodedKey = new String(bEncodedKey);
				return encodedKey;
			} catch (NoSuchAlgorithmException e) {
				// should never occur... configuration error
			}
			return null;
		}
		
		public static String generateCaoLiaoUrl(String user,String key,String companyUrl, String model) {
			StringBuffer sf = new StringBuffer("https://cli.im/api/qrcode/code?text=otpauth://totp/");
			sf.append(user);
			sf.append("-"+companyUrl);
			sf.append("?secret=");
			sf.append(key);
			sf.append("&mhid=");
			sf.append(model);
			return sf.toString();
		}

		/**
		 * Return a URL that generates and displays a QR barcode. The user scans
		 * this bar code with the Google Authenticator application on their
		 * smartphone to register the auth code. They can also manually enter the
		 * secret if desired
		 * 
		 * @param user
		 *            user id (e.g. fflinstone)
		 * @param host
		 *            host or system that the code is for (e.g. myapp.com)
		 * @param secret
		 *            the secret that was previously generated for this user
		 * @return the URL for the QR code to scan
		 */
		public static String getQRBarcodeURL(String user, String host, String secret) {
			//https://cli.im/api/qrcode/code?text=二维码内容&mhid=sELPDFnok80gPHovKdI
//			String format = "http://www.google.com/chart?chs=200x200&chld=M%%7C0&cht=qr&chl=otpauth://totp/%s@%s?secret=%s";
			String format = "https://cli.im/api/qrcode/code?text=otpauth://totp/%s@%s?secret=%s&mhid=sELPDFnok80gPHovKdI";
			return String.format(format, user, host, secret);
		}

		/**
		 * 生成一个google身份验证器,识别的字符串,只需要把该方法返回值生成二维码扫描就可以了。
		 * 
		 * @param user
		 *            账号
		 * @param secret
		 *            密钥
		 * @return
		 */
		public static String getQRBarcode(String user, String secret) {
			String format = "otpauth://totp/%s?secret=%s";
			return String.format(format, user, secret);
		}

		/**
		 * Check the code entered by the user to see if it is valid 验证code是否合法
		 * 
		 * @param secret
		 *            The users secret.
		 * @param code
		 *            The code displayed on the users device
		 * @param t
		 *            The time in msec (System.currentTimeMillis() for example)
		 * @return
		 */
		public static boolean check_code(String secret, long code, long timeMsec) {
			Base32 codec = new Base32();
			byte[] decodedKey = codec.decode(secret);
			// convert unix msec time into a 30 second "window"
			// this is per the TOTP spec (see the RFC for details)
			long t = (timeMsec / 1000L) / 30L;
			// Window is used to check codes generated in the near past.
			// You can use this value to tune how far you're willing to go.
			for (int i = -window_size; i <= window_size; ++i) {
				long hash;
				try {
					hash = verify_code(decodedKey, t + i);
				} catch (Exception e) {
					// Yes, this is bad form - but
					// the exceptions thrown would be rare and a static
					// configuration problem
					e.printStackTrace();
					throw new RuntimeException(e.getMessage());
					// return false;
				}
				if (hash == code) {
					return true;
				}
			}
			// The validation code is invalid.
			return false;
		}

		private static int verify_code(byte[] key, long t) throws NoSuchAlgorithmException, InvalidKeyException {
			byte[] data = new byte[8];
			long value = t;
			for (int i = 8; i-- > 0; value >>>= 8) {
				data[i] = (byte) value;
			}
			SecretKeySpec signKey = new SecretKeySpec(key, "HmacSHA1");
			Mac mac = Mac.getInstance("HmacSHA1");
			mac.init(signKey);
			byte[] hash = mac.doFinal(data);
			int offset = hash[20 - 1] & 0xF;
			// We're using a long because Java hasn't got unsigned int.
			long truncatedHash = 0;
			for (int i = 0; i < 4; ++i) {
				truncatedHash <<= 8;
				// We are dealing with signed bytes:
				// we just keep the first byte.
				truncatedHash |= (hash[offset + i] & 0xFF);
			}
			truncatedHash &= 0x7FFFFFFF;
			truncatedHash %= 1000000;
			return (int) truncatedHash;
		}
}

二维码生成类

public class ZxingUtils {
    private static final Logger logger = LoggerFactory.getLogger(ZxingUtils.class);

    private static final int BLACK = 0xFF000000;
    private static final int WHITE = 0xFFFFFFFF;

    private static BufferedImage toBufferedImage(BitMatrix matrix) {
    	System.setProperty("java.awt.headless","true");
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
            }
        }
        return image;
    }

    private static void writeToFile(BitMatrix matrix, String format, File file) throws IOException {
        BufferedImage image = toBufferedImage(matrix);
        if (!ImageIO.write(image, format, file)) {
            throw new IOException("Could not write an image of format " + format + " to " + file);
        }
    }

    /**
     * 将内容contents生成长宽均为width的图片,图片路径由imgPath指定
     */
    public static File getQRCodeImge(String contents, int width, String imgPath) {
        return getQRCodeImge(contents, width, width, imgPath);
    }

    /**
     * 将内容contents生成长为width,宽为width的图片,图片路径由imgPath指定
     */
    public static File getQRCodeImge(String contents, int width, int height, String imgPath) {
        try {
            Map<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
            hints.put(EncodeHintType.CHARACTER_SET, "UTF8");

            BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, width, height, hints);

            File imageFile = new File(imgPath);
            writeToFile(bitMatrix, "png", imageFile);

            return imageFile;

        } catch (Exception e) {
            logger.error("create QR code error!", e);
            return null;
        }
    }

    /**
     * 生成二维码,返回base64串
     * @param contents
     * @param width
     * @return
     */
    public static String getQRCodeImge(String contents, int width){
        try {
            Map<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
            hints.put(EncodeHintType.CHARACTER_SET, "UTF8");

            BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, width, width, hints);

            BufferedImage image = toBufferedImage(bitMatrix);
            ByteArrayOutputStream os = new ByteArrayOutputStream();//新建流。
            ImageIO.write(image, "png", os);
            byte b[] = os.toByteArray();
            return new BASE64Encoder().encode(b);
        } catch (Exception e) {
            logger.error("create QR code error!", e);
            return null;
        }
    }
}

测试

//生成密钥
String secret = GoogleAuthenticator.generateSecretKey();
//生成二维码地址
String qrcode = GoogleAuthenticator.getQRBarcode("wangxun-exchange", secret);
//生成二维码图片
String img = ZxingUtils.getQRCodeImge(qrcode, 100);

下载google动态口令https://sj.qq.com/myapp/detail.htm?apkName=com.google.android.apps.authenticator2 
通过密钥或扫描二维码添加后,即可测试
System.out.println(GoogleAuthenticator.check_code("TN57A5C32DH3OLDZ", code,System.currentTimeMillis()));
返回true即可证明认证通过

实际使用说明

1. 将密钥或二维码返回给页面,用户通过密钥或扫描二维码生成google验证码
2. 用户输入自己密码和验证码,前端将密钥当作默认参数传回,判断成功后,将用户的密钥存储在数据库中
3. 取消认证也需要密码和密钥,核对成功后,将密钥清空。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值