0
点赞
收藏
分享

微信扫一扫

双因子验证

之前感觉双因子验证很高大上,今天正好有时间就学了学

目录

引入jar

实体类

工具类

控制器

参考文档:快速接入Google两步认证Google Authenticator_最咔酷学院的博客-CSDN博客_谷歌认证


直接上代码

引入jar

实体类

package pers.wwz.study.twofactorauthentication.entity;

import lombok.Data;

@Data
public class Code {

    /**
     * 图片base64串
     */
    private String imgBase64;

    /**
     * randomSecretKey
     * 很重要
     */
    private String randomSecretKey;
}

工具类

package pers.wwz.study.twofactorauthentication.utils;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import de.taimos.totp.TOTP;
import org.apache.commons.codec.binary.Base32;
import org.apache.commons.codec.binary.Hex;
import sun.misc.BASE64Encoder;
 
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.util.UUID;

/**
 * @Author bilibili-nanoda
 * @Date 2021/8/13 10:33
 * @Version 1.0
 */
public class GoogleAuthenticationTool {
 
    public static String generateSecretKey() {
        SecureRandom random = new SecureRandom();
        byte[] bytes = new byte[20];
        random.nextBytes(bytes);
        Base32 base32 = new Base32();
        return base32.encodeToString(bytes);
    }
 
    /**
     * 根据32位随机码获得正确的6位数字
     *
     * @param secretKey
     * @return
     */
    public static String getTOTPCode(String secretKey) {
        Base32 base32 = new Base32();
        byte[] bytes = base32.decode(secretKey);
        String hexKey = Hex.encodeHexString(bytes);
        return TOTP.getOTP(hexKey);
    }
 
 
    /**
     * 生成绑定二维码(字符串)
     *
     * @param account   账户信息(展示在Google Authenticator App中的)
     * @param secretKey 密钥
     * @param title     标题 (展示在Google Authenticator App中的)
     * @return
     */
    public static String spawnScanQRString(String account, String secretKey, String title) {
        try {
            return "otpauth://totp/"
                    + URLEncoder.encode(title + ":" + account, "UTF-8").replace("+", "%20")
                    + "?secret=" + URLEncoder.encode(secretKey, "UTF-8").replace("+", "%20")
                    + "&issuer=" + URLEncoder.encode(title, "UTF-8").replace("+", "%20");
        } catch (UnsupportedEncodingException e) {
            throw new IllegalStateException(e);
        }
    }
 
    /**
     * 生成二维码(文件)【返回图片的base64,若指定输出路径则同步输出到文件中】
     *
     * @param barCodeData 二维码字符串信息
     * @param outPath     输出地址
     * @param height
     * @param width
     * @throws WriterException
     * @throws IOException
     */
    public static String createQRCode(String barCodeData, String outPath, int height, int width)
            throws WriterException, IOException {
        BitMatrix matrix = new MultiFormatWriter().encode(barCodeData, BarcodeFormat.QR_CODE,
                width, height);
        BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(matrix);
 
        ByteArrayOutputStream bof = new ByteArrayOutputStream();
        ImageIO.write(bufferedImage, "png", bof);
        String base64 = imageToBase64(bof.toByteArray());
        if(outPath!=null&&!outPath.equals("")) {
            try (FileOutputStream out = new FileOutputStream(outPath)) {
                MatrixToImageWriter.writeToStream(matrix, "png", out);
            }
        }
        return base64;
    }
 
    /**
     * 将图片文件转换成base64字符串,参数为该图片的路径
     *
     * @param dataBytes
     * @return java.lang.String
     */
    private static String imageToBase64(byte[] dataBytes) {
        // 对字节数组Base64编码
        BASE64Encoder encoder = new BASE64Encoder();
        if (dataBytes != null) {
            return "data:image/jpeg;base64," + encoder.encode(dataBytes);// 返回Base64编码过的字节数组字符串
        }
        return null;
    }

    public static void main(String[] args) {
        String secretKey = UUID.randomUUID().toString().replace("-", "");
        for (int i = 0; i < 100; i++) {
            String totpCode = getTOTPCode(secretKey);
            System.out.println(totpCode);
        }

    }
 
}

控制器

package pers.wwz.study.twofactorauthentication;

import com.google.zxing.WriterException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import pers.wwz.study.twofactorauthentication.entity.Code;
import pers.wwz.study.twofactorauthentication.utils.GoogleAuthenticationTool;

import java.io.IOException;

@Slf4j
@RestController
@RequestMapping("/code")
public class CodeController {


    /**
     * 生成绑定的二维码(base64),并把密钥返回
     * @param userId
     * @return
     */
    @GetMapping("/genCode")
    public Code genCode(@RequestParam("userId")String userId) {
        // 这个很重要 和用户相关
        String randomSecretKey = GoogleAuthenticationTool.generateSecretKey();

        //此步设置的参数就是App扫码后展示出来的参数
        // 扫描后展示内容格式:titl(userId),如wangdachui(123456)
        String qrCodeString = GoogleAuthenticationTool.spawnScanQRString(userId, randomSecretKey, "wangdachui");
        String qrCodeImageBase64 = null;
        try {
            qrCodeImageBase64 = GoogleAuthenticationTool.createQRCode(qrCodeString, null, 512, 512);
        } catch (WriterException | IOException e) {
            e.printStackTrace();
        }
        log.info("随机密钥:{}",randomSecretKey);
        Code code = new Code();
        code.setImgBase64(qrCodeImageBase64);
        code.setRandomSecretKey(randomSecretKey);
        return code;
    }

    /**
     * 执行谷歌两步验证绑定
     * 输入绑定二维码上的6位数字
     * 个人认为randomSecretKey不输入也可以,直接生成的时候存起来(扫码可以获取randomSecretKey)
     * @return
     */
    @PostMapping("/bindCode")
    @ResponseBody
    public String bindCode(@RequestParam("randomSecretKey")String randomSecretKey,@RequestParam("inputGoogleCode")String inputGoogleCode){

        String rightCode =GoogleAuthenticationTool.getTOTPCode(randomSecretKey);
        if(rightCode.equals(inputGoogleCode)){
            return "成功";

        }
        return "失败";


    }

    /**
     * 登录验证
     * @return
     */
    @PostMapping("/loginVerify")
    @ResponseBody
    public String loginVerify(@RequestParam String code){

        String rightCode =GoogleAuthenticationTool.getTOTPCode("KFCTNPLXJ7COTL5BTSSK76BLUWEITHHY");
        if(rightCode.equals(code)){
            return "成功";

        }
        return "失败";


    }



}

参考文档:快速接入Google两步认证Google Authenticator_最咔酷学院的博客-CSDN博客_谷歌认证

举报

相关推荐

npm 配置双因素身份验证

0 条评论