CMS后台权限验证
添加用户角色
封装权限判断功能
客户端权限验证
服务端权限验证
cms/models.py
# @ Time : 2020/5/18
# @ Author : Ellen
from exts import db
from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash
class CMSPermission(object):
# 255 二进制来表示所有的权限
ALL_PERMISSION = 0b11111111
# 访问权限
VISITOR = 0b00000001
# 管理帖子权限
POSTER = 0b00000010
# 管理评论
COMMENTER = 0b00000100
# 管理板块
BOARDER = 0b00001000
# 管理前台用户
FORNTUSER = 0b00010000
# 管理后台用户板块
CMSUSER = 0b00100000
# 管理管理员用户
ADMINER = 0b01000000
# role与user的中间表
cms_role_user = db.Table(
'cms_role_user',
db.Column('cms_role_id', db.Integer, db.ForeignKey('cms_role.id'), primary_key=True),
db.Column('cms_user_id', db.Integer, db.ForeignKey('cms_user.id'), primary_key=True),
)
# 角色
class CMSRole(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(50), nullable=False)
desc = db.Column(db.String(220), nullable=False)
create_time = db.Column(db.DateTime, default=datetime.now)
permissions = db.Column(db.Integer, default=CMSPermission.VISITOR)
users = db.relationship('CMSUser', secondary=cms_role_user, backref='roles')
class CMSUser(db.Model):
__tablename__ = "cms_user"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(50), nullable=False)
_password = db.Column(db.String(100), nullable=False)
email = db.Column(db.String(50), nullable=False, unique=True)
join_time = db.Column(db.DateTime, default=datetime.now)
def __init__(self, username, password, email):
self.username = username
self.password = password
self.email = email
@property
def password(self):
return self._password
@password.setter
def password(self, raw_password):
self._password = generate_password_hash(raw_password)
def check_password(self, raw_password):
result = check_password_hash(self.password, raw_password)
return result
# 封装权限判断功能,判断当前用户有没有这个权限
@property
def permissions(self):
if not self.roles:
return 0
all_permissions = 0
for role in self.roles:
permissions = role.permissions
# 获取角色的所有权限
all_permissions |= permissions
return all_permissions
def has_permission(self, permission):
all_permissions = self.permissions
# 0b11111111 用户的权限 0b00001000
result = all_permissions & permission == permission
return result
@property
def is_developer(self):
return self.has_permission(CMSPermission.ALL_PERMISSION)
manage.py
# @ Time : 2020/5/18
# @ Author : Ellen
from flask_script import Manager
from bbs import app
from flask_migrate import Migrate, MigrateCommand
from exts import db
# 导入模型
from apps.cms.models import CMSUser, CMSRole, CMSPermission
manager = Manager(app)
Migrate(app, db)
manager.add_command('db', MigrateCommand)
@manager.option('-u', '--username', dest='username')
@manager.option('-p', '--password', dest='password')
@manager.option('-e', '--email', dest='email')
def create_cms_user(username, password, email):
user = CMSUser(username=username, password=password, email=email)
db.session.add(user)
db.session.commit()
print("cms用户添加成功")
@manager.command
def create_role():
# 访问者
visitor = CMSRole(name='访问者', desc='只能查看数据,不能修改数据')
visitor.permissions = CMSPermission.VISITOR
# 运营人员
operator = CMSRole(name='运营', desc='管理帖子,管理评论,管理前台用户')
operator.permissions = CMSPermission.VISITOR | CMSPermission.POSTER | CMSPermission.CMSUSER | CMSPermission.COMMENTER | CMSPermission.FORNTUSER
# 管理员
admin = CMSRole(name='管理员', desc='拥有本系统大部分权限')
admin.permissions = CMSPermission.VISITOR | CMSPermission.POSTER | CMSPermission.CMSUSER | CMSPermission.COMMENTER | CMSPermission.FORNTUSER | CMSPermission.BOARDER
# 开发人员
developer = CMSRole(name='开发者', desc='拥有所有的权限')
developer.permissions = CMSPermission.ALL_PERMISSION
db.session.add_all([visitor, operator, admin, developer])
db.session.commit()
@manager.command
def test_permission():
user = CMSUser.query.get(2)
print(user)
if user.has_permission(CMSPermission.VISITOR):
print('这个用户有访问者的权限')
else:
print('这个用户没有访问者的权限')
# 用户添加到角色里面
@manager.option('-e', '--email', dest='email')
@manager.option('-n', '--name', dest='name')
def add_user_to_role(email, name):
user = CMSUser.query.filter_by(email=email).first()
if user:
role = CMSRole.query.filter_by(name=name).first()
if role:
role.users.append(user)
db.session.commit()
print('用户添加到角色成功')
else:
print('角色不存在')
else:
print('邮箱不存在')
if __name__ == '__main__':
manager.run()
decorators.py
# 装饰器验证是否登录
from flask import session, redirect, url_for, g
from functools import wraps
def login_required(func):
def inner(*args, **kwargs):
if "user_id" in session:
return func(*args, **kwargs)
else:
return redirect(url_for('cms.login'))
return inner
# 装饰器传参数
def permission_required(permission):
def outter(func):
@wraps(func)
def inner(*args, **kwargs):
user = g.cms_user
if user.has_permission(permission):
return func(*args, **kwargs)
else:
return redirect(url_for('cms.index'))
return inner
return outter
hooks.py
@cms_bp.context_processor
def cms_context_processor():
return {'CMSPermission': CMSPermission}
views.py
# @ Time : 2020/5/18
# @ Author : Ellen
from flask import (
Blueprint,
render_template,
views,
request,
redirect,
url_for,
session,
jsonify,
g
)
from apps.cms.forms import LoginForm, ResetPwdForm, ResetEmailForm
from apps.cms.models import CMSUser, CMSPermission
from exts import db, mail
from utils import restful, random_captcha, lgcache
from flask_mail import Message
from .decorators import login_required, permission_required
cms_bp = Blueprint("cms", __name__, url_prefix='/cms')
from .hooks import before_request
@cms_bp.route("/")
# @login_required
def index():
# print(session.get('user_id'))
# return "cms index"
return render_template("cms/cms_index.html")
@cms_bp.route('/logout/')
def logout():
# 删除 session user_id
# 重定向 登录页面
del session['user_id']
return redirect(url_for('cms.login'))
# @cms_bp.route("/text/")
# def demo():
# return "测试是否可以访问"
@cms_bp.route("/profile/")
def profile():
return render_template("cms/cms_profile.html")
class LoginView(views.MethodView):
def get(self, message=None):
return render_template('cms/cms_login.html', message=message)
def post(self):
login_form = LoginForm(request.form)
if login_form.validate():
# 数据库验证 接收表单发送的方式
email = login_form.email.data
password = login_form.password.data
remember = login_form.remember.data
user = CMSUser.query.filter_by(email=email).first()
# 验证用户是否存在 密码是否正确
if user and user.check_password(password):
session['user_id'] = user.id
if remember:
session.permanent = True
# 登录成功 跳转首页
return redirect(url_for('cms.index'))
else:
return self.get(message="邮箱或者密码错误")
else:
# print(login_form.errors.popitem()[1][0])
# return "表单验证错误"
# message = login_form.errors.popitem()[1][0]
return self.get(message=login_form.get_error())
class ResetPwdView(views.MethodView):
def get(self):
return render_template('cms/cms_resetpwd.html')
def post(self):
form = ResetPwdForm(request.form)
if form.validate():
oldpwd = form.oldpwd.data
newpwd = form.newpwd.data
# 当前用户的对象
user = g.cms_user
# 用户提交的数据 ellen 秘密 是否和数据库中一致
if user.check_password(oldpwd):
# 更新我的密码
user.password = newpwd
db.session.commit()
# return jsonify({"code": 200, "message": ""})
return restful.success()
else:
# return jsonify({"code": 400, "message": "旧密码错误"})
return restful.params_errors(message="旧密码错误")
else:
# ajax 要返回json类型的数据
# message = form.errors.popitem()[1][0]
# return jsonify({"code": 400, "message": message})
return restful.params_errors(message=form.get_error())
class ResetEmailView(views.MethodView):
def get(self):
return render_template('cms/cms_resetemail.html')
def post(self):
form = ResetEmailForm(request.form)
if form.validate():
email = form.email.data
# 查询数据库
# CMSUser.query.filter_by(email=email).first()
# CMSUser.query.filter(CMSUser.email == email).first()
g.cms_user.email = email
db.session.commit()
return restful.success()
else:
return restful.params_errors(form.get_error())
# 发送邮件
@cms_bp.route("/send_mail/")
def send_mail():
message = Message('邮件发送', recipients=['80058851@qq.com'], body='测试邮件发送')
mail.send(message)
return '邮件已发送'
# 邮件发送
class EmailCaptcha(views.MethodView):
def get(self):
email = request.args.get('email')
if not email:
return restful.params_errors('请传递邮箱参数')
# 发送邮件 内容发送一个验证码 4 位或6位 数字和英文组合
captcha = random_captcha.get_random_captcha(4)
message = Message('论坛邮箱验证码', recipients=[email], body='您的验证码是 %s' % captcha)
try:
mail.send(message)
except:
return restful.server_errors()
# 验证码保存 mysql 过期时间 Redis 效率 key email value 验证码
lgcache.redis_set(email, captcha)
return restful.success()
@cms_bp.route("/posts/")
@permission_required(CMSPermission.POSTER)
def posts():
return render_template("cms/cms_posts.html")
@cms_bp.route("/comments/")
@permission_required(CMSPermission.COMMENTER)
def comments():
return render_template("cms/cms_comments.html")
@cms_bp.route("/boards/")
@permission_required(CMSPermission.BOARDER)
def boards():
return render_template("cms/cms_boards.html")
@cms_bp.route("/fusers/")
@permission_required(CMSPermission.FORNTUSER)
def fusers():
return render_template("cms/cms_fusers.html")
@cms_bp.route("/cusers/")
@permission_required(CMSPermission.CMSUSER)
def cusers():
return render_template("cms/cms_cusers.html")
@cms_bp.route("/croles/")
@permission_required(CMSPermission.ADMINER)
def croles():
return render_template("cms/cms_croles.html")
cms_bp.add_url_rule("/login/", view_func=LoginView.as_view('login'))
cms_bp.add_url_rule("/resetpwd/", view_func=ResetPwdView.as_view('resetpwd'))
cms_bp.add_url_rule("/resetemail/", view_func=ResetEmailView.as_view('resetemail'))
cms_bp.add_url_rule("/email_captcha/", view_func=EmailCaptcha.as_view('email_captcha'))
cms_profile.html
{% extends 'cms/cms_base.html' %}
{% block title %}
个人信息
{% endblock %}
{% block page_title %}
{{ self.title() }}
{% endblock %}
{% block content %}
{% set user = g.cms_user %}
<table class="table table-bordered">
<tr>
<td>用户名:</td>
<td>{{ user.username }}</td>
</tr>
<tr>
<td>邮箱:</td>
<td>{{ user.email }}</td>
</tr>
<tr>
<td>角色:</td>
<td>{% for role in user.roles %}
{{ role.name}}
{% if not loop.last %}
,
{% endif %}
{% endfor %}</td>
</tr>
<tr>
<td>权限:</td>
<td>{% for role in user.roles %}
{{ role.desc }}
{% if not loop.last %}
,
{% endif %}
{% endfor %}</td>
</tr>
<tr>
<td>加入时间:</td>
<td>{{ user.join_time }}</td>
</tr>
</table>
{% endblock %}
cms_base.html
{% set user = g.cms_user %}
{% if user.has_permission(CMSPermission.POSTER) %}
<li class="nav-group post-manage"><a href="#">帖子管理</a></li>
{% endif %}
{% if user.has_permission(CMSPermission.COMMENTER) %}
<li class="comments-manage"><a href="#">评论管理</a></li>
{% endif %}
{% if user.has_permission(CMSPermission.BOARDER) %}
<li class="board-manage"><a href="#">板块管理</a></li>
{% endif %}
{% if user.has_permission(CMSPermission.FORNTUSER) %}
<li class="FORNTUSER user-manage"><a href="#">前台用户管理</a></li>
{% endif %}
{% if user.has_permission(CMSPermission.CMSUSER) %}
<li class="CMSUSER-manage"><a href="#">后台用户管理</a></li>
{% endif %}
cms_boards.html
cms_comments.html…croles , fusers, posts,cusers
…
{% extends 'cms/cms_base.html' %}
{% block title %}
板块管理
{% endblock %}
{% block page_title %}
{{ self.title() }}
{% endblock %}
{% block content %}
板块管理
{% endblock %}