准备工作
下载手机端App:谷歌的Google Authenticator或者微软的Microsoft Authenticator
验证原理
- 用户查看Google Authenticator手机端应用绑定后生成的6为动态密码(每隔1min动态刷新)
- 后端服务查库得到绑定时保存的32位密钥,根据密钥计算得到6位动态验证码
- 将用户输入的6位验证码和正确的6位验证码做匹配,相同则登陆成功,不同则验证码时间失效或错误
流程图
maven依赖
<dependency>
<groupId>com.warrenstrange</groupId>
<artifactId>googleauth</artifactId>
<version>1.4.0</version>
</dependency><!-- ZXing core library -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.4.1</version>
</dependency><!-- ZXing JavaSE library -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.4.1</version>
</dependency>
关键代码示例
校验动态密码
GoogleAuthenticator gAuth = new GoogleAuthenticator();
if (!String.valueOf(gAuth.getTotpPassword(user.getTwoFactorSecretKey())).equals(twoFactoryCode)) {
throw new BaseException("动态密码错误");
}
获取二维码
public TwoFactoryQRVO twoFactoryQR(String operator) {
GoogleAuthenticator gAuth = new GoogleAuthenticator();
GoogleAuthenticatorKey googleAuthenticatorKey = gAuth.createCredentials();
String secretKey = googleAuthenticatorKey.getKey();
try {
String qrCode = getOtpAuthURL(operator, secretKey, "XXX平台");
// BufferedImage qrCodeImage = generateQRCodeImage(qrCode);
// String qrCodeBase64 = bufferedImageToBase64(qrCodeImage);
return TwoFactoryQRVO.builder().qrCode(qrCode).secretKey(secretKey).operator(operator).build();
} catch (Exception e) {
log.error("生成二维码失败:", e);
throw new BaseException("生成二维码失败");
}
}
// 生成OTP认证URL
private String getOtpAuthURL(String account, String secretKey, String issuer) throws UnsupportedEncodingException {
String Url = "otpauth://totp/"
+ URLEncoder.encode((!StringUtils.isEmpty(issuer) ? (issuer + ":") : "") + account, "UTF-8").replace("+", "%20")
+ "?secret=" + URLEncoder.encode(secretKey, "UTF-8").replace("+", "%20")
+ (!StringUtils.isEmpty(issuer) ? ("&issuer=" + URLEncoder.encode(issuer, "UTF-8").replace("+", "%20")) : "");
//log.info(Url);
return Url;
}