Google-Authenticator
接入流程
我之前做量化系统的时候,刚好研究过该类认证服务的接入问题,我给大家阐述一下整体的接入流程:
-
添加依赖库:首先需要引入支持TOTP的库,com.warrenstrange的Google Authenticator是一个流行的选择。
-
生成密钥:为每个用户生成一个唯一的密钥,这个密钥会被用户用于Google Authenticator应用的配置。
-
生成二维码:用户扫描这个二维码来在Google Authenticator应用中配置账号。
-
验证TOTP:验证用户在Google Authenticator应用中生成的一次性密码(TOTP)是否正确。
接下来,我给出具体的代码实现~
添加依赖
<!-- https://mvnrepository.com/artifact/com.warrenstrange/googleauth -->
<dependency>
<groupId>com.warrenstrange</groupId>
<artifactId>googleauth</artifactId>
<version>1.5.0</version>
</dependency>
生成密钥
使用GoogleAuthenticator库为用户生成一个唯一的密钥,代码如下:
import com.warrenstrange.googleauth.GoogleAuthenticator;
import com.warrenstrange.googleauth.GoogleAuthenticatorKey;
public class TwoFactorAuth {
public static void main(String[] args) {
GoogleAuthenticator gAuth = new GoogleAuthenticator();
final GoogleAuthenticatorKey key = gAuth.createCredentials();
String secret = key.getKey();
System.out.println("Secret key: " + secret);
}
}
生成二维码
使用ZXing库生成二维码,用户可以扫描这个二维码将密钥添加到Google Authenticator应用中,代码如下:
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.warrenstrange.googleauth.GoogleAuthenticator;
import com.warrenstrange.googleauth.GoogleAuthenticatorKey;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
public class GenerateQRCode {
public static void main(String[] args) {
GoogleAuthenticator gAuth = new GoogleAuthenticator();
final GoogleAuthenticatorKey key = gAuth.createCredentials();
String secret = key.getKey();
String email = "user@example.com";
String issuer = "ExampleApp";
String barCodeUrl = getGoogleAuthenticatorBarCode(secret, email, issuer);
System.out.println("QR Barcode URL: " + barCodeUrl);
try {
generateQRCodeImage(barCodeUrl, 350, 350, "QRCode.png");
} catch (WriterException | IOException e) {
e.printStackTrace();
}
}
private static String getGoogleAuthenticatorBarCode(String secretKey, String account, String issuer) {
return "otpauth://totp/"
+ issuer + ":"
+ account + "?secret=" + secretKey
+ "&issuer=" + issuer;
}
private static void generateQRCodeImage(String text, int width, int height, String filePath)
throws WriterException, IOException {
QRCodeWriter qrCodeWriter = new QRCodeWriter();
BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height);
Path path = FileSystems.getDefault().getPath(filePath);
MatrixToImageWriter.writeToPath(bitMatrix, "PNG", path);
}
}
验证TOTP
用户在Google Authenticator应用中输入生成的验证码,你需要验证这个验证码是否正确,代码如下:
import com.warrenstrange.googleauth.GoogleAuthenticator;
public class VerifyTOTP {
public static void main(String[] args) {
GoogleAuthenticator gAuth = new GoogleAuthenticator();
String secretKey = "用户的密钥";
int verificationCode = 123456; // 用户从Google Authenticator应用中输入的验证码
boolean isCodeValid = gAuth.authorize(secretKey, verificationCode);
if (isCodeValid) {
System.out.println("验证成功");
} else {
System.out.println("验证失败");
}
}
}
以上就是使用Java集成Google Authenticator的完整流程和代码实现,也是接入二次认证的整个流程,为你的系统增加了一道安全屏障!
1、这里,建议用 org.jboss.aerogear.security.otp - 用于生成和验证 TOTP,并提供了需要的依赖jar包,如下:
<dependency>
<groupId>org.jboss.aerogear</groupId>
<artifactId>aerogear-otp-java</artifactId>
<version>1.0.0</version>
</dependency>
2、创建一个服务来生成和验证 TOTP,代码如下:
import org.jboss.aerogear.security.otp.Totp;
import org.jboss.aerogear.security.otp.api.Base32;
public class TotpService {
public String generateSecretKey() {
return Base32.random();
}
public String getTotpUri(String secretKey, String username) {
return "otpauth://totp/YourAppName:" + username + "?secret=" + secretKey + "&issuer=YourAppName";
}
public boolean verifyCode(String code, String secretKey) {
Totp totp = new Totp(secretKey);
return totp.verify(code);
}
}
3、用户注册时生成一个密钥,激活二次认证时将该密钥转换为二维码供用户扫描,代码如下:
public class UserService {
private TotpService totpService = new TotpService();
public void registerUser(String username, String password) {
String secretKey = totpService.generateSecretKey();
// 将 secretKey 存储于数据库中,与用户账户关联
}
public String enable2Fa(String username) {
String secretKey = // 从数据库获取
return totpService.getTotpUri(secretKey, username);
}
}
4、最后,用户登录相关的代码也给出来了,代码如下:
public class AuthenticationController {
private UserService userService = new UserService();
@PostMapping("/login")
public ResponseEntity<?> login(@RequestParam String username, @RequestParam String password, @RequestParam String totpCode) {
// 正常的用户名和密码验证逻辑
String secretKey = // 从数据库获取
if (userService.verifyTotp(totpCode, secretKey)) {
// 验证成功 ,进入应用
return ResponseEntity.ok().build();
} else {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
}
}
说实话,这份代码只是一个初稿,不能直接使用,毕竟还缺少错误处理、日志记录以及安全性配置相关的代码。