关于 OTP 的介绍与实现见 OTP 介绍与实现。
使用 pyotp 可以方便地计算 OTP,不用自己实现了。
HOTP:
import pyotp
import base64
secret = "12345678901234567890"
b32secret = base64.b32encode(secret.encode()).decode()
hotp = pyotp.HOTP(b32secret)
# 计算 HOTP
hotp.at(0) # => '755224'
hotp.at(1) # => '287082'
# 校验 HOTP
hotp.verify('755224', 0) # => True
hotp.verify('755224', 1) # => False
TOTP:
import pyotp
import base64
from datetime import datetime
secret = "12345678901234567890"
b32secret = base64.b32encode(secret.encode()).decode()
totp = pyotp.TOTP(b32secret)
# 计算当前时间的 TOTP(方式一)
totp.now()
# 计算当前时间的 TOTP(方式二)
now = datetime.now()
totp.at(now)
totp.interval - now.timestamp() % totp.interval # 可以这样计算出 TOTP 的剩余有效时间
# 校验 TOTP
totp.verify('755224')
totp.verify('755224', datetime.now())
:::info
使用 pyotp 时,secret 要先 base32 编码再传入 HOTP 或 TOTP 对象中,pyotp 会在其内部解码,使用解码后的值计算 OTP。
关于为什么要先 base32 编码,pyotp 中再解码,而不是直接传入 secret 的原因暂不知。
:::