提交 955c40fe 编写于 作者: C Corley

V1.4

上级 65e72ce0
......@@ -15,4 +15,7 @@
在V1.2的时候进一步完善,首先实现在Flask中发送邮件,并进一步定义发送验证码,并进一步实现修改邮箱,还对权限和角色模型进行了定义。
注意:
在配置文件config.md中需要将自己的邮箱信息输入,才能正常实现其功能。
\ No newline at end of file
在配置文件config.md中需要将自己的邮箱信息输入,才能正常实现其功能。
#### V1.4
在V1.3的基础上进一步完善权限验证功能,首先在manage.py中实现添加用户角色,再实现页面修改,最后在客户端和服务端进行双重权限验证,是吸纳了权限验证的基本功能。
\ No newline at end of file
from flask import session, redirect, url_for
from flask import session, redirect, url_for, g
from functools import wraps
def login_required(func):
def index(*args, **kwargs):
......@@ -6,4 +7,18 @@ def login_required(func):
return func(*args, **kwargs)
else:
return redirect(url_for('cms.login'))
return index
\ No newline at end of file
return index
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
\ No newline at end of file
from flask import request, session, url_for, redirect, g
from .models import CMSUser
from .models import CMSUser, CMSRole, CMSPermission
from .views import cms_bp
......@@ -17,4 +17,13 @@ def before_request():
user = CMSUser.query.get(user_id)
# 使用g对象保存用户
if user:
g.cms_user = user
\ No newline at end of file
g.cms_user = user
roles = user.roles
max_permission = max([role.permissions for role in roles])
max_role = CMSRole.query.filter_by(permissions=max_permission).first().name
g.max_role = max_role
@cms_bp.context_processor
def cms_context_processor():
return {'CMSPermission': CMSPermission}
\ No newline at end of file
......@@ -32,6 +32,29 @@ class CMSUser(db.Model):
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
result = all_permissions & permission == permission # 如果当前用户有某个权限,则他的全部权限与该权限按位与的结果等于该权限本身
return result
@property
def is_developer(self):
'''判断当前用户是否是开发人员'''
return self.has_permission(CMSPermission.ALL_PERMISSION)
class CMSPermission(object):
# 255二进制表示所有权限
......@@ -73,4 +96,4 @@ class CMSRole(db.Model):
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')
\ No newline at end of file
users = db.relationship('CMSUser', secondary=cms_role_user, backref='roles')
from flask import Blueprint, render_template, views, request, redirect, url_for, session, g
from flask_mail import Message
from apps.cms.forms import LoginForm, ResetPwdForm, ResetEmailForm
from apps.cms.models import CMSUser
from apps.cms.models import CMSUser, CMSPermission
from exts import db, mail
from utils import restful, random_captcha, clcache
# from .decorators import login_required # .代表当前路径
from .decorators import permission_required # .代表当前路径
cms_bp = Blueprint('cms', __name__, url_prefix='/cms')
from .hooks import before_request
@cms_bp.route('/')
# @login_required
def index():
return render_template('cms/cms_index.html')
return render_template('cms/cms_index.html', max_role=g.max_role)
@cms_bp.route('/logout/')
......@@ -28,7 +27,7 @@ def logout():
@cms_bp.route("/profile/")
def profile():
return render_template("cms/cms_profile.html")
return render_template("cms/cms_profile.html", max_role=g.max_role)
class LoginView(views.MethodView):
......@@ -62,7 +61,7 @@ class LoginView(views.MethodView):
class ResetPwdView(views.MethodView):
def get(self):
return render_template('cms/cms_resetpwd.html')
return render_template('cms/cms_resetpwd.html', max_role=g.max_role)
def post(self):
form = ResetPwdForm(request.form)
......@@ -85,7 +84,7 @@ class ResetPwdView(views.MethodView):
class ResetEmailView(views.MethodView):
def get(self):
return render_template('cms/cms_resetemail.html')
return render_template('cms/cms_resetemail.html', max_role=g.max_role)
def post(self):
form = ResetEmailForm(request.form)
......@@ -116,6 +115,42 @@ class EmailCaptchaView(views.MethodView):
return restful.success(message='邮件发送成功,请注意接收验证码')
@cms_bp.route('/posts/')
@permission_required(CMSPermission.POSTER)
def posts():
return render_template('cms/cms_posts.html', max_role=g.max_role)
@cms_bp.route('/comments/')
@permission_required(CMSPermission.COMMENTER)
def comments():
return render_template('cms/cms_comments.html', max_role=g.max_role)
@cms_bp.route('/boards/')
@permission_required(CMSPermission.BOARDER)
def boards():
return render_template('cms/cms_boards.html', max_role=g.max_role)
@cms_bp.route('/fusers/')
@permission_required(CMSPermission.FRONTUSER)
def fusers():
return render_template('cms/cms_fusers.html', max_role=g.max_role)
@cms_bp.route('/cusers/')
@permission_required(CMSPermission.CMSUSER)
def cusers():
return render_template('cms/cms_cusers.html', max_role=g.max_role)
@cms_bp.route('/croles/')
@permission_required(CMSPermission.ADMINER)
def croles():
return render_template('cms/cms_croles.html', max_role=g.max_role)
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'))
......
......@@ -12,7 +12,7 @@ from apps.front.views import front_bp
import config
app = Flask(__name__)
app = Flask(__name__) # type:Flask
CSRFProtect(app)
app.config.from_object(config)
db.init_app(app)
......
......@@ -24,8 +24,8 @@ MAIL_PORT = 587
MAIL_USE_TLS = True
# MAIL_USE_SSL = True # MAIL_PORT为465时设置此项
# 用户名可以为你的邮箱,需要自行添加
MAIL_USERNAME = '123456789@qq.com'
MAIL_USERNAME = '379869029@qq.com'
# 邮箱密码,不是邮箱账号密码,而是第三方客户端登录使用的授权码,需要自行获取
MAIL_PASSWORD = 'xxxxxxxxxxxxxxxx'
MAIL_PASSWORD = 'vrxiqciwjnbcbiaj'
# 发送者即你的邮箱,需要自行添加
MAIL_DEFAULT_SENDER = '123456789@qq.com'
\ No newline at end of file
MAIL_DEFAULT_SENDER = '379869029@qq.com'
\ No newline at end of file
......@@ -2,7 +2,7 @@ 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
from apps.cms.models import CMSUser, CMSRole, CMSPermission
manager = Manager(app)
Migrate(app, db)
......@@ -20,5 +20,53 @@ def create_cms_user(username, password, email):
print('CMS用户添加成功')
@manager.command
def create_role():
# 访问者
visitor = CMSRole(name='访问者', desc='只能查看数据,不能修改数据')
visitor.permissions = CMSPermission.VISITOR # 也可以省去,因为默认权限就是VISITOR
# 运营者
operator = CMSRole(name='运营', desc='管理帖子,管理评论,管理前台和后台用户')
# 有多个权限时,使用或运算表示
operator.permissions = CMSPermission.VISITOR | CMSPermission.POSTER | CMSPermission.CMSUSER | CMSPermission.COMMENTER | CMSPermission.FRONTUSER
# 管理员
admin = CMSRole(name='管理员', desc='拥有本系统大部分权限')
admin.permissions = CMSPermission.VISITOR | CMSPermission.POSTER | CMSPermission.CMSUSER | CMSPermission.COMMENTER | CMSPermission.FRONTUSER | CMSPermission.BOARDER
# 开发人员
developer = CMSRole(name='开发者', desc='拥有所有权限')
developer.permissions = CMSPermission.ALL_PERMISSION
db.session.add_all([visitor, operator, admin, developer])
db.session.commit()
print('角色添加成功')
@manager.command
def test_permission():
user = CMSUser.query.first()
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()
"""empty message
Revision ID: 63b5250011d6
Revises: ba80d307aa21
Create Date: 2020-06-18 19:35:35.914548
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '63b5250011d6'
down_revision = 'ba80d307aa21'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('cms_role',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('name', sa.String(length=50), nullable=False),
sa.Column('desc', sa.String(length=200), nullable=False),
sa.Column('create_time', sa.DateTime(), nullable=True),
sa.Column('permissions', sa.Integer(), nullable=True),
sa.PrimaryKeyConstraint('id')
)
op.create_foreign_key(None, 'cms_role_user', 'cms_user', ['cms_user_id'], ['id'])
op.create_foreign_key(None, 'cms_role_user', 'cms_role', ['cms_role_id'], ['id'])
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'cms_role_user', type_='foreignkey')
op.drop_constraint(None, 'cms_role_user', type_='foreignkey')
op.drop_table('cms_role')
# ### end Alembic commands ###
......@@ -41,16 +41,16 @@ $(function () {
} else if (url.indexOf('permissions') >= 0) {
var permissionManageLi = $('.permission-manage');
permissionManageLi.addClass('unfold').siblings().removeClass('unfold');
} else if (url.indexOf('roles') >= 0) {
} else if (url.indexOf('froles') >= 0) {
var roleManageLi = $('.role-manage');
roleManageLi.addClass('unfold').siblings().removeClass('unfold');
} else if (url.indexOf('users') >= 0) {
} else if (url.indexOf('fusers') >= 0) {
var userManageLi = $('.user-manage');
userManageLi.addClass('unfold').siblings().removeClass('unfold');
} else if (url.indexOf('cmsuser_manage') >= 0) {
} else if (url.indexOf('cusers') >= 0) {
var cmsuserManageLi = $('.cmsuser-manage');
cmsuserManageLi.addClass('unfold').siblings().removeClass('unfold');
} else if (url.indexOf('cmsrole_manage') >= 0) {
} else if (url.indexOf('croles') >= 0) {
var cmsroleManageLi = $('.cmsrole-manage');
cmsroleManageLi.addClass('unfold').siblings().removeClass('unfold');
} else if (url.indexOf('comments') >= 0) {
......
......@@ -35,7 +35,7 @@
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="#">{{ g.cms_user.username }}<span>[超级管理员]</span></a></li>
<li><a href="#">{{ g.cms_user.username }}<span>[{% block role %}{% endblock %}]</span></a></li>
<li><a href="{{ url_for('cms.logout') }}">注销</a></li>
</ul>
<form class="navbar-form navbar-right">
......@@ -49,7 +49,7 @@
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav-sidebar">
<li class="unfold"><a href="#">首页</a></li>
<li class="unfold"><a href="{{ url_for('cms.index') }}">首页</a></li>
<li class="profile-li">
<a href="#">个人中心<span></span></a>
<ul class="subnav">
......@@ -59,15 +59,27 @@
</ul>
</li>
<li class="nav-group post-manage"><a href="#">帖子管理</a></li>
<li class="comments-manage"><a href="#">评论管理</a></li>
<li class="board-manage"><a href="#">板块管理</a></li>
{% set user = g.cms_user %}
{% if user.has_permission(CMSPermission.POSTER) %}
<li class="nav-group post-manage"><a href="{{ url_for('cms.posts') }}">帖子管理</a></li>
{% endif %}
{% if user.has_permission(CMSPermission.COMMENTER) %}
<li class="comments-manage"><a href="{{ url_for('cms.comments') }}">评论管理</a></li>
{% endif %}
{% if user.has_permission(CMSPermission.BOARDER) %}
<li class="board-manage"><a href="{{ url_for('cms.boards') }}">板块管理</a></li>
{% endif %}
{% if user.has_permission(CMSPermission.FRONTUSER) %}
<li class="nav-group user-manage"><a href="{{ url_for('cms.fusers') }}">前台用户管理</a></li>
{% endif %}
{% if user.has_permission(CMSPermission.CMSUSER) %}
<li class="nav-group cmsuser-manage"><a href="{{ url_for('cms.cusers') }}">CMS用户管理</a></li>
{% endif %}
{% if user.is_developer %}
<li class="cmsrole-manage"><a href="{{ url_for('cms.croles') }}">CMS组管理</a></li>
{% endif %}
<li class="nav-group user-manage"><a href="#">用户管理</a></li>
<li class="role-manage"><a href="#">组管理</a></li>
<li class="nav-group cmsuser-manage"><a href="#">CMS用户管理</a></li>
<li class="cmsrole-manage"><a href="#">CMS组管理</a></li>
</ul>
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
......
{% extends 'cms/cms_base.html' %}
{% block title %}
熊熊论坛后台板块管理
{% endblock %}
{% block page_title %}
熊熊板块管理
{% endblock %}
{% block role %}
{{ max_role }}
{% endblock %}
{% block content %}
板块管理部分
{% endblock %}
\ No newline at end of file
{% extends 'cms/cms_base.html' %}
{% block title %}
熊熊论坛后台评论管理
{% endblock %}
{% block page_title %}
熊熊评论管理
{% endblock %}
{% block role %}
{{ max_role }}
{% endblock %}
{% block content %}
评论管理部分
{% endblock %}
\ No newline at end of file
{% extends 'cms/cms_base.html' %}
{% block title %}
熊熊论坛后台用户组管理
{% endblock %}
{% block page_title %}
熊熊后台用户组管理
{% endblock %}
{% block role %}
{{ max_role }}
{% endblock %}
{% block content %}
后台用户组管理部分
{% endblock %}
\ No newline at end of file
{% extends 'cms/cms_base.html' %}
{% block title %}
熊熊论坛后台用户管理
{% endblock %}
{% block page_title %}
熊熊后台管理
{% endblock %}
{% block role %}
{{ max_role }}
{% endblock %}
{% block content %}
后台用户管理部分
{% endblock %}
\ No newline at end of file
{% extends 'cms/cms_base.html' %}
{% block title %}
熊熊论坛前台用户管理
{% endblock %}
{% block page_title %}
熊熊前台用户管理
{% endblock %}
{% block role %}
{{ max_role }}
{% endblock %}
{% block content %}
前台用户管理部分
{% endblock %}
\ No newline at end of file
......@@ -8,6 +8,10 @@
熊熊论坛
{% endblock %}
{% block role %}
{{ max_role }}
{% endblock %}
{% block content %}
欢迎来到{{ self.page_title() }}......
{% endblock %}
\ No newline at end of file
{% extends 'cms/cms_base.html' %}
{% block title %}
熊熊论坛后台帖子管理
{% endblock %}
{% block page_title %}
熊熊帖子管理
{% endblock %}
{% block role %}
{{ max_role }}
{% endblock %}
{% block content %}
帖子管理部分
{% endblock %}
\ No newline at end of file
......@@ -8,6 +8,10 @@
熊熊个人中心
{% endblock %}
{% block role %}
{{ max_role }}
{% endblock %}
{% block content %}
{% set user = g.cms_user %}
<table class="table table-bordered">
......@@ -21,11 +25,26 @@
</tr>
<tr>
<td>角色:</td>
<td>暂无</td>
<td>
{% for role in user.roles %}
{{ role.name }}
{% if not loop.last %}
&nbsp;
{% endif %}
{% endfor %}
</td>
</tr>
<tr>
<td>权限:</td>
<td>暂无</td>
<td>
{% for role in user.roles %}
{{ role.desc }}
{% if not loop.last %}
{% endif %}
{% endfor %}
</td>
</tr>
<tr>
<td>加入时间:</td>
......
......@@ -12,6 +12,10 @@
<script src="{{ url_for('static', filename='cms/js/resetemail.js') }}"></script>
{% endblock %}
{% block role %}
{{ max_role }}
{% endblock %}
{% block content %}
<form action="" method="post">
<div class="form-container">
......
......@@ -12,6 +12,10 @@
<script src="{{ url_for('static', filename='cms/js/resetpwd.js') }}"></script>
{% endblock %}
{% block role %}
{{ max_role }}
{% endblock %}
{% block content %}
<form action="" method="post">
{# <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">#}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册