背景
最近在为 流苏云计算 的计算节点写一个 Nova 计算组件、Ceilometer 监控组件的辅助系统,本身没有对外提供 Api 服务,仅仅通过消息队列通信,但是就是硬想整活,便将 Ward 用 Solon 重写整合进了 Leaf 组件。
但是这样就有了个大问题,这界面可不能随便就让陌生人访问到,应该怎么保护呢?密码?不行,太 Low 了,咱还是要整活,于是便采用了 用户名 + TOTP 的方式。
实现??
懒~
所以我才不会选择用网上的代码片段来拼 TOTP 实现,咱直接用现成的:# jchambers/java-otp,实现 TOTP 不是轻轻松松的么!
final TimeBasedOneTimePasswordGenerator totp = new TimeBasedOneTimePasswordGenerator();
final KeyGenerator keyGenerator = KeyGenerator.getInstance(totp.getAlgorithm());
// Key length should match the length of the HMAC output (160 bits for SHA-1, 256 bits
// for SHA-256, and 512 bits for SHA-512). Note that while Mac#getMacLength() returns a
// length in _bytes,_ KeyGenerator#init(int) takes a key length in _bits._
final int macLengthInBytes = Mac.getInstance(totp.getAlgorithm()).getMacLength();
keyGenerator.init(macLengthInBytes * 8);
final SecretKeySpec secretKey = keyGenerator.generateKey();
只要拿着生成的密钥生成二维码用 Google Authenticator 扫一下不就能用了!哎,等等,SecretKeySpec 是个啥,我咋从来没见过?toString() 一下?别说运行了,IDEA 都提示这样不行了,这是咋回事?
实现?
网上查过资料以后发现,SecretKeySpec 可以通过 getEncoded() 获取到内部的密钥,是个 byte[] 形式的,这不好说嘛 new String(secretKey.getEncoded())
,运行试试:
L3Û5¯0Ûæù?Þ®zKå
???
这啥?算了管它呢,套进 URL 里面生成二维码扫一下试试:
进不去 ,怎么想都进不去吧
那那那,咱用 Base64 加密下试试?
进不去 ,怎么想都进不去吧
实现
果然,图快是快不了的,还是看看别人的代码怎么实现的吧:
/**
* 生成唯一密钥
*
* @return
*/
public static String generateSecretKey() {
// UUID + 4位随机字符生成唯一标识
String uniqueId = UUID.randomUUID() + RandomStringUtils.randomAlphabetic(4);
return new String(new Base32().encode(uniqueId.getBytes()));
}
Base32?好家伙原来是 Base32 加密。真是未曾设想的道路,那么这样我们就能或得到真正的 Secret 了:
new Base32().encodeToString(secretKey.getEncoded());
撒花~
Base32 为
Apache Common Codec
包中提供的类,需要 Maven 导入哦!