flask之用户角色和用户资料编辑
来源:互联网 发布:用友nc外部数据平台 编辑:程序博客网 时间:2024/06/03 23:49
效果图
这一章节完成后的效果如下:
- 1.普通用户
- 2.管理者
用户角色
- 1.在个人博客系统中用户分为4种分立角色,分别为管理员、协管员、普通用户和匿名用户,每种用户有不同的权限,下面在数据库中建立用户这张表。
class Role(db.Model): __tablename__ = 'roles' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String, nullable=True, unique=True) default = db.Column(db.Boolean, default=False) permissions = db.Column(db.Integer) users = db.relationship('User', backref='itsrole')
只有普通用户的default字段为True,其它都默认为False。permissions字段是个整数,表示位操作,各操作都对应一个位位置,如果能执行某项操作的角色,其位被设为1。permissions各个权限位的表示如下:
* FOLLOW = 0x01
关注用户
* COMMENT = 0x02
在他人文章中发表评论
* WRITE_ARTICLES=0x04
写文章
* MODERATE_COMMENTS=0x08
管理他人评论
* ADMINISTER=0x80
管理员
- 2.下表列出了4种用户角色以及用户角色的权限,如果想要添加另外的角色,只需要使用不同的权限进行组合。在个人博客系统中用户分为4种分立角色,分别为管理员、协管员、普通用户和匿名用户,每种用户有不同的权限。
- 3.下面在app/models.py文件中创建一个静态方法函数,一次性插入所有角色,代码如下:
@staticmethod def insert_roles(): roles = { 'User':(Permission.FOLLOW|Permission.COMMENT| Permission.WRITE_ARTICLES, True), # 只有普通用户的default为True 'Moderare':(Permission.FOLLOW|Permission.COMMENT| Permission.WRITE_ARTICLES|Permission.MODERATE_COMMENTS, False), 'Administrator':(0xff, False) } for r in roles: role = Role.query.filter_by(name=r).first() if role is None: role = Role(name=r) role.permissions = roles[r][0] role.default = roles[r][1] db.session.add(role) db.session.commit()
- 4.把角色写入数据库中,使用shell会话:
(vent)$ python manage.py shell>>>Role.insert_roles()>>>Role.query.all() # 查看所有角色
赋予角色
- 1.用户在注册的时候,绝大多数都是普通用户,唯一的例外是管理者,管理员由保存在环境变量FLASK_ADMIN中的电子邮件识别,如果用户的邮箱与FLASK_ADMIN相同,那么该用户是管理员,其它的默认为普通用户,在User的构造函数中实现:
def __init__(self, **kwargs): super(User, self).__init__(**kwargs) # 初始化父类 if self.itsrole is None: if self.email == current_app.config['FLASK_ADMIN']: # 邮箱与管理者邮箱相同 self.itsrole = Role.query.filter_by(permissions=0xff).first() # 权限为管理者 else: self.itsrole = Role.query.filter_by(default=True).first() # 默认用户
在构造函数中先初始化父类的构造函数,带上参数**kwargs。如果用户邮箱匹配坏境变量中的FLASK_ADMIN
,该用户为管理员。
角色验证
- 1.在很多情况下会对用户的权限进行验证,判断用户是否能够执行相应的权限操作,在User类中定义监测权限的函数,该
can()
方法对用户的赋予角色和请求角色权限进行位与操作,返回True即用户允许执行此操作。同时还定义了一个匿名类,继承AnonymousUser,如果用户未登陆时,current_user
即匿名用户,代码如下:
from flask_login import UserMixin, AnonymousUserMixinclass User(UserMixin, db.Model): def can(self, permissions): # 检查用户的权限 return self.itsrole is not None and \ (self.itsrole.permissions & permissions) == permissions def is_administrator(self): # 检查是否为管理者 return self.can(Permission.ADMINISTRATOR)class AnonymousUser(AnonymousUserMixin): # 匿名用户 def can(self, permissions): return False def is_administrator(self): return Falselogin_manager.anonymous_user = AnonymousUser # 将其设为用户未登陆时的current_user的值
- 2.经过上面代码的实现,
current_user
无论在匿名还是登陆情况下,都可以调用can
和is_administrator
函数。
视图函数对特定的用户开放
- 1.使用装饰器对函数进行包装,让一些视图函数只对特定的用户开放。装饰器的使用方法可以看下廖雪峰老师的教程,链接为http://www.liaoxuefeng.com。在app目录下新建一个decorators.py文件,如果没有权限,则直接进入403禁止页面。需要额外编写一个403.html。
from functools import wrapsfrom flask import abortfrom flask_login import current_userfrom .models import Permission# 装饰器函数,带参数,3层函数def permission_required(permissions): def decorator(f): @wraps(f) def wrapper(*args, **kwargs): if not current_user.can(permissions): abort(403) return f(*args, **kwargs) return wrapper return decorator# 调用上面装饰器函数def admin_required(f): return permission_required(Permission.ADMINISTRATOR)(f) # 带参数,且传递函数
- 2.下面两个函数给出如何使用上面定义的装饰器函数,在app/main/views.py文件中
from flask_login import login_required, current_userfrom ..decorators import admin_required, permission_required@main.route('/admin') # 在登陆状态下只允许管理者进入,否则来到403禁止登陆界面@login_required@admin_requireddef for_admin_only(): return u'管理者进入'@main.route('/moderator')@login_required@permission_required(Permission.MODERATE_COMMENTS)def for_moderator_only(): return u'协管员进入'
用户资料信息
- 1.在导航栏创建个人资料分类,用户可以编写自己的个人信息,在models.py文件中给User添加几个字段
from . import dbclass User(UserMixin, db.Model): name = db.Column(db.String(64)) # 用户信息中的昵称 location = db.Column(db.String(64)) # 用户地址 about_me = db.Column(db.Text()) # 用户介绍 member_since = db.Column(db.DATETIME(), default=datetime.utcnow) # 注册时间,datetime.utcnow不用带上括号 last_seen = db.Column(db.DATETIME(), default=datetime.utcnow) # 上次访问时间
新添加的字段包括昵称、地址、关于我、注册时间和上次访问时间。两个与时间相关的字段的默认值为都为datetime.utcnow
,后面不需要带(),default接受函数作为默认值。上次访问时间是每次都需要刷新的,在before_app_request
每次在请求前执行该函数,可以刷新上次访问时间。
- 2.刷新上次访问时间,在app/models.py中
class User(UserMixin, db.Model): def ping(self): self.last_seen = datetime.utcnow() # 刷新上次访问时间 db.session.add(self) db.session.commit()
- 3.在
before_app_request
每次在请求前执行该函数,在app/auth/views.py中
@auth.before_app_request # 用户已登陆、用户帐号还未确认、请求的的端点不在auth认证蓝本中def before_request(): if current_user.is_authenticated: current_user.ping() # 在每次请求前刷新上次访问时间 if not current_user.confirmed \ and request.endpoint[:5] != 'auth.': return redirect(url_for('auth.unconfirmed'))
用户资料页面
- 1.定义一个资料页面的路由很简单,从数据库中找到用户,传给模板进行渲染
@main.route('/user/<username>')def user(username): user = User.query.filter_by(username=username).first() if user is None: abort(404) return render_template('user.html', user=user)
模板user.html的编写可以到文章最底端的github链接中去查看。
2.编辑用户资料页面,普通用户和管理员的编辑是不一样的,普通用户只能编辑自己的信息,而管理员可以编辑所有用户的信息。
- 普通用户表单
# 普通用户登陆表单class EditProfileForm(FlaskForm):name = StringField(label=u'真实姓名', validators=[Length(0,64)])location = StringField(label=u'地址', validators=[Length(0,64)])about_me = TextAreaField(label=u'关于我')submit = SubmitField(label=u'提交')
- 管理员表单
# 管理员登陆表单,能编辑用户的电子邮件,用户名,确认状态和角色class EditProfileAdministratorForm(FlaskForm):email = StringField(label=u'邮箱', validators=[DataRequired(), Length(1,64), Email()])username = StringField(label=u'用户名', validators=[DataRequired(), Length(1, 64)])confirmed = BooleanField(label=u'确认')role = SelectField(label=u'角色', coerce=int)name = StringField(label=u'真实姓名', validators=[Length(0, 64)])location = StringField(label=u'地址', validators=[Length(0, 64)])about_me = TextAreaField(label=u'关于我')submit = SubmitField(label=u'提交')# 初始化时要对role的复选框进行搭建def __init__(self, user, *args, **kwargs): super(EditProfileAdministratorForm, self).__init__(*args, **kwargs) self.role.choices = [(role.id, role.name) for role in Role.query.order_by(Role.name)] self.user = user
- 3.编辑资料路由,同样也分别普通用户的编辑和管理员的编辑
# 普通用户级别的编辑@main.route('/edit-profile',methods=['GET','POST'])@login_requireddef edit_profile(): form = EditProfileForm() if form.validate_on_submit(): current_user.name = form.name.data current_user.location = form.location.data current_user.about_me = form.about_me.data flash(u'你的个人信息已经被更改') db.session.add(current_user) # 更新个人资料 db.session.commit() return redirect(url_for('main.user', username=current_user.username)) form.name.data = current_user.name form.location.data = current_user.location form.about_me.data = current_user.about_me return render_template('edit_profile.html',form=form)# 管理员级别的编辑@main.route('/edit-profile/<int:id>',methods=['GET','POST'])@login_required@admin_requireddef edit_profile_admin(id): user = User.query.get_or_404(id) # 查找这个用户 form = EditProfileAdministratorForm(user=user) if form.validate_on_submit(): user.email = form.email.data user.username = form.username.data user.confirmed = form.confirmed.data user.itsrole = Role.query.get(form.role.data) user.name = form.name.data user.location = form.location.data user.about_me = form.about_me.data db.session.add(user) db.session.commit() flash(u'该用户的信息已经更新了') return redirect(url_for('main.user',username=user.username)) form.email.data = user.email form.username.data = user.username form.confirmed.data = user.confirmed form.role.data = user.role_id # role_id 与 itsrole是关联的 form.name.data = user.name form.location.data = user.location form.about_me.data = user.about_me return render_template('edit_profile.html',form=form,user=user)
4.为了让用户能找到编辑链接,在app/templates/user.html中加入编辑链接
{% if user == current_user %} <a class="btn btn-default" href="{{ url_for('main.edit_profile') }}"> 编辑信息 </a> {% endif %}
Github链接
https://github.com/happyte/flask-blog,里面上传了个人博客系统的代码
- flask之用户角色和用户资料编辑
- FLASK(9)-用户角色
- Flask(10)-用户资料
- Flask Web 开发 用户角色
- Flask Web 开发 用户资料
- 【Flask】Flask之用户指导
- flask笔记:7:用户资料信息页和头像
- Oracle操作管理之用户和角色
- Oracle之用户、特权和角色
- 数据库Oracle之用户、角色和权限
- 关于收集的用户和角色的资料
- Oracle 用户和角色
- Oracle:用户和角色
- 用户、权限和角色
- 用户、角色和权限
- Oracle用户和角色
- Flask Web 开发 用户资料_2
- Flask Web 开发 用户资料_3
- [Unity3D]射线碰撞检测+LayerMask的使用
- mssql在JDBC通用更新时出现 不支持从 UNKNOWN 到 UNKNOWN 的转换。
- 我也遇到这种情况
- Hadoop学习笔记 --- hadoop1.0 与 hadoop 2.0架构图
- Udacity笔记
- flask之用户角色和用户资料编辑
- 网络爬虫之scrapy学习之安装和工程创建
- 数据结构与算法分析之01绪论
- android自定义View之五子棋小游戏
- 如何快速转载CSDN中的博客
- [BZOJ3295][Cqoi2011]动态逆序对
- python os模块常用命令
- IOS中使用UITableViewCell的按钮事件
- 【BZOJ 3157, 3516, 4126】 国王奇遇记 - 极致的组合数学