密码重置令牌
在实现 send_password_reset_email()
函数之前,我需要一种方法来生成密码重置链接,它将被通过电子邮件发送给用户。 当链接被点击时,将为用户展现设置新密码的页面。 这个计划中棘手的部分是确保只有有效的重置链接可以用来重置帐户的密码。
生成的链接中会包含 令牌 ,它将在允许密码变更之前被验证,以证明请求重置密码的用户是通过访问重置密码邮件中的链接而来的。JSON Web Token(JWT)是这类令牌处理的流行标准。 JWTs 的优点是它是自成一体的,不但可以生成令牌,还提供对应的验证方法。
如何运行 JWTs?让我们通过 Python shell 来学习一下:
>>> import jwt
>>> token = jwt.encode({'a': 'b'}, 'my-secret', algorithm='HS256')
>>> token
b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhIjoiYiJ9.dvOo58OBDHiuSHD4uW88nfJikhYAXc_sfUHq1mDi4G0'
>>> jwt.decode(token, 'my-secret', algorithms=['HS256'])
{'a': 'b'}
{'a':'b'}
字典是要写入令牌的示例有效载荷。 为了使令牌安全,需要提供一个秘密密钥用于创建加密签名。 在这个例子中,我使用了字符串 'my-secret'
,但是在应用中,我将使用配置中的 SECRET_KEY
。 algorithm
参数指定使用什么算法来生成令牌,而 HS256
是应用最广泛的算法。
如你所见,得到的令牌是一长串字符。 但是不要认为这是一个加密的令牌。 令牌的内容,包括有效载荷,可以被任何人轻易解码(不相信我?复制上面的令牌,然后粘贴在 JWT 调试器 上就可以看到它的内容)。 使令牌安全的是,有效载荷是 被签名的 。 如果有人试图伪造或篡改令牌中的有效载荷,则签名将会无效,并且生成新的签名依赖秘密密钥。 令牌验证通过时,有效负载的内容将被解码并返回给调用者。 如果令牌的签名验证通过,有效载荷才可以被认为是可信的。
我要用于密码重置令牌的有效载荷格式为 {'reset_password':user_id,'exp':token_expiration}
。 exp
字段是 JWTs 的标准,如果它存在,则表示令牌的到期时间。 如果一个令牌有一个有效的签名,但是它已经过期,那么它也将被认为是无效的。 对于密码重置功能,我会给这些令牌 10 分钟的有效期。
当用户点击电子邮件链接时,令牌将被作为 URL 的一部分发送回应用,处理这个 URL 的视图函数首先要做的就是验证它。 如果签名是有效的,则可以通过存储在有效载荷中的 ID 来识别用户。 一旦得知用户的身份,应用可以要求一个新的密码,并将其设置在用户的帐户上。
由于这些令牌属于用户,因此我将在 User
模型中编写令牌生成和验证的方法:
from time import time
import jwt
from app import app
class User(UserMixin, db.Model):
# ...
def get_reset_password_token(self, expires_in=600):
return jwt.encode(
{'reset_password': self.id, 'exp': time() + expires_in},
app.config['SECRET_KEY'], algorithm='HS256').decode('utf-8')
@staticmethod
def verify_reset_password_token(token):
try:
id = jwt.decode(token, app.config['SECRET_KEY'],
algorithms=['HS256'])['reset_password']
except:
return
return User.query.get(id)
get_reset_password_token()
函数以字符串形式生成一个 JWT 令牌。 请注意, decode('utf-8')
是必须的,因为 jwt.encode()
函数将令牌作为字节序列返回,但是在应用中将令牌表示为字符串更方便。
verify_reset_password_token()
是一个静态方法,这意味着它可以直接从类中调用。 静态方法与类方法类似,唯一的区别是静态方法不会接收类作为第一个参数。 这个方法需要一个令牌,并尝试通过调用 PyJWT 的 jwt.decode()
函数来解码它。 如果令牌不能被验证或已过期,将会引发异常,在这种情况下,我会捕获它以防止出现错误,然后将 None
返回给调用者。 如果令牌有效,那么来自令牌有效负载的 reset_password
的值就是用户的 ID,所以我可以加载用户并返回它。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论