1、角色定义
创建角色定义的函数,并添加到数据库中:
命令行添加角色信息:manage.py
# -*- encoding: utf-8 -*-
"""
@File : manage.py
@Time : 2020/5/10 17:36
@Author : chen
"""
from flask_script import Manager
from bbs import app # 需要将当前文件夹设置为当前根目录,才不会报错
from flask_migrate import Migrate, MigrateCommand
from exts import db
# 导入模型 才能映射到数据库 导入后端的模型
from apps.cms.models import CMS_User
# 导入角色模型,映射到数据库 CMSPersmission角色权限定义类
from apps.cms.models import CMSRole, CMSPersmission
manage = Manager(app)
Migrate(app, db)
manage.add_command('db', MigrateCommand)
# 命令行添加后端用户
@manage.option('-u', '--username', dest='username')
@manage.option('-p', '--password', dest='password')
@manage.option('-e', '--email', dest='email')
def create_cms_user(username, password, email):
user = CMS_User(username=username, password=password, email=email)
# 添加映射到数据库,提交至数据库
db.session.add(user)
db.session.commit()
print("cms后端用户添加成功")
# 添加角色 不传参用command,传参用option
@manage.command
def create_role():
# 访问者
visitor = CMSRole(name="访问者", desc="只能查看数据,不能修改数据")
visitor.permission = CMSPersmission.VISITOR # 权限
# 运营人员
operator = CMSRole(name="运营人员", desc="管理评论、帖子、管理前台用户")
# 权限或运算,代表包含有运算中的所有权限 二进制的运算 001|010=011
operator.permission = CMSPersmission.VISITOR | CMSPersmission.POSTER | CMSPersmission.CMSUSER | \
CMSPersmission.COMMENTER | CMSPersmission.FRONTUSER
# 管理员
admin = CMSRole(name="管理员", desc="拥有本系统大部分权限")
admin.permission = CMSPersmission.VISITOR | CMSPersmission.POSTER | CMSPersmission.CMSUSER | \
CMSPersmission.COMMENTER | CMSPersmission.FRONTUSER | CMSPersmission.BOARDER
# 开发人员
developer = CMSRole(name="开发人员", desc="拥有本系统所有权限")
developer.permission = CMSPersmission.ALL_PERMISSION
# 提交数据库 添加身份字段到数据库中的表,
db.session.add_all([visitor, operator, admin, developer])
db.session.commit()
return "创建角色成功"
if __name__ == '__main__':
manage.run()
实现效果如下:
2、用户权限
判断用户所具有的权限:模型文件apps/cms/models.py
# -*- encoding: utf-8 -*-
"""
@File : models.py
@Time : 2020/5/11 10:00
@Author : chen
"""
# 定义后端用户模型
from exts import db # 数据库
from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash # 导入密码加密,解密方法的库
# 权限定义,不是模型,没有继承db.Model
class CMSPersmission(object):
# 255 二进制表示所有的权限
ALL_PERMISSION = 0b11111111 # 每一位数代表一个权限,共7个权限,8位1个字节
# 访问权限
VISITOR = 0b00000001
# 管理帖子
POSTER = 0b00000010
# 管理评论
COMMENTER = 0b00000100
# 管理板块
BOARDER = 0b00001000
# 管理后台用户
CMSUSER = 0b00010000
# 管理前台用户
FRONTUSER = 0b00100000
# 管理管理员用户
ADMINER = 0b01000000
# 权限与角色是多对多的关系,创建他们的中间表
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),
)
# 角色模型定义 继承了db.Model
class CMSRole(db.Model):
__tablename__ = 'cms_role'
id = db.Column(db.Integer, primary_key=True, autoincrement=True) # 主键 自增
name = db.Column(db.String(50), nullable=False) # 非空
desc = db.Column(db.String(250), nullable=False) # 非空
creat_time = db.Column(db.DateTime, default=datetime.now)
permission = db.Column(db.Integer, default=CMSPersmission.VISITOR) # 默认先给游客权限
# 反向查询属性,关联中间表secondary=cms_role_user,对应了CMS_User模型,建立模型联系,不映射到数据库中
users = db.relationship('CMS_User', secondary=cms_role_user, backref="roles") # roles是CMS_User的外键
# 后台用户模型定义
class CMS_User(db.Model):
__tablename__ = 'cms_user'
id = db.Column(db.Integer, primary_key=True, autoincrement=True) # 主键 自增
username = db.Column(db.String(150), nullable=False) # 非空
# password = db.Column(db.String(150), nullable=False)
_password = db.Column(db.String(150), nullable=False) # 密码加密操作修改字段
email = db.Column(db.String(50), nullable=False, unique=True) # 非空、唯一
join_time = db.Column(db.DateTime, default=datetime.now) # 默认当前时间
# 修改密码加密操作中的字段,在manage.py映射数据库时候,使用字段还是保持相同
def __init__(self, username, password, email):
self.username = username
self.password = password # 调用该方法 返回下面的self._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)
# 用于验证后台登录密码是否和数据库一致,raw_password是后台登录输入的密码
def check_password(self, raw_password):
result = check_password_hash(self.password, raw_password) # 相当于用相同的hash加密算法加密raw_password,检测与数据库中是否一致
return result
# 封装用户的权限
@property
def permission(self):
if not self.roles: # 反向查询属性,backref="roles",
return 0 # 没有任何权限
# 所有权限
all_permissions = 0
for role in self.roles: # 循环调用所有角色
permissions = role.permission # 将这个角色的权限都取出来 role.permission代表CMSRole中的属性
all_permissions |= permissions # 当前这个角色的权限都在all_permissions
return all_permissions
# 判断用户所具有的权限
def has_permissions(self, permission):
all_permissions = self.permission # 调用permission(self)方法
# 若所有权限0b11111111 & 用户权限 等于 本身,则代表具有该权限
result = all_permissions & permission == permission
# print(result)
return result
# 判断是否是开发人员
@property
def is_developer(self):
return self.has_permissions(CMSPersmission.ALL_PERMISSION) # 调用has_permissions方法并传入所有权限
命令行添加用户到角色
添加测试用户权限方法:命令行添加用户到角色里面manage.py
# -*- encoding: utf-8 -*-
"""
@File : manage.py
@Time : 2020/5/10 17:36
@Author : chen
"""
from flask_script import Manager
from bbs import app # 需要将当前文件夹设置为当前根目录,才不会报错
from flask_migrate import Migrate, MigrateCommand
from exts import db
# 导入模型 才能映射到数据库 导入后端的模型
from apps.cms.models import CMS_User
# 导入角色模型,映射到数据库 CMSPersmission角色权限定义类
from apps.cms.models import CMSRole, CMSPersmission
manage = Manager(app)
Migrate(app, db)
manage.add_command('db', MigrateCommand)
# 命令行添加后端用户
@manage.option('-u', '--username', dest='username')
@manage.option('-p', '--password', dest='password')
@manage.option('-e', '--email', dest='email')
def create_cms_user(username, password, email):
user = CMS_User(username=username, password=password, email=email)
# 添加映射到数据库,提交至数据库
db.session.add(user)
db.session.commit()
print("cms后端用户添加成功")
# 添加角色 不传参用command
@manage.command
def create_role():
# 访问者
visitor = CMSRole(name="访问者", desc="只能查看数据,不能修改数据")
visitor.permission = CMSPersmission.VISITOR # 权限
# 运营人员
operator = CMSRole(name="运营人员", desc="管理评论、帖子、管理前台用户")
# 权限或运算,代表包含有运算中的所有权限 二进制的运算 001|010=011
operator.permission = CMSPersmission.VISITOR | CMSPersmission.POSTER | CMSPersmission.CMSUSER | \
CMSPersmission.COMMENTER | CMSPersmission.FRONTUSER
# 管理员
admin = CMSRole(name="管理员", desc="拥有本系统大部分权限")
admin.permission = CMSPersmission.VISITOR | CMSPersmission.POSTER | CMSPersmission.CMSUSER | \
CMSPersmission.COMMENTER | CMSPersmission.FRONTUSER | CMSPersmission.BOARDER
# 开发人员
developer = CMSRole(name="开发人员", desc="拥有本系统所有权限")
developer.permission = CMSPersmission.ALL_PERMISSION
# 提交数据库 添加身份字段到数据库中的表,
db.session.add_all([visitor, operator, admin, developer])
db.session.commit()
return "创建角色成功"
# 测试用户权限
@manage.command
def test_permission():
# user = CMS_User.query.first() # 查询第一个用户,当时创建的用户还没有关联权限,所以应该是没有权限
user = CMS_User.query.get(3)
print(user) # 显示用户信息
if user.has_permissions(CMSPersmission.VISITOR): # has_permissions方法判定是否具有该权限
print("这个用户有访问者的权限!")
else:
print("这个用户有访问者的权限!")
# 添加用户到角色里面
@manage.option("-e", "--email", dest="email")
@manage.option("-n", "--name", dest="name")
def add_user_to_role(email, name):
user = CMS_User.query.filter_by(email=email).first() # 通过邮箱查询用户
if user:
role = CMSRole.query.filter_by(name=name).first() # 邮箱存在的前提下,通过name查询角色
if role:
role.users.append(user) # 将用户添加到角色中,list类型数据,role.users是CMSRole中的外键
db.session.commit() # 映射到数据库
print("用户添加到角色成功")
else:
print("该角色不存在")
else:
print("邮箱不存在")
if __name__ == '__main__':
manage.run()
测试效果如下:
3、用户权限渲染到个人页面
用户权限渲染到个人中心页面cms_profile.html
<!-- 继承模板文件cms/cms_base.html 简化代码 -->
{% extends 'cms/cms_base.html' %}
<!-- 页面标题 -->
{% block title %}
个人信息
{% endblock %}
<!-- 标题 -->
{% block page_title %}
{{self.title()}}
{% endblock %}
{% block content %}
<!-- 将全局变量的对象在这个block模块中命名为user -->
{% set user = g.cms_user %}
<table class="table table-bordered">
<tr>
<td>用户名:</td>
<!-- 调用全局变量对象的username字段属性 user替代g.cms_user -->
<td>{{ user.username }}</td>
</tr>
<tr>
<td>邮箱:</td>
<td>{{ user.email }}</td>
</tr>
<tr>
<td>角色:</td>
<td>
<!-- 循环 全局变量对象的外键roles 一个用户多个角色 -->
{% for role in user.roles %}
{{ role.name }}
{% endfor %}
</td>
</tr>
<tr>
<td>权限:</td>
<td>
<!-- 循环 全局变量对象的外键roles -->
{% for role in user.roles %}
{{ role.desc }}
{% endfor %}
</td>
</tr>
<tr>
<td>加入时间:</td>
<td>{{ user.join_time }}</td>
</tr>
</table>
{% endblock %}
渲染效果如下:
4、客户端权限验证
hooks.py文件添加钩子函数中的上下文处理器:返回的字典中的键可以在模板上下文中使用,传输到模板文件中调用
# -*- encoding: utf-8 -*-
"""
@File : hooks.py
@Time : 2020/5/13 9:36
@Author : chen
"""
from flask import request, session, url_for, redirect, g # g对象全局变量gloabl,方便调用
from .views import cms_bp
from .models import CMS_User
from .models import CMSPersmission # 导入CMSPersmission到上下文管理器中,方便全局调用
# 钩子函数 ,所有操作前执行该方法,判断当前界面是否是登录界面,不是就将url重定向到登录界面
@cms_bp.before_request
def before_request():
print(request.path) # 输出的是网页url的后缀,即/cms/login/
if not request.path.endswith(url_for('cms.login')): # 判断当前所在url是否是/cms/login/,不是代表不在后台登录界面
user_id = session.get('user_id') # 登陆之后,获取登录时候记录的session中的user_id
if not user_id: # 若没有user_id,说明登录不成功
return redirect(url_for('cms.login')) # 重定向到后台登录界面
# 判断user_id是否登陆过,登录之后就返回用户名到CMS后台管理系统
if 'user_id' in session:
user_id = session.get('user_id') # 调用session中user_id
user = CMS_User.query.get(user_id) # 通过user_id查询到用户对象,方便前端界面调用对象中的字段属性
if user:
g.cms_user = user # 赋值给g对象,全局变量g.cms_user用于渲染到后台管理界面cms_index.html
# 上面的代码相对于下面的来说比较简单,下面的是将对象中的字段属性单独来调用并修改为全局变量,上面只是将完整的一个对象变成全局变量
'''
# 判断user_id是否登陆过,登录之后就返回用户名到CMS后台管理系统
if 'user_id' in session: # user_id在session中,说明cms用户已经登录了
user_name = session.get('user_name') # 从session中调用user_username
user_email = session.get('user_email') # 从session中调用user_email,用于设置为全局变量,渲染到cms_profile.html中
user_join_time = session.get('user_join_time') # 从session中调用user_join_time,用于设置为全局变量,渲染到cms_profile.html中
if user_name:
g.cms_user = user_name # 赋值给g对象,全局变量g.cms_user用于渲染到后台管理界面cms_index.html
g.cms_email = user_email # 设置为全局变量,渲染到cms_profile.html中
g.cms_join_time = user_join_time # 设置为全局变量,渲染到cms_profile.html中
'''
# 上下文处理器,返回的字典中的键可以在模板上下文中使用。
@cms_bp.context_processor
def cms_context_processor():
return {"CMSPersmission": CMSPersmission} # 模板上下文中使用 cms_base.html中使用
模板文件:templates/cms/cms_base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- 在头文件中接收csrf信息 -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{% block title %}
{% endblock %}</title>
<script src="http://cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
<link href="http://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<script src="http://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<!-- 关联本地的cms_base.css样式 后台管理界面CMS的样式 -->
<link rel="stylesheet" href="{{ url_for('static', filename='cms/css/cms_base.css') }}">
<!-- 关联本地的cms_base.js样式 后台管理界面CMS的样式 -->
<script src="{{ url_for('static', filename='cms/js/cms_base.js') }}"></script>
<!-- 提示框的静态资源文件 -->
<link rel="stylesheet" href="{{ url_for('static', filename='common/sweetalert/sweetalert.css') }}">
<!-- 关联提示框的js样式 -->
<script src="{{ url_for('static', filename='common/sweetalert/lgalert.js') }}"></script>
<script src="{{ url_for('static', filename='common/sweetalert/sweetalert.min.js') }}"></script>
<!-- 预留空间,给之后的html文件进行修改调整 -->
{% block head %}
{% endblock %}
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">论坛CMS管理系统</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<!-- 从数据库中调用用户名,g对象全局调用g.cms_user对象 .username是该对象的一个字段属性 -->
<li><a href="#">{{ g.cms_user.username }}</a></li>
<!-- 用户注销,关联到views.py中的@cms_bp.route("/logout/")路由,重定向到该路由 -->
<li><a href="{{ url_for('cms.logout') }}">注销</a></li>
</ul>
<form class="navbar-form navbar-right">
<input type="text" class="form-control" placeholder="查找...">
</form>
</div>
</div>
</nav>
<div class="container-fluid">
<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="profile-li">
<a href="#">个人中心<span></span></a>
<ul class="subnav">
<!-- url重定向到/cms/profile/下 路由在views.py中定义了 -->
<li><a href="{{ url_for('cms.profile') }}">个人信息</a></li>
<!-- 密码修改的url_for 重定向到/cms/resetpwd/ 路由在views.py中定义了 -->
<li><a href="{{ url_for('cms.resetpwd') }}">修改密码</a></li>
<!-- 重定向到修改邮箱的url_for=/cms/resetemail/ -->
<li><a href="{{ url_for('cms.resetemail') }}">修改邮箱</a></li>
</ul>
</li>
<!-- 将全局变量的对象命名为user -->
{% set user = g.cms_user %}
<!-- 判断是否有权限进行管理后台,CMSPersmission.ALL_PERMISSION并没有传输过来,无法识别,需要用到钩子函数中的上下文管理器,在hooks.py中编写 -->
{% if user.has_permissions(CMSPersmission.POSTER) %}
<li class="nav-group post-manage"><a href="#">帖子管理</a></li>
{% endif %}
{% if user.has_permissions(CMSPersmission.COMMENTER) %}
<li class="comments-manage"><a href="#">评论管理</a></li>
{% endif %}
{% if user.has_permissions(CMSPersmission.BOARDER) %}
<li class="board-manage"><a href="#">板块管理</a></li>
{% endif %}
{% if user.has_permissions(CMSPersmission.FRONTUSER) %}
<li class="nav-group user-manage"><a href="#">前台用户管理</a></li>
{% endif %}
{% if user.has_permissions(CMSPersmission.CMSUSER) %}
<li class="nav-group cmsuser-manage"><a href="#">CMS用户管理</a></li>
{% endif %}
{% if user.is_developer %}
<li class="cmsrole-manage"><a href="#">CMS组管理</a></li>
{% endif %}
</ul>
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1>{% block page_title %}
{% endblock %}</h1>
<div class="main_content">
{% block content %}
{% endblock %}
</div>
</div>
</div>
</div>
</body>
</html>
5、服务端权限验证
装饰器文件用于验证用户不同的权限问题:apps/cms/decorators.py
# -*- encoding: utf-8 -*-
"""
@File : decorators.py
@Time : 2020/5/12 22:38
@Author : chen
"""
# 装饰器方法实现另一种判定后台用户当前界面是否是登录界面,不是就重定向到登录界面
from flask import session, g
from flask import redirect, url_for
# 双层装饰器修饰
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):
# print(func) # <function posts at 0x0000018950B76BF8>,views.py文件中的posts路由
# print(type(func)) # <class 'function'> 类
@wraps(func) # func需要传参,就需要用wraps
def inner(*args, **kwargs): # 内层函数
user = g.cms_user
if user.has_permissions(permission): # 判断g对象的权限
return func(*args, **kwargs) # 执行该方法
else:
return redirect(url_for('cms.index')) # 跳转回首页/cms/index/
return inner
return outter
视图文件apps/cms/views.py文件添加装饰器验证服务端权限
# -*- encoding: utf-8 -*-
"""
@File : views.py
@Time : 2020/5/11 9:59
@Author : chen
"""
# 蓝图文件:实现模块化应用,应用可以分解成一系列的蓝图 后端的类视图函数写在这个文件
from flask import (
request, redirect, url_for, # 页面跳转redirect request请求收集
Blueprint, render_template, views, session, # 定义类视图,显示模板文件
jsonify, g # jsonify强制转换成json数据
)
from exts import db, mail # 数据库中更新密码、邮箱等使用
# 导入form表单 .forms代表同级目录下的forms.py ResetPwdForm修改密码的form信息
from .forms import LoginForm, ResetPwdForm
# 导入forms.py文件中的邮箱验证的表单信息类
from apps.cms.forms import ResetEmailForm
# 导入模型 .models代表同级目录下的models.py CMSPersmission验证用户不同模块权限
from .models import CMS_User, CMSPersmission, CMSRole
from .decorators import permission_required # 传参装饰器验证用户不同模块权限
# 导入装饰器:判断当前界面是否是登录界面,不是就将url重定向到登录界面,一般不用,使用的主要是钩子函数
from .decorators import login_required
# 导入restful.py中的访问网页状态码的函数 redis_captcha:redis存储、提取、删除验证码功能
from utils import restful, random_captcha, redis_captcha # 随机生成验证码函数random_captcha()
# 导入flask-mail中的Message
from flask_mail import Message
cms_bp = Blueprint("cms", __name__, url_prefix='/cms/') # URL前缀url_prefix
# 钩子函数是在cms_bp创建之后才创建的,顺序在cms_bp创建之后
from .hooks import before_request
@cms_bp.route("/") # 后台界面
# @login_required # 装饰器判定当前界面是否是登录界面,但是需要每个路由函数都要加该装饰器,比较麻烦,推荐使用钩子函数
def index():
# return "cms index:后端类视图文件"
return render_template('cms/cms_index.html') # 登陆之后进入CMS后台管理界面,路径写全cms/cms_index.html
# 用户注销登录
@cms_bp.route("/logout/") # 需要关联到cms/cms_index.html中的注销属性
def logout():
# session清除user_id
del session['user_id']
# 重定向到登录界面
return redirect(url_for('cms.login')) # 重定向(redirec)为把url变为重定向的url
# 定义个人中心的路由
@cms_bp.route("/profile/")
def profile():
return render_template("cms/cms_profile.html") # 模板渲染(render_template)则不会改变url,模板渲染是用模板来渲染请求的url
# 定义类视图,显示模板文件 用户登录功能实现
class LoginView(views.MethodView):
def get(self, message=None): # message=None时候不传输信息到cms_login.html页面
return render_template("cms/cms_login.html", message=message) # 针对post方法中同样要返回到cms_login.html页面进行代码简化
# 用户登录操作验证
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 = CMS_User.query.filter_by(email=email).first() # 邮箱唯一,用于查询验证用户
if user and user.check_password(password): # 验证用户和密码是否都正确
session['user_id'] = user.id # 查询到用户数据时,保存session的id到浏览器
# session['user_name'] = user.username # 将数据库中的user.username保存到session中,在hooks.py中判断
# session['user_email'] = user.email # 将数据库中的email保存到session中,方便html调用信息
# session['user_join_time'] = user.join_time # 将数据库中的join_time保存到session中,方便html调用信息
if remember: # 如果用户点击了remember选择,在浏览器中进行数据持久化
session.permanent = True # 数据持久化,默认31天,需要设置session_key在config.py中
# 登录成功,跳转到后台首页
return redirect(url_for('cms.index')) # 在蓝图中必须加cms 跳转到index方法
else:
# return "邮箱或密码错误" # 登录出错,返回结果
# return render_template("cms/cms_login.html", message="邮箱或密码错误") # 登录出错,返回结果渲染到cms_login.html页面
return self.get(message="邮箱或密码错误") # 传参到get方法中,多加一个传输错误信息的参数到方法中
else:
# print(login_form.errors) # forms.py中的错误信息 字典类型数据
# print(login_form.errors.popitem()) # forms.py中的错误信息 元祖类型数据
# return "表单验证错误" # 错误信息需要渲染到cms_login.html页面
# return self.get(message=login_form.errors.popitem()[1][0]) # 字典类型数据信息提取
return self.get(message=login_form.get_error()) # login_form是收集到的表单信息,信息提取放置到forms.py的父类中实现
# 修改密码的类视图验证
class ResetPwd(views.MethodView):
def get(self):
return render_template('cms/cms_resetpwd.html') # 模板渲染到cms_resetpwd.html
# post提交密码修改
def post(self):
# 先审查旧密码是否与数据库中的信息相同
form = ResetPwdForm(request.form)
if form.validate():
oldpwd = form.oldpwd.data
newpwd = form.newpwd.data
# 对象
user = g.cms_user
# 将用户输入的密码进行加密检测是否与数据库中的相同
if user.check_password(oldpwd):
# 更新我的密码 将新密码赋值,此时的新密码已经经过验证二次密码是否一致
user.password = newpwd # user.password已经调用了models.py中的 @property装饰器进行密码加密
# 数据库更新
db.session.commit()
# return jsonify({"code": 400, "message": "密码修改成功"}) # 代码改写为下面
return restful.success("密码修改成功") # 调用restful.py中定义的访问网页成功的函数
else:
# 当前用户输入的旧密码与数据库中的不符
# return jsonify({"code": 400, "message": "旧密码输入错误"})
return restful.params_error(message="旧密码输入错误") # 参数错误
else:
# ajax 需要返回一个json类型的数据
# message = form.errors.popitem()[1][0] # 收集错误信息
# return jsonify({"code": 400, "message": message}) # 将数据转换成json类型
return restful.params_error(message=form.get_error()) # 参数错误,信息的收集在forms.py的父类函数中实现 form是收集到的信息
# 定义修改邮箱的类视图 验证
class ResetEmail(views.MethodView):
def get(self):
return render_template("cms/cms_resetemail.html") # 返回到修改邮箱页面url
def post(self):
form = ResetEmailForm(request.form) # 接收邮箱验证的form表单信息
if form.validate(): # 验证表单信息是否通过
email = form.email.data # 获取form表单中填写的邮箱地址
# 查询数据库
# CMS_User.query.filter_by(email=email).first()
# CMS_User.query.filter(CMS_User.email == email).first()
g.cms_user.email = email # 数据库中的查询在apps/cms/hooks.py文件中确定了该用户的数据库信息,用全局对象g.cms_user修改邮箱
db.session.commit()
return restful.success() # 邮箱修改成功
else:
return restful.params_error(form.get_error()) # form是这个类中的所有表单信息
# 发送测试邮件进行验证
@cms_bp.route("/send_email/")
def send_mail():
message = Message('邮件发送', recipients=['[email protected]'], body='测试邮件发送') # 主题:邮件发送;收件人:recipients;邮件内容:测试邮件发送
mail.send(message) # 发送邮件
return "邮件已发送"
# 邮件发送
class EmailCaptcha(views.MethodView):
def get(self): # 根据resetemail.js中的ajax方法来写函数,不需要post请求
email = request.args.get('email') # 查询email参数是否存在
if not email:
return restful.params_error('请传递邮箱参数')
# 发送邮件,内容为一个验证码:4、6位数字英文组合
captcha = random_captcha.get_random_captcha(4) # 生成4位验证码
message = Message('BBS论坛邮箱验证码', recipients=[email], body='您的验证码是:%s' % captcha)
# 异常处理
try:
mail.send(message)
except:
return restful.server_error(message="服务器错误,邮件验证码未发送!") # 发送异常,服务器错误
# 验证码保存,一般有时效性,且频繁请求变化,所以保存在Redis中
redis_captcha.redis_set(key=email, value=captcha) # redis中都是键值对类型,存储验证码
return restful.success("邮件验证码发送成功!")
# 帖子管理路由 ,需要和cms_base.js中命名的相同才可以
@cms_bp.route("/posts/")
@permission_required(CMSPersmission.POSTER) # 传参装饰器验证不同用户不同模块权限
def posts():
return render_template("cms/cms_posts.html")
# 评论管理路由
@cms_bp.route("/comments/")
@permission_required(CMSPersmission.COMMENTER) # 传参装饰器验证不同用户不同模块权限
def comments():
return render_template("cms/cms_comments.html")
# 板块管理路由
@cms_bp.route("/boards/")
@permission_required(CMSPersmission.BOARDER) # 传参装饰器验证不同用户不同模块权限
def boards():
return render_template("cms/cms_boards.html")
# 前台用户管理路由
@cms_bp.route("/fusers/")
@permission_required(CMSPersmission.FRONTUSER) # 传参装饰器验证不同用户不同模块权限
def fuser():
return render_template("cms/cms_fuser.html")
# 后用户管理路由
@cms_bp.route("/cusers/")
@permission_required(CMSPersmission.CMSUSER) # 传参装饰器验证不同用户不同模块权限
def cuser():
return render_template("cms/cms_cuser.html")
# 添加登录路由
cms_bp.add_url_rule("/login/", view_func=LoginView.as_view('login')) # view_func 命名操作名字,"/login/"路由地址
# 类视图函数添加绑定路由 注意类视图需要修改ResetPwd.as_view('resetpwd')
cms_bp.add_url_rule("/resetpwd/", view_func=ResetPwd.as_view('resetpwd')) # view_func 命名操作名字,/resetpwd/路由地址
# 添加修改邮箱的类视图路由绑定,路由的命名和cms_base.js中的命名要相同,否则不关联,url=/resetemail/必须要和resetemail.js中的ajax绑定的路由相同
cms_bp.add_url_rule("/resetemail/", view_func=ResetEmail.as_view('resetemail'))
# 绑定路由,路由的命名和cms_base.js中的命名要相同,必须要和resetemail.js中的ajax绑定的路由相同
cms_bp.add_url_rule("/email_captcha/", view_func=EmailCaptcha.as_view('email_captcha'))
同时添加不同模块管理的html页面文件,继承cms_base.html
模板文件templates/cms/cms_posts.html
<!-- 继承模板文件cms/cms_base.html 简化代码 -->
{% extends 'cms/cms_base.html' %}
<!-- 页面标题 -->
{% block title %}
帖子管理
{% endblock %}
<!-- 标题 -->
{% block page_title %}
{{self.title()}}
{% endblock %}
{% block content %}
{% endblock %}
模板文件templates/cms/cms_comments.html
<!-- 继承模板文件cms/cms_base.html 简化代码 -->
{% extends 'cms/cms_base.html' %}
<!-- 页面标题 -->
{% block title %}
评论管理
{% endblock %}
<!-- 标题 -->
{% block page_title %}
{{self.title()}}
{% endblock %}
{% block content %}
{% endblock %}
模板文件templates/cms/cms_boards.html
<!-- 继承模板文件cms/cms_base.html 简化代码 -->
{% extends 'cms/cms_base.html' %}
<!-- 页面标题 -->
{% block title %}
板块管理
{% endblock %}
<!-- 标题 -->
{% block page_title %}
{{self.title()}}
{% endblock %}
{% block content %}
{% endblock %}
模板文件templates/cms/cms_fusers.html
<!-- 继承模板文件cms/cms_base.html 简化代码 -->
{% extends 'cms/cms_base.html' %}
<!-- 页面标题 -->
{% block title %}
前台用户管理
{% endblock %}
<!-- 标题 -->
{% block page_title %}
{{self.title()}}
{% endblock %}
{% block content %}
{% endblock %}
模板文件templates/cms/cms_cusers.html
<!-- 继承模板文件cms/cms_base.html 简化代码 -->
{% extends 'cms/cms_base.html' %}
<!-- 页面标题 -->
{% block title %}
后台用户管理
{% endblock %}
<!-- 标题 -->
{% block page_title %}
{{self.title()}}
{% endblock %}
{% block content %}
{% endblock %}