关于 OTP 的介绍与实现见 OTP 介绍与实现

    使用 pyotp 可以方便地计算 OTP,不用自己实现了。

    HOTP:

    1. import pyotp
    2. import base64
    3. secret = "12345678901234567890"
    4. b32secret = base64.b32encode(secret.encode()).decode()
    5. hotp = pyotp.HOTP(b32secret)
    6. # 计算 HOTP
    7. hotp.at(0) # => '755224'
    8. hotp.at(1) # => '287082'
    9. # 校验 HOTP
    10. hotp.verify('755224', 0) # => True
    11. hotp.verify('755224', 1) # => False

    TOTP:

    1. import pyotp
    2. import base64
    3. from datetime import datetime
    4. secret = "12345678901234567890"
    5. b32secret = base64.b32encode(secret.encode()).decode()
    6. totp = pyotp.TOTP(b32secret)
    7. # 计算当前时间的 TOTP(方式一)
    8. totp.now()
    9. # 计算当前时间的 TOTP(方式二)
    10. now = datetime.now()
    11. totp.at(now)
    12. totp.interval - now.timestamp() % totp.interval # 可以这样计算出 TOTP 的剩余有效时间
    13. # 校验 TOTP
    14. totp.verify('755224')
    15. totp.verify('755224', datetime.now())

    :::info 使用 pyotp 时,secret 要先 base32 编码再传入 HOTP 或 TOTP 对象中,pyotp 会在其内部解码,使用解码后的值计算 OTP。
    关于为什么要先 base32 编码,pyotp 中再解码,而不是直接传入 secret 的原因暂不知。 :::