15 -Flask构建弹幕微电影网站-基于角色的访问控制基于角色的访问控制

本章内容: 基于角色的访问控制 已上线演示地址: http://movie.mtianyan.cn 项目源码地址:https://github.com/mtianyan/movie_project

基于角色的访问控制

角色的访问控制:

将职责和功能划分一个角色,比如电影管理员,预告管理员。

  1. 模型: Auth
  2. 表单: AuthForm
  3. 请求方法: GET POST
  4. 访问控制: @admin_login_req

首先定义authform

class AuthForm(FlaskForm):
    name = StringField(
        label="权限名称",
        validators=[
            DataRequired("权限名称不能为空!")
        ],
        description="权限名称",
        render_kw={
            "class": "form-control",
            "placeholder": "请输入权限名称!"
        }
    )
    url = StringField(
        label="权限地址",
        validators=[
            DataRequired("权限地址不能为空!")
        ],
        description="权限地址",
        render_kw={
            "class": "form-control",
            "placeholder": "请输入权限地址!"
        }
    )
    submit = SubmitField(
        '编辑',
        render_kw={
            "class": "btn btn-primary",
        }
    )

views中定义auth_add

权限添加

@admin.route("/auth/add/", methods=["GET", "POST"])
@admin_login_req
def auth_add():
    """
    添加权限
    """
    form = AuthForm()
    if form.validate_on_submit():
        data = form.data
        auth = Auth(
            name=data["name"],
            url=data["url"]
        )
        db.session.add(auth)
        db.session.commit()
        flash("添加权限成功!", "ok")
    return render_template("admin/auth_add.html",form=form)

将form传递到表单中,然后开始在模板中替换字段

mark

记得自行加上表单令牌

为字段添加错误信息:

mark

添加form表单的methods

mark

添加flash消息闪现的显示

mark

添加添加标签的权限

mark

mark

权限列表

views中

@admin.route("/auth/list/<int:page>/", methods=["GET"])
@admin_login_req
def auth_list(page=None):
    """
    权限列表
    """
    if page is None:
        page = 1
    page_data = Auth.query.order_by(
        Auth.addtime.desc()
    ).paginate(page=page, per_page=2)
    return render_template("admin/auth_list.html", page_data=page_data)

取出所有的数据然后进行时间排序。

pagedata传递到了模板,进行字段填充,import pg 然后调用page方法。

mark

mark

mark

grid中为跳转list的url添加page参数。

mark

编辑与删除功能实现

@admin.route("/auth/del/<int:id>/", methods=["GET"])
@admin_login_req
def auth_del(id=None):
    """
    权限删除
    """
    auth = Auth.query.filter_by(id=id).first_or_404()
    db.session.delete(auth)
    db.session.commit()
    flash("删除权限成功!", "ok")
    return redirect(url_for('admin.auth_list', page=1))


@admin.route("/auth/edit/<int:id>/", methods=["GET", "POST"])
@admin_login_req
def auth_edit(id=None):
    """
    编辑权限
    """
    form = AuthForm()
    auth = Auth.query.get_or_404(id)
    if form.validate_on_submit():
        data = form.data
        auth.url = data["url"]
        auth.name = data["name"]
        db.session.add(auth)
        db.session.commit()
        flash("修改权限成功!", "ok")
        redirect(url_for('admin.auth_edit', id=id))
    return render_template("admin/auth_edit.html", form=form, auth=auth)

为编辑和删除按钮添加url

mark

新建auth_edit.html复制auth_add的代码修改其中汉字部分以及填充值。

mark

mark

权限列表中添加展示消息闪现的部分。

mark

角色管理

  1. 模型: Role
  2. 表单: RoleForm
  3. 请求方法: GET POST
  4. 访问控制: @admin_login_req

角色权限列表中存入id的字符串。

首先创建一个form Roleform

class RoleForm(FlaskForm):
    name = StringField(
        label="角色名称",
        validators=[
            DataRequired("角色名称不能为空!")
        ],
        description="角色名称",
        render_kw={
            "class": "form-control",
            "placeholder": "请输入角色名称!"
        }
    )
    # 多选框
    auths = SelectMultipleField(
        label="权限列表",
        validators=[
            DataRequired("权限列表不能为空!")
        ],
        # 动态数据填充选择栏:列表生成器
        coerce=int,
        choices=[(v.id, v.name) for v in Auth.query.all()],
        description="权限列表",
        render_kw={
            "class": "form-control",
        }
    )
    submit = SubmitField(
        '编辑',
        render_kw={
            "class": "btn btn-primary",
        }
    )

在views中进行对于表单的校验以及传递到模板中。

@admin.route("/role/add/", methods=["GET", "POST"])
@admin_login_req
def role_add():
    """
    角色添加
    """
    form = RoleForm()
    if form.validate_on_submit():
        data = form.data
        role = Role(
            name=data["name"],
            auths=",".join(map(lambda v: str(v), data["auths"]))
        )
        db.session.add(role)
        db.session.commit()
        flash("添加角色成功!", "ok")
    return render_template("admin/role_add.html", form=form)

此时前往form中进行字段的填充。为模板中form添加post方法

mark

mark

添加提示的flash信息块。

mark

添加字段校验:

mark

备用: 制作多选框checkbox 用widgets.ListWidget 包裹 widgets.CheckboxInput()自己做一个多选.然后choices=[(v.id, v.name) for v in Auth.query.all(). 这样传回来的也是[1,2,3]

角色列表的展示

@admin.route("/role/list/<int:page>/", methods=["GET"])
@admin_login_req
def role_list(page=None):
    """
    角色列表
    """
    if page is None:
        page = 1
    page_data = Role.query.order_by(
        Role.addtime.desc()
    ).paginate(page=page, per_page=2)
    return render_template("admin/role_list.html", page_data=page_data)

views中定义角色列表,然后将pagedata进行填充,以及import pg与调用page方法进行分页。

mark

mark

mark

grid中的url添加page参数

mark

因为会有删除功能添加flash信息显示

mark

删除角色功能

@admin.route("/role/del/<int:id>/", methods=["GET"])
@admin_login_req
def role_del(id=None):
    """
    删除角色
    """
    role = Role.query.filter_by(id=id).first_or_404()
    db.session.delete(role)
    db.session.commit()
    flash("删除角色成功!", "ok")
    return redirect(url_for('admin.role_list', page=1))

为list中的删除按钮添加对应的url

mark

编辑角色功能实现

views中对于edit的处理

@admin.route("/role/edit/<int:id>/", methods=["GET", "POST"])
@admin_login_req
def role_edit(id=None):
    """
     编辑角色
    """
    form = RoleForm()
    role = Role.query.get_or_404(id)
    # get时进行赋值。应对无法模板中赋初值
    if request.method == "GET":
        auths = role.auths
        form.auths.data = list(map(lambda v: int(v), auths.split(",")))
    if form.validate_on_submit():
        data = form.data
        role.name = data["name"]
        role.auths = ",".join(map(lambda v: str(v), data["auths"]))
        db.session.add(role)
        db.session.commit()
        flash("修改角色成功!", "ok")
    return render_template("admin/role_edit.html", form=form, role=role)

新建一个role_edit.html 把add中的内容粘贴过来,修改汉字。以及填充值

mark

在list中修改指向编辑的链接。

管理员管理

  1. 模型: Admin
  2. 表单: AdminForm
  3. 请求方法: GET POST
  4. 访问控制: @admin_login_req

定义管理员的表单模型

class AdminForm(FlaskForm):
    name = StringField(
        label="管理员名称",
        validators=[
            DataRequired("管理员名称不能为空!")
        ],
        description="管理员名称",
        render_kw={
            "class": "form-control",
            "placeholder": "请输入管理员名称!",
        }
    )
    pwd = PasswordField(
        label="管理员密码",
        validators=[
            DataRequired("管理员密码不能为空!")
        ],
        description="管理员密码",
        render_kw={
            "class": "form-control",
            "placeholder": "请输入管理员密码!",
        }
    )
    repwd = PasswordField(
        label="管理员重复密码",
        validators=[
            DataRequired("管理员重复密码不能为空!"),
            EqualTo('pwd', message="两次密码不一致!")
        ],
        description="管理员重复密码",
        render_kw={
            "class": "form-control",
            "placeholder": "请输入管理员重复密码!",
        }
    )
    role_id = SelectField(
        label="所属角色",
        coerce=int,
        choices=[(v.id, v.name) for v in Role.query.all()],
        render_kw={
            "class": "form-control",
        }
    )
    submit = SubmitField(
        '编辑',
        render_kw={
            "class": "btn btn-primary",
        }
    )

views中实例化form 并将form 传递到前台的模板中 将数据存入数据库

@admin.route("/admin/add/", methods=["GET", "POST"])
@admin_login_req
def admin_add():
    """
    添加管理员
    """
    form = AdminForm()
    from werkzeug.security import generate_password_hash
    if form.validate_on_submit():
        data = form.data
        admin = Admin(
            name=data["name"],
            pwd=generate_password_hash(data["pwd"]),
            role_id=data["role_id"],
            is_super=1
        )
        db.session.add(admin)
        db.session.commit()
        flash("添加管理员成功!", "ok")
    return render_template("admin/admin_add.html", form=form)

mark

mark

添加flash消息显示和错误提示。(自行)注意为模板中form添加post方法。

管理员列表显示

views中添加管理员列表显示

@admin.route("/admin/list/<int:page>/", methods=["GET"])
@admin_login_req
def admin_list(page=None):
    """
    管理员列表
    """
    if page is None:
        page = 1
    page_data = Admin.query.join(
        Role
    ).filter(
        Role.id == Admin.role_id
    ).order_by(
        Admin.addtime.desc()
    ).paginate(page=page, per_page=1)
    return render_template("admin/admin_list.html", page_data=page_data)

前往admin_list中填充pagedata 以及pg的import以及调用page方法进行分页。

mark

mark

mark

grid中修改调转到list的url参数,添加上page=1

mark

访问权限控制

def admin_auth(f):
    @wraps(f)
    def decorate_function(*args, **kwargs):
        # 权限查询
        abort(404)
        return f(*args, **kwargs)

    return decorate_function
# 调用权限装饰器
@admin_auth

通过一个权限装饰器进行访问的控制,在装饰器里面进行一个查询,拿出session中保存的管理员的id,查询出对应的角色。同过角色查询出角色所对应的列表。列表是一个id的列表,id列表中去权限表中查询出我们能够访问的路由规则。根据路由规则进行匹配,得出我们能不能访问该页面。

print(request.script_root);print(request.url_rule)
from flask import abort
def admin_auth(f):
    """
    权限控制装饰器
    """
    @wraps(f)
    def decorated_function(*args, **kwargs):
        admin = Admin.query.join(
            Role
        ).filter(
            Role.id == Admin.role_id,
            Admin.id == session["admin_id"]
        ).first()
        auths = admin.role.auths
        # 将原本存储的权限字符串转换为列表
        auths = list(map(lambda v: int(v), auths.split(",")))
        auth_list = Auth.query.all()
        urls = [v.url for v in auth_list for val in auths if val == v.id]
        rule = request.url_rule
        if str(rule) not in urls:
            abort(404)
        return f(*args, **kwargs)

    return decorated_function

接下来为除过登录和后台首页都加上。然后测试是否可用。

登录我们的标签管理员。

进阶: 后台菜单动态显示,这个可以设计一个菜单数据表,分配可访问的菜单到用户权限中即可。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏沈唁志

网页服务器HTTP响应状态-HTTP状态码

1962
来自专栏运维小白

10.11 Linux网络相关

linux网络相关 ifconfig查看网卡ip(yum install net-tools) ifup ens33/ifdown ens33 设定虚拟网卡en...

2746
来自专栏张戈的专栏

Nginx-helper纯代码版,文章评论发布自动清理Fastcgi缓存

摘 要 张戈博客之前分享过Nginx开启fastcgi静态缓存加速的教程,文中也提到了WordPress对应的最佳配套插件:Nginx-Helper。本文分享...

3827
来自专栏魏艾斯博客www.vpsss.net

SFTP 和 FTP 的区别及用 SFTP 代替 FTP

1K3
来自专栏Golang语言社区

HTTP协议漫谈

简介 园子里已经有不少介绍HTTP的的好文章。对HTTP的一些细节介绍的比较好,所以本篇文章不会对HTTP的细节进行深究,而是从够高和更结构化的角度将H...

35013
来自专栏乐百川的学习频道

安装和使用Redis

Redis是一个高性能的内存数据库,它体积轻巧性能又高,在企业中被广泛使用。 安装Redis Windows安装 Redis是为Linux系统设计的,但是也有团...

46610
来自专栏DeveWork

记录一个在Mac OS X 中本地安装Ghost 的报错问题

新买的Macbook Air 升级了最新版的OS X 10.10 Yosemite,昨天在本地安装Ghost 的时候出现了问题,在这里做一个记录。 安装node...

2329
来自专栏程序员同行者

构建NTP时间服务器

2232
来自专栏逍遥剑客的游戏开发

从Native到Web(一), NaCl学习笔记: 环境搭建

2252
来自专栏Java帮帮-微信公众号-技术文章全总结

java.io.IOException 断开的管道【面试+工作】

查看采集数据的tomcat日志,习惯性的先翻到日志的最后去查看有没有异常的打印,果然发现了好几种异常信息,但是最多还是这个:

3523

扫码关注云+社区