上一章中还有一个itsdangerous包没有讲,itsdangerous 包可以用来生成包含用户 id 的安全令牌。因为一般来说确认邮件中最简单的确认链接是 http://www.xxx.com/auth/confirm/<id>
这种形式的URL,其中 id 是数据库分配给用户的数字 id。但是如果被用户识别出了这种格式,那么只需修改id值就可以确认任意的账户,显然这样是违规的。所以这里就需要itsdangerous包来生成一个令牌。
我们可以使用itsdangerous包中的TimedJSONWebSignatureSerializer
类生成具有过期时间的 JSON Web 签名。其中的dumps()
方法为指定的数据生成一个加密签名,然后再对数据和签名进行序列化,生成令牌字符串。expires_in
参数设置令牌的过期时间,单位为秒。OK,将此功能加入User模型中。
from . import db
from werkzeug.security import generate_password_hash, check_password_hash
from . import login_manager
from flask.ext.login import UserMixin, AnonymousUserMixin
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from flask import current_app
class User(UserMixin, db.Model):
__tablename__ = 'users'
...
def generate_confirmation_token(self, expiration=3600):
s = Serializer(current_app.config['SECRET_KEY'], expiration)
return s.dumps({'confirm': self.id})
def confirm(self, token):
s = Serializer(current_app.config['SECRET_KEY'])
try:
data = s.loads(token)
except:
return False
if data.get('confirm') != self.id:
return False
self.confirmed = True
db.session.add(self)
return True
上面出现了一个loads()
方法,这个方法会检验签名和过期时间,如果通过,返回原始数据。如果提供给 loads()
方法的令牌不正确或过期了,则抛出异常,其唯一的参数是令牌字符串。
接下来需要做发送确认邮件的功能,当前的 /register
路由把新用户添加到数据库中后,会重定向到/index
。在重定向之前,这个路由需要发送确认邮件。这个功能参考《Flask Web开发》这本书就可以了,我是拿QQ邮箱作为发送端的,所以我就只讲一下QQ邮箱配置需要注意的地方,在config.py
文件中的配置如下。
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config:
...
FLASKY_MAIL_SUBJECT_PREFIX = '[DXFORUM]'
FLASKY_MAIL_SENDER = 'DXFORUM Admin <XXXXXXX@qq.com>'
FLASKY_ADMIN = os.environ.get('DXFORUM_ADMIN')
MAIL_SERVER = 'smtp.qq.com'
MAIL_PORT = 465
MAIL_USE_SSL = True
MAIL_USERNAME = 'XXXXXXX@qq.com'
MAIL_PASSWORD = 'XXXXXXXXXXX'
DEBUG = True
@staticmethod
def init_app(app):
pass
config ={ 'default': Config }
端口号465,MAIL_USERNAME
是你的QQ邮箱地址,MAIL_PASSWORD
是你QQ邮箱SMTP服务生成的授权码,获取步骤如下:
进入邮箱,点击设置,选择账户
一直往下拉,找到POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务一栏
只有开启了你的SMTP服务才能成功发送邮件,我这边是已经开启了,然后点击生成授权码,把生成的授权码复制填入MAIL_PASSWORD
中即可。当然,MAIL_USERNAME
和MAIL_PASSWORD
这两个应该在环境配置中配置才更加稳妥,这里只是作为说明写在config.py
中。
完成之后运行网站就可以去测试一下自己的注册功能是否成功实现,这里我还踩到一个坑,需要讲清楚。我在用确认邮件来确认注册账户的时候,flash消息提示已经成功验证您的账户,但是数据库中confirmed
的值仍然为0,也就是说还是处于未验证状态。后来整了好久发现这个数据根本就没有被提交,应当在User模型中的confirm方法中添加db.session.commit()
方法。
但是书中并没有写,这是因为它在配置文件中配置时写了SQLALCHEMY_COMMIT_ON_TEARDOWN = True
这个配置键,这个配置键的作用我在第二章写过,是用于每次request自动提交db.session.commit()
,而且我还写了这个配置键在最新版的Flask-SQLAlchemy中这个配置键已经被移除了,无需配置。Flask-SQLAlchemy 的 Changelog 文档里可以看出确实被移除了。
在查看完我的Flask-SQLAlchemy版本确认是最新版的之后,现在我只能说,它只是从文档中移除了,而没有从代码中移除,所以还是可以配置使用的。为了方便起见,我还是选择配置了,当然也可以自己去多加一个db.session.commit()
方法,这无关紧要。