记录一下使用flask_security过程中遇到的一些坑。
在templates文件夹中创建security文件夹,创建要替换的同名html文件即可。
创建Form对象,(最好继承自flask_security默认的Form,默认给提供了很多表单验证方法。)在创建Security对象时指明即可,如下:
security = Security(
app, user_datastore,
confirm_register_form=ExtendConfirmRegisterForm,
login_form=ExtendLoginForm,
reset_password_form=ExtendResetPasswordForm,
forgot_password_form=ExtendForgetPasswordForm,
change_password_form=ExtendChangePasswordForm
)
注意:
1、需要邮箱认证的注册表单和不需要邮箱认证的注册表单不同。confirm_register_form,register_form。
2、默认的ForgotPasswordForm的email字段(StringField)有一个验证器(validator)名为valid_user_email,这个验证器会根据邮箱值(账号)查询数据库,验证用户输入的账号(邮箱)是否存在,将结果赋值给form.user。默认ForgotPasswordForm还自定义了一个validate,
def validate(self):
if not super(ForgotPasswordForm, self).validate():
return False
if requires_confirmation(self.user):
self.email.errors.append(get_message('CONFIRMATION_REQUIRED')[0])
return False
return True
requires_confirmation方法需要参数self.user这个值是valid_user_email验证成功(此账号存在)后得到的。
如果你自定义一个ForgotPasswordForm虽然继承了默认的ForgotPasswordForm。但是你要是覆盖默认的email字段的话,此StringField对象没有valid_user_email。所以不会给self.user赋值,在调用requires_confirmation时,会报错。
错误信息如下:
File "/home/sheng/.local/lib/python3.6/site-packages/flask_security/confirmable.py", line 63, in requires_confirmation
user.confirmed_at is None)
AttributeError: 'NoneType' object has no attribute 'confirmed_at'
解决方法:
1、从flask_security.forms中import该验证器valid_user_email,添加至自定义的email字段(StringField对象)的validators属性中。
2、使用默认的email字段
方法一:配置SECURITY_UNAUTHORIZED_VIEW = lambda :’/unauthorized’,不能是字符串,/unauthorized是url,需要自定义视图函数。
方法二:装饰器@security.unauthorized_handler
3 中的方法无法修改默认的login_required验证失败跳转的页面。login_required是flask_login中的用于用户登录验证的装饰器。我们需要用LoginManager对象的unauthorized_handler装饰器。flask_security会为当前app对象添加login_manager对象,我们可以这样使用:
@app.login_manager.unauthorized_handler
def unauthorized():
abort(403)
security对象中有当前app对象,你也可以这样使用:
@security.app.login_manager.unauthorized_handler
def unauthorized():
abort(403)
如果Message对象中没有指明发送者(sender),需要配置默认的发送者(SECURITY_EMAIL_SENDER),不然会报错:
File "/home/sheng/anaconda3/envs/chatbot/lib/python3.7/site-packages/flask_mail.py", line 105, in sanitize_address
nm, addr = addr
ValueError: too many values to unpack (expected 2)
需设置SECURITY_TRACKABLE = True
User类需要添加如下字段(字段名必须如下所示):
last_login_at = DateTimeField()
current_login_at = DateTimeField()
last_login_ip = StringField()
current_login_ip = StringField()
login_count = IntField(default=0)
注意: 需要修改配置SECURITY_DATETIME_FACTORY 为datetime.datetime.now,默认为datetime.datetime.utcnow返回的是UTC(协调世界时即格林威治平太阳时间,标准时间)时间,与北京时间相差8小时。