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 %}