内容目录
一、authenticator解决了什么问题二、authenticator的原理三、springboot集成authenticator四、做成可复用starter五、参考
一、authenticator解决了什么问题
1.authenticator是什么?
谷歌Authenticator是谷歌推出的一种双因素身份验证应用程序。它是一种为用户提供额外层次的账户保护的安全工具。传统的认证方式通常只依赖于用户名和密码,而双因素身份验证则需要用户提供两个不同类型的验证信息,以增加账户的安全性。
谷歌Authenticator通过生成动态的一次性密码来实现双因素身份验证。当你登录一个已启用谷歌Authenticator的系统或服务时时,需要输入用户名和密码,然后打开 Authenticator 应用来获取当前的一次性密码。这个密码每30秒钟更新一次,只在短暂的时间段内有效。
这种一次性密码是通过基于时间戳的算法计算得出的,同时还需要通过与账户绑定的密钥进行验证。由于每个密码只在极短的时间内有效,并且密码是动态变化的,即使有人获得了您的用户名和密码,他们也无法成功登录您的账户,因为他们没有有效的一次性密码。
谷歌Authenticator还可以与多个账户关联,这意味着您可以在一个应用中管理多个账户的一次性密码。它对于保护您的各种在线账户(如电子邮件、社交媒体、金融服务)非常有用。
简而言之,谷歌Authenticator是一种提供额外层次安全保护的双因素身份验证应用程序。它通过生成动态的一次性密码来增加账户的安全性,并在登录过程中要求用户提供额外的验证信息。
2.它本质上解决了什么问题?
谷歌Authenticator本质上解决了以下问题:
强化账户安全性:谷歌 Authenticator 提供了一种额外的身份验证层,以保护您的帐户免受未经授权的访问。即使有人获得了您的用户名和密码,他们仍然需要有效的一次性密码才能成功登录。
降低密码泄露风险:由于谷歌 Authenticator 生成的一次性密码在每30秒钟更新一次,并且只在特定的时间段内有效,即使密码泄露,攻击者也只能在一个非常短的时间窗口内进行利用。这大大降低了密码被滥用的风险。
抵御钓鱼和网络针对性攻击:通过生成每30秒钟更改的动态一次性密码,谷歌 Authenticator 防止了恶意用户和攻击者使用被窃取的认证凭据进行登录。这增加了实施钓鱼和网络针对性攻击的难度。
提供离线身份验证:由于一次性密码是基于时间戳计算的,所以即使在没有网络连接的情况下,您仍然可以进行身份验证。这对于旅行、临时网络中断或无法接收短信验证码的情况非常有用。
总之,谷歌Authenticator增加了双因素身份验证的安全性,提供了一种简便而有效的方式来保护您的帐户免受未经授权访问和针对性攻击的威胁。
二、authenticator的原理
1.基于时间的TOTP
谷歌Authenticator是基于TOTP算法实现的验证方式,TOTP(Time-Based One-Time Password是谷歌Authenticator中使用的一种身份验证方法。它基于时间的动态密码算法,用于生成一次性密码(One-Time Passwords)。
当启用谷歌Authenticator并为特定帐户配置时,它会与该帐户关联一个密钥。该密钥私密地存储在您的设备上。每30秒钟,该密钥都会与当前时间戳进行计算,并生成一个新的一次性密码。
当您需要进行身份验证时,您可以打开谷歌Authenticator应用程序,输入相关帐户的用户名,然后应用程序会基于与服务器同步的时间戳生成相应的一次性密码。您将此密码输入到身份验证页面或应用程序中,以确认您是合法用户。
TOTP 提供了一种额外的安全层次,因为即使有人获得了您的用户名和密码,仍然需要一个有效的一次性密码才能访问您的帐户。这增加了保护您的帐户免受未经授权访问的可能性。
TOTP是HOTP的一个变种,将HOTP中的计数器C替换为依托时间的参数T,T是由当前时间(CurrentUnixTime、初始时间(T0)、步长(X)决定的。即:
$$ T = (Current Unix time - T0) / X $$
复制
CurrentUnixTime:当前的Unix时间。
T0: 开始计步初始化时间,默认为0
X : 步长,默认情况下为30s
TOTP 是谷歌 Authenticator 中使用的基于时间的动态密码算法,提供了一种增强的身份验证机制,以确保只有授权用户能够访问其帐户。
2.认证流程与原理
登录成功,由服务端程序生成随机秘钥,通过二维码返回给客户端
authenticator客户端扫描二维码或者手动输入秘钥进行绑定
应用程序使用authenticator生成的验证码请求服务端验证
三、springboot集成authenticator
1.引入依赖
<dependency> <groupId>com.warrenstrange</groupId> <artifactId>googleauth</artifactId> </dependency> <dependency> <groupId>com.google.zxing</groupId> <artifactId>javase</artifactId> </dependency>
googleauth 是一个开源的 Java 库,用于在 Java 应用程序中实现谷歌 Authenticator 功能。它提供了一组类和方法,让开发人员能够轻松地集成谷歌 Authenticator 的功能到他们的 Java 应用程序中。googleauth 库使用谷歌 Authenticator 的算法来生成一次性密码,并提供了验证这些密码的功能。
2.编写实现
编写生成秘钥、二维码以及code验证工具类:
@Slf4j
@Service
public class GoogleAuthenticatorService {
private static final GoogleAuthenticator googleAuthenticator = new GoogleAuthenticator();
private static final String KEY_FORMAT = "otpauth://totp/%s?secret=%s";
private static final String IMAGE_EXT = "png";
private static final int WIDTH = 300;
private static final int HEIGHT = 300;
@Autowired
private UserDao userDao;
@PostConstruct
public void init() {
googleAuthenticator.setCredentialRepository(new ICredentialRepository() {
@Override
public String getSecretKey(String userName) {
return userDao.getSecretKey(userName);
}
@Override
public void saveUserCredentials(String userName, String secretKey, int validationCode, List<Integer> scratchCodes) {
userDao.saveUserCredentials(userName, secretKey);
}
});
log.info("GoogleAuthenticator初始化成功...");
}
/**
* 生成二维码链接
*/
private String getQrUrl(String username) {
//调用createCredentials都会生成新的secretKey
GoogleAuthenticatorKey key = googleAuthenticator.createCredentials(username);
log.info("username={},secretKey={}", username, key.getKey());
return String.format(KEY_FORMAT, username, key.getKey());
}
/**
* 验证code
*/
public boolean validCode(String username, int code) {
return googleAuthenticator.authorizeUser(username, code);
}
/**
* 生成二维码
*/
public void genQRImage(String username, ServletOutputStream stream) {
try {
String content = getQrUrl(username);
BitMatrix bm = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, WIDTH, HEIGHT);
MatrixToImageWriter.writeToStream(bm, IMAGE_EXT, stream);
} catch (WriterException | IOException e) {
log.error("occur error",e);
}
}
}编写逻辑入口:
@Slf4j
@Controller
public class IndexController {
@Autowired
private GoogleAuthenticatorService googleAuthenticatorService;
/**
* 二次验证,生成二维码
*/
@RequestMapping("/qrcode")
public void qrcode(String username, HttpServletResponse response) {
try (ServletOutputStream stream = response.getOutputStream()) {
googleAuthenticatorService.genQRImage(username, stream);
} catch (IOException e) {
log.error("occur error", e);
}
}
/**
* 二次验证,输入google authenticator上的6位数字,成功跳转到首页
*/
@RequestMapping("/verify")
public String verify(String username, int code) {
boolean validCode = googleAuthenticatorService.validCode(username, code);
if (validCode){
return "index";
}
return "error";
}
}3.使用方式
用户下载authenticator,如果已经下载可跳过
使用账密登录系统,如果没有绑定过authenticator,弹出二维码
使用authenticator扫描二维码进行秘钥绑定,如果已经绑定过跳过
使用authenticator生成的6为数字输入到系统进行验证
https://cloud.tencent.com/developer/article/2310461?areaId=10600