《Flask Web开发:基于Python的Web应用开发实战》学习笔记(二)

转载于:http://pdf.us/2017/10/05/492.html,感谢这位大神

《Flask Web开发:基于Python的Web应用开发实战》学习笔记

这里是第二部分的学习笔记。第二部分:实例:社交博客程序

第八章 用户认证

用到的扩展

Flask-Login:管理已登录用户的用户会话
Werkzeug:计算密码散列并核对
istdangerous:生成并核对加密安全令牌Flask-Mail:发送与认证相关的密码
Flask-Bootstrap:HTML模板
Flask-WTF:Web表单
使用Werkzeug实现密码散列

Werkzeug的security模块可以实现计算密码散列。主要用于用户注册和验证用户。

generate_password_hash(password,method=pbkdf2:sha1,salt_length=8)  以密码作为输入,输出密码的散列值

check_password_hash(hash,password)  返回True即表示验证通过

程序从7a版本开始推进。数据库改用mysql。先不要建表,db init;db migrate;db upgrade生成当前数据库。

对app/models.py中User模型做改造:

关于@property@password.setter装饰器
把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@password.setter,负责把一个setter方法变成属性赋值
简单讲,@property附加到那个方法上,该方法变为同名属性,并只具有读属性
而要设置属性的值,需要使用另外一个方法,并附加@方法名.setter,这样提供了写属性
一句话就是对属性读写分别处理,如果没有setter,则属性为只读

hash后的加密串,即使相同的密码加密,hash串也不相同

该功能的单元测试用例:

创建认证蓝本

对于不同的程序功能,使用不同的蓝本,这样可以使代码保持整齐有序。

蓝本:auth/__init__.py

auth/views.py

auth/login.html位于app/templates/目录下。当然,蓝本也可以定义自己的模板文件夹,此时,render_template()会先搜索程序文件夹,再搜索蓝本配置的模板文件夹。

在create_app函数中附加蓝本auth到程序:app/__init__.py

url_prefix是可选参数,使用该参数后,蓝本中定义的所有路由都会加上指定前缀,这里,/login变成了/auth/login。

使用Flask-Login认证用户

pip install flask-login

使用Flask-Login扩展,User模型需要实现如下几个方法:

属性/方法说明
is_authenticated若用户已登录,则返回True,否则返回False
is_active若允许用户登录,则返回True,否则返回False;禁用用户,可返回False
is_anonymous对普通用户返回False
get_id()必须返回用户唯一标识符,使用Unicode编码

这四个方法可以直接在User类中实现,更简单的方法是使用Flask-Login提供的UserMixin类。

app/modles.py

初始化:app/__init__.py

session_protection可设置为None,'basic','strong',当设置为‘strong'时,会记录客户端IP和浏览器用户代理信息,发现异动就登出用户。

Flask-Login要求实现一个回调函数,使用指定的标识符加载用户:app/models.py

回调函数接收以Unicode字符串形式表示的用户标识符,若存在该用户,则返回用户对象,否则返回None

保护路由

让一个路由仅让认证的用户能访问,未认证用户访问,Flask-Login会拦截请求,把用户发往登录页面,示例如下:

添加登录表单

app/auth/forms.py

app/templates/base.html

<ul class="nav navbar-nav navbar-right">
{% if current_user.is_authenticated %}
<li><a href="{{ url_for('auth.logout') }} ">Sign Out</a></li>
{% else %}
<li><a href="{{ url_for('auth.login') }}">Sign In</a></li>
{% endif %}
</ul>

current_user由Flask-Login定义, 在视图函数和模板中自动可用,这个变量的值是当前登录的用户,若未登录,则是匿名用户代理对像。

登入用户

app/auth/views.py

app/templates/auth/login.html

 

{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Flasky - Login{% endblock %}

{% block page_content %}
<div class="page-header">
<h1>Login</h1>
</div>
<div class="col-md-4">
{{ wtf.quick_form(form) }}
</div>
{% endblock %}

 

登出用户

app/auth/views.py

测试登录

shell中注册新用户

>>> u=User(email='[email protected]',username='ma',password='admin')
>>> db.session.add(u)
>>> db.session.commit()
{% if current_user.is_authenticated %}
{{ current_user.username }}
{% else %}
Stranger
{% endif %}
注册新用户

用户注册表单:

注意,validator是复数:validators

其中,验证函数Regexp是正则表达式验证,第一个参数是正则表达式(包含字母、数字、下划线和点),第二个是表达式的旗标(通常为0),第三个是匹配失败时的错误消息。

密码的验证使用EqualTo,放到任意一个就可以,另一个字段做为参数传入。

自定义的验证函数:以validate_开头,后面跟字段名的方法。该方法会和常规验证函数一起调用。

注册表单的渲染:

{% import "bootstrap/wtf.html" as wtf %}
{{ wtf.quick_form(form) }}

注册新用户的视图函数:

确认帐户

验证邮箱,通过点击包含令牌的URL,修改标记状态。

itsdangerous提供多种生成令牌方法,其中TimedJSONWebSignatureSerializer类生成具有过期时间的JSON Web签名,该类构造函数接收参数是一个密钥和过期时间(秒)。dumps方法为指定数据生成加密的令牌字符串,load方法解码令牌。

python manage.py shell
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
s=Serializer(app.config['SECRET_KEY'],expires_in=3600)
token=s.dumps({'confirm':23})   #生成token,签名字符串
data=s.loads(token)                   #data={u'confirm':23}

修改模型:app/models.py

发送确认邮件

app/auth/views.py

因为只有提交数据库后才能够得到新用户id,而生成token需要用到用户id,所以需要添加db.session.commit()

模板:{{ url_for('auth.confirm',token=token,_external=True) }}

确认token:

蓝本中的程序全局请求钩子-before_app_request

重新发送确认邮件

管理帐户

修改密码

重设密码

修改电子邮件

先确认邮件进行确认,输入新邮件地址后,向该邮件地址发送一封包含令牌的邮件。服务器发送令牌前,可先将邮件地址存到临时表或者是直接存到token中。

第九章 用户角色

角色在数据库中的表示

app/models.py,添加两个属性

default = db.Column(db.Boolean,default=False,index=True)
permissions = db.Column(db.Integer)

其中permissions字段使用二进制位表示不同的权限。

权限常量:

class Permission:
FOLLOW=0x01                                 #0b00000001关注其它用户
COMMENT=0x02                             #0b00000010在他人文章后发表评论
WRITE_ARTICLES=0x04                    #0b00000100写文章
MODERATE_COMMENTS=0x08       #0b00001000管理他人发表的评论
ADMINISTER=0x80                           #0b10000000管理员

用户角色:

用户角色权限权限说明
匿名0b000000000x00未登录用户,仅阅读权限
用户0b000001110x07写文章,写评论,关注其他用户
协管员0b000011110x0f增加管理他人评论功能
管理员0b111111110xff所有权限,包括修改其它用户权限

通过insert_roles方法添加角色,使用shell操作,Role.insert_roles()

赋予角色

app/models.py

角色验证

添加辅助方法:app/models.py

can方法使用位与操作,检查用户权限。Anonymous类出于一致性考虑,无论用户是否登录,均可使用current_user.can()和current_user.is_administrator()方法来验证用户权限。

检查用户权限的自定义修饰器

app/decorators.py

自定义修饰器的使用方法

模板中也需要检查权限,为避免每次调用render_template()时都多添加一个模板参数,可以使用上下文处理器,上下文处理器能让变量在所有模板中全局可访问

app/main/__init__.py

@main.app_context_processor
def inject_permissions():
return dict(Permission=Permission)

第十章 用户资料

资料信息

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章