【Flask微电影】23.基于角色访问控制-管理员管理和访问权限
2018-11-11 本文已影响39人
吾星喵
个人博客,欢迎查看:https://blog.starmeow.cn/
Github地址:https://github.com/xyliurui/FlaskMovie
管理员管理
管理员添加
创建管理员表单
通过表单的字段EqualTo()
来验证重复密码是否一致。
from wtforms.validators import DataRequired, ValidationError, EqualTo
class AdminForm(FlaskForm):
name = StringField(
label='管理员名称',
validators=[
DataRequired('请输入管理员名称!')
],
description='管理员名称',
render_kw={
'class': "form-control",
'placeholder': "请输入管理员名称",
'required': "required"
}
)
pwd = PasswordField(
label='管理员密码',
validators=[
DataRequired('请输入管理员密码!')
],
description='管理员密码',
render_kw={
'class': "form-control",
'placeholder': "请输入管理员密码",
'required': "required"
}
)
repwd = PasswordField(
label='管理员重复密码',
validators=[
DataRequired('请输入管理员重复密码!'),
EqualTo('pwd', message='两次密码不一致')
],
description='管理员重复密码',
render_kw={
'class': "form-control",
'placeholder': "请输入管理员重复密码",
'required': "required"
}
)
is_super = SelectField(
label='星级',
validators=[
DataRequired('请选择星级!')
],
description='星级',
coerce=int,
choices=[(1, '普通管理员'), (0, '超级管理员')],
render_kw={
'class': "form-control"
}
)
role_id = SelectField(
label='所属角色',
validators=[
DataRequired('请选择所属角色!')
],
coerce=int,
# choices=[(role.id, role.name) for role in Role.query.all()],
description='所属角色',
render_kw={
'class': "form-control"
}
)
def __init__(self, *args, **kwargs):
super(AdminForm, self).__init__(*args, **kwargs)
self.role_id.choices = [(v.id, v.name) for v in Role.query.all()]
submit = SubmitField(
label='提交',
render_kw={
'class': "btn btn-primary"
}
)
修改admin_add管理员添加视图
@admin.route("/admin/add/", methods=['GET', 'POST'])
@admin_login_require
def admin_add():
form = AdminForm(is_super=1)
from werkzeug.security import generate_password_hash
print(form.data)
if form.validate_on_submit():
data = form.data
if Admin.query.filter_by(name=data['name']).count() == 1:
flash('管理员已存在!', category='err')
return redirect(url_for('admin.admin_add'))
add_admin = Admin(
name=data['name'],
pwd=generate_password_hash(data['pwd']),
role_id=data['role_id'],
is_super=1
)
db.session.add(add_admin)
db.session.commit()
flash('管理员添加成功', category='ok')
return render_template('admin/admin_edit.html', form=form)
修改admin_edit.html添加管理员模板
<form role="form" method="post">
{% include 'admin/alert_info.html' %}
<div class="box-body">
<div class="form-group">
<label for="input_name">{{ form.name.label }}</label>
{{ form.name }}
{% for err in form.name.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
</div>
<div class="form-group">
<label for="input_pwd">{{ form.pwd.label }}</label>
{{ form.pwd }}
{% for err in form.pwd.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
</div>
<div class="form-group">
<label for="input_re_pwd">{{ form.repwd.label }}</label>
{{ form.repwd }}
{% for err in form.repwd.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
</div>
<div class="form-group">
<label for="input_role_id">{{ form.role_id.label }}</label>
{{ form.role_id }}
{% for err in form.role_id.errors %}
<div class="col-md-12" style="color: red">{{ err }}</div>
{% endfor %}
</div>
</div>
{{ form.csrf_token }}
<div class="box-footer">
{{ form.submit }}
</div>
</form>
image.png
image.png
image.png
管理员列表
修改admin_list管理员列表视图
@admin.route("/admin/list/<int:page>")
@admin_login_require
def admin_list(page=None):
if not page:
page = 1
page_admins = Admin.query.order_by(
Admin.add_time.desc()
).join(
Role
).filter(
Role.id == Admin.role_id # 关联查询
).paginate(page=page, per_page=10)
return render_template('admin/admin_list.html', page_admins=page_admins)
修改admin_list.html管理员列表模板
<div class="box-body table-responsive no-padding">
{% include 'admin/alert_info.html' %}
<table class="table table-hover">
<tbody>
<tr>
<th>编号</th>
<th>管理员名称</th>
<th>管理员类型</th>
<th>管理员角色</th>
<th>添加时间</th>
</tr>
{% for admin in page_admins.items %}
<tr>
<td>{{ admin.id }}</td>
<td>{{ admin.name }}</td>
<td>{% if admin.is_super == 0 %}超级管理员{% else %}普通管理员{% endif %}</td>
<td>{{ admin.role.name }}</td>
<td>{{ admin.add_time }}1</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="box-footer clearfix">
{% import 'admin/pagination.html' as pg %}
{{ pg.render_pagination(page_admins, 'admin.admin_list') }}
</div>
image.png
访问权限控制
在views.py中编写权限验证装饰器
# 权限控制装饰器
def permission_control(func):
@wraps(func)
def decorated_function(*args, **kwargs):
login_admin = Admin.query.join(
Role
) .filter(
Role.id == Admin.role_id,
Admin.name == session['login_admin']
).first()
all_auth = Auth.query.all() # 数据库所有权限
auths = login_admin.role.auths
auths = list(map(lambda item: int(item), auths.split(','))) # 用户权限id列表
urls = [auth.url for auth in all_auth for admin_auth_id in auths if admin_auth_id == auth.id]
print(urls)
rule = request.url_rule
print(rule) # 需要转为str判断是否在list中
if str(rule) not in urls and login_admin.is_super != 0: # 权限不存在,且不是超级管理员
abort(401)
return func(*args, **kwargs)
return decorated_function
在各个视图中添加装饰
例如:
@admin.route("/")
@admin_login_require
@permission_control
def index():
# ....
@admin.route("/tag/add/", methods=['GET', 'POST'])
@admin_login_require
@permission_control
def tag_add():
# ....
创建无权访问提示
创建401视图
在app/__init__.py
中添加以下视图和404的视图在一个文件中
# 添加全局401无权限页面
@app.errorhandler(401)
def unauthorized_access(error):
return render_template('401.html'), 401
创建401模板
这儿就没什么样式,随意了
{% extends 'admin/base.html' %}
{% block content %}
<h1>无权访问<a href="{{ request.path }}">{{ request.path }}</a> </h1>
{% endblock %}
当访问无权限的url时,会进行提示
image.png