1.totp是什么
TOTP 是Time-based One-Time Password的简写,表示基于时间戳算法的一次性密码。 是时间同步,基于客户端的动态口令和动态口令验证服务器的时间比对,一般每60秒,或30秒产生一个新口令,要求客户端和服务器能够十分精确的保持正确的时钟,客户端和服务端基于时间计算的动态口令才能一致。
适用场景
- 服务器登录动态密码验证
- 公司VPN登录双因素验证
- 银行转账动态密码
- 网银、网络游戏的实体动态口令牌
- 等基于时间有效性验证的应用场景
2. jotp java实现
OTP (One Time Password) utility in Java. To enable two-factor authentication (2FA) using HMAC-based or Time-based algorithms.
官网:https://amdelamar.com/jotp/
pom文件引入依赖
<dependency> <groupId>com.amdelamar</groupId> <artifactId>jotp</artifactId> <version>1.3.0</version> </dependency>
使用
import com.amdelamar.jotp.OTP; import com.amdelamar.jotp.type.Type; //基于系统时间产生一个base32加密的随机密钥因子,根据密钥生成对应的验证码,验证码6位 // Random secret Base32 with 20 bytes (160 bits) length // (Use this to setup 2FA for new accounts). String secret = OTP.randomBase32(20); // Returns: IM4ZL3G5Q66KW4U7PMOQVXQQH3NGOCHQ // Generate a Time-based OTP from the secret, using Unix-time // rounded down to the nearest 30 seconds. String hexTime = OTP.timeInHex(System.currentTimeMillis()); String code = OTP.create(secret, hexTime, 6, Type.TOTP);
java示例
import org.jotp.TOTP;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
@Controller
public class AuthenticationController {
private static final String SECRET_KEY = "mysecretkey"; // 你需要为每个用户生成一个唯一的密钥
@GetMapping("/login")
public String showLoginForm() {
return "login";
}
@PostMapping("/login")
public String authenticate(@RequestParam String username, @RequestParam String password, @RequestParam String totpToken, Model model) {
boolean isAuthenticated = authenticateUser(username, password, totpToken);
if (isAuthenticated) {
return "redirect:/home";
} else {
model.addAttribute("error", "Invalid username, password, or TOTP token");
return "login";
}
}
private boolean authenticateUser(String username, String password, String totpToken) {
// 验证用户名和密码
// 在这里添加你的代码,从数据库中获取用户的凭据,并验证用户名和密码是否匹配
// 验证TOTP令牌
long timeWindow = 30; // TOTP令牌的时间窗口为30秒
int tokenLength = 6; // TOTP令牌长度为6位数
int validationWindow = 1; // 验证窗口为1个时间窗口
long currentTimestamp = System.currentTimeMillis() / 1000L;
long[] timeValues = {
currentTimestamp / timeWindow};
String[] totpValues = {
totpToken};
TOTP totp = new TOTP(SECRET_KEY, timeWindow, tokenLength);
boolean isValid = totp.verify(timeValues, totpValues, validationWindow);
return isValid;
}
}
在以上代码中,我们首先定义了一个名为SECRET_KEY的静态常量,用于存储每个用户的TOTP密钥。然后,我们实现了一个名为showLoginForm()的GET请求处理方法,用于显示登录表单。接着,我们实现了一个名为authenticate()的POST请求处理方法,用于验证用户的凭据和TOTP令牌。如果验证成功,则将用户重定向到主页;否则,将显示一个错误消息。
在authenticateUser()方法中,我们首先验证用户名和密码是否匹配。然后,我们使用JOTP库来验证TOTP令牌是否有效。需要注意的是,在实际应用中,你需要为每个用户生成一个唯一的密钥,并将其存储在数据库中。每个TOTP令牌都是基于密钥生成的,并且只有拥有正确密钥的人才能生成有效令牌。因此,你需要确保密钥是安全的,并且不会被泄露。
3.将生成的32位base32密钥保存到手机app
这里我们使用手机应用应用商城的 google authenticator ,不需要登录。
如何安装,请参考https://support.google.com/accounts/answer/1066447?hl=zh-Hans&co=GENIE.Platform%3DAndroid Google 身份验证器
网上大多是那种看了都不知道怎么办的文章,我就当给大家扫盲了,配置好后端和前端,你就可以根据自己的动态令牌去做一些安全验证了,一码在手,天下我有!