27、Flask实战第27天:cms后台登录
cms后台登录界面
后台登录页面,我们不用自己写,只需要去Bootstrap中文网去找一个模板改一下就行
这里使用的模板是:https://v3.bootcss.com/examples/signin/
点击右键查看网页源码,把源码复制下载
在项目templates目录下新建目录cms
在cms目录下新建文件cms_login.html,并把源码复制到该文件中
cms_login.html会用到样式文件signin.css, 点击它查看源码

在项目static目录下新建目录 cms/css
在static/cms/css新建文件signin.css, 并把源码拷贝进去
body {
padding-top: 40px;
padding-bottom: 40px;
background-color: #eee;
}
.form-signin {
max-width: 330px;
padding: 15px;
margin: 0 auto;
}
.form-signin .form-signin-heading,
.form-signin .checkbox {
margin-bottom: 10px;
}
.form-signin .checkbox {
font-weight: normal;
}
.form-signin .form-control {
position: relative;
height: auto;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 10px;
font-size: 16px;
}
.form-signin .form-control:focus {
z-index:;
}
.form-signin input[type="email"] {
margin-bottom: -1px;
border-bottom-right-radius:;
border-bottom-left-radius:;
}
.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius:;
border-top-right-radius:;
}
signin.css
修改cms_login.html, 修改后如下
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<meta name="description" content="">
<meta name="author" content=""> <title>登录-论坛CMS管理系统</title> <!-- Bootstrap core CSS -->
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> <!-- Custom styles for this template -->
<link href="{{ url_for('static', filename='cms/css/signin.css') }} " rel="stylesheet"> </head> <body> <div class="container"> <form class="form-signin" method="post">
<h2 class="form-signin-heading">请登录</h2>
<label for="inputEmail" class="sr-only">邮箱</label>
<input type="email" id="inputEmail" class="form-control" placeholder="邮箱" required autofocus name="email">
<label for="inputPassword" class="sr-only">密码</label>
<input type="password" id="inputPassword" class="form-control" placeholder="密码" required name="password">
<div class="checkbox">
<label>
<input type="checkbox" value="1" name="remember"> 记住我
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">登录</button>
</form> </div> <!-- /container --> </body>
</html>
cms_login.html
编写cms登录视图,编辑cms.views.py
... from flask views, render_template class LoginView(views.MethodView):
def get(self):
return render_template('cms/cms_login.html') def post(self):
pass bp.add_url_rule('/login/', view_func=LoginView.as_view('login'))
启动访问http://127.0.0.1:5000/cms/login/

cms后台登录功能
后台登录,前端就需要提交数据给我们,那么首先,我们就需要form验证
安装flask-wtf
pip install flask-wtf
编辑cms.forms.py
from wtforms import Form, StringField, IntegerField
from wtforms.validators import Email, InputRequired, Length class LoginForm(Form):
email = StringField(validators=[Email(message='邮箱格式错误'), InputRequired(message='请输入邮箱')])
password = StringField(validators=[Length(6,20, message='密码长度为6-20位')])
remember = IntegerField() #这个值不用验证,这里只是接收
cms.forms.py
然后就可以写视图了,编辑cms.views.py
from flask import Blueprint, views, render_template, request, session
from flask import redirect, url_for
from .forms import LoginForm
from .models import CMSUser bp = Blueprint('cms', __name__, url_prefix='/cms') @bp.route('/')
def index():
return 'cms index' 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,这样就算浏览器关闭session还是存在的
session.permanent = True
return redirect(url_for('cms.index')) #因为是蓝图这里必须使用cms.index,不能使用index
else:
#return render_template('cms/cms_login.html', message='账号或密码错误')
#等同于以下代码
return self.get(message='账号或密码错误') else:
#login_form.errors是一个字典,如{"email":['邮箱格式错误'], "password":["密码长度为6-20位"]}
#login_form.errors.popitem() 是取出字典的任意一项,结果是元组,如:("password":["密码长度为6-20位"])
#取出该元组的第2个元素:login_form.errors.popitem()[1], 如:["密码长度为6-20位"]
#最后取出错误提示语:login_form.errors.popitem()[1][0]
message = login_form.errors.popitem()[1][0]
return self.get(message=message) bp.add_url_rule('/login/', view_func=LoginView.as_view('login'))
cms.views.py
因为用到了session,所以还需要在配置文件,配置一个key为session加密用
...
import os
from datatime import timedelta #session
SECRET_KEY = os.urandom(24)
#设置session有效期为2天,若开启了session.permanent后不设置该参数,则默认为31天
PERMANENT_SESSION_LIFETIME = timedelta(days=7)
config.py
前端代码需要加上错误提示,首先要判断message是否存在



访问输入正确的邮箱,就可以登录成功,跳转的http://127.0.0.1/cms/并且保存用户session到cookie了
CMS后台登录限制
限制存在个问题,就是我们没有登录的情况下,也能够访问cm后台的首页http://127.0.0.1/cms/.接下来我们就要给它加上限制,只有登录后才能访问。
要实现这个功能,可以使用装饰器。
首先在cms下面新建个文件decorators.py, 以后此蓝图下的所有装饰器都放到这个文件里面
from flask import session, redirect, url_for
from functools import wraps def login_required(func):
@wraps(func) # 保留func的属性
def inner(*args, **kwargs):
if 'user_id' in session:
return func(*args, **kwargs)
else:
#session中没有user_id表示没有登录,则跳转到登录页面
return redirect(url_for('cms.login'))
return inner
decorators.py
然后在cms首页视图加上login_required装饰器
...
from .decorators import login_required
@bp.route('/') #路由装饰器一定要放在最上面,否则会找不到路由
@login_required
def index():
return 'cms index'
cms.views.py
这样,当我们在没有登录的情况下访问http://127.0.0.1/cms/会自动跳转到登录页面了,O(∩_∩)O哈哈~
代码优化
优化一
可以发现,我们把用户的session信息(user.id)保存在session['user_id']中

在登录装饰器中也用到

这样做有几个缺点:
1、当我们fornt也用到session的时候也这样用user_id 就不好区分
2、因为多处都用这个这个值,很容易写错
所以,我们可以把它写成一个常量来用,编辑config.py
...
CMS_USER_ID = 'HEBOANHEHE'
然后在用到user_id的地方都import config ,然后使用CMS_USER_ID


优化二
当表单验证不通过以后,我们是如下实现的,随机抽取一个错误信息出来(实际项目中可能要列出所有的错误信息,要根据需求来定)
message = login_form.errors.popitem()[1][0]
我们可以把获取错误信息的代码写到 form中,这样就避免每次都写这么长的代码,也避免容易犯错
class LoginFrom(Form):
email = StringField(validators=[Email(message='邮箱格式错误'),InputRequired(message='请输入邮箱') ])
password = StringField(validators=[Length(6,30, message='密码长度6-30')])
remember = IntegerField() #添加获取错误信息的方法
def get_error(self):
message = self.errors.popitem()[1][0]
return message
然后我们视图中调用这个方法就可以了
message = login_form.get_error()
因为项目中以后还会有其他的form验证,那么每个form中都要加这个方法,这样也比较麻烦,所以,我们可以进一步优化。我们可以使用继承来解决
在apps/下面新建一个forms.py
from wtforms import Form class BaseForm(Form):
def get_error(self):
message = self.errors.popitem()[1][0]
return message
以后我们写的form继承BaseForm就拥有get_error方法了
class LoginFrom(BaseForm):
email = StringField(validators=[Email(message='邮箱格式错误'),InputRequired(message='请输入邮箱') ])
password = StringField(validators=[Length(6,30, message='密码长度6-30')])
remember = IntegerField()
CSRF保护
编辑主程序文件bbs.py,开启csrf
...
from flask_wtf import CSRFProtect CSRFProtect(app)
加上csrf保护后,我们再尝试登陆就会失败

因为还需在提交表单的 form中添加一个input携带csrf_token给服务器验证
<form class="form-signin" method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
... </form>
27、Flask实战第27天:cms后台登录的更多相关文章
- PHP代码审计5-实战漏洞挖掘-cms后台登录绕过
cms后台登录绕过 练习源码:[来源:源码下载](数据库配置信息有误,interesting) 注:需进行安装 1.创建数据库 2.设置账号密码,连接数据库 3.1 正常登录后台,抓包分析数据提交位置 ...
- 九十四:CMS系统之cms后台登录限制
装饰器,验证当前session中是否存在定义的user_id,没有就重定向到登录页 from flask import session, redirect, url_forfrom functools ...
- 九十三:CMS系统之cms后台登录功能
config form from wtforms import Form, StringField, IntegerFieldfrom wtforms.validators import Email, ...
- 九十二:CMS系统之cms后台登录界面
html <!DOCTYPE html><html lang="zh-CN"> <head> <meta charset="ut ...
- 帝国CMS 后台登录空白
编辑/e/config/config.php中 $ecms_config['esafe']['ckfromurl']=0; //是否启用来源地址验证,0为不验证,1为全部验证,2为后台验证,3为前台验 ...
- 31、Flask实战第31天:cms后台修改密码
cms后台修改密码界面布局 先创建cms_resetpwd.html页面,继承cms_base.html {% extends 'cms/cms_base.html' %} {% block titl ...
- 28、Flask实战第28天:cms后台模板渲染
这节开始,我们需要用到前端模板.^_^..如果需要模板素材的同学,可以点击博客的右侧二维码进行打赏(10元),截图发送到邮箱463951510@qq.com,写明索取flask论坛素材即可,博主收到邮 ...
- [易学易懂系列|rustlang语言|零基础|快速入门|(27)|实战4:从零实现BTC区块链]
[易学易懂系列|rustlang语言|零基础|快速入门|(27)|实战4:从零实现BTC区块链] 项目实战 实战4:从零实现BTC区块链 我们今天来开发我们的BTC区块链系统. 简单来说,从数据结构的 ...
- Asp.Net Core 2.0 项目实战(10) 基于cookie登录授权认证并实现前台会员、后台管理员同时登录
1.登录的实现 登录功能实现起来有哪些常用的方式,大家首先想到的肯定是cookie或session或cookie+session,当然还有其他模式,今天主要探讨一下在Asp.net core 2.0下 ...
随机推荐
- 【BZOJ】1702: [Usaco2007 Mar]Gold Balanced Lineup 平衡的队列
[题意]给定n头牛,k个特色,给出每头牛拥有哪些特色的二进制对应数字,[i,j]平衡当且仅当第i~j头牛的所有特色数量都相等,求最长区间长度. [算法]平衡树+数学转化 [题解]统计前缀和sum[i] ...
- 【HDU】5269 ZYB loves Xor I
[算法]trie [题解] 为了让数据有序,求lowbit无法直接排序,从而考虑倒过来排序,然后数据就会呈现出明显的规律: 法一:将数字倒着贴在字典树上,则容易发现两数的lowbit就是它们岔道结点的 ...
- BTA 常问的 Java基础40道常见面试题及详细答案(山东数漫江湖))
八种基本数据类型的大小,以及他们的封装类 引用数据类型 Switch能否用string做参数 equals与==的区别 自动装箱,常量池 Object有哪些公用方法 Java的四种引用,强弱软虚,用到 ...
- 20151024_001_C#基础知识(静态与非静态的区别,值类型和引用类型,堆和栈的区别,字符串的不可变性,命名空间)
1:我们把这些具有相同属性和相同方法的对象进行进一步的封装,抽象出来类这个概念. 类就是个模子,确定了对象应该具有的属性和方法. 对象是根据类创建出来的. 2:类:语法 [public] class ...
- CSS3禁止网页中文本被选中代码
通常大家会有js来实现,另一个方案就是,将-webkit-user-select 和-moz-user-select 的值设为none,这针对于移动用户,可能会很有用.请谨慎使用这个属性:因为大部分用 ...
- js函数定义方法
1.函数声明 其语法为 function functionName(){ //函数体 } 首先是function关键字,然后是函数名,其重要特征是函数声明提升,即在执行代码之前会先读取函数声明,使其在 ...
- 74cms 注入exp
遇到就瞎写了一个: #!/usr/bin/env python #encoding:utf-8 #by i3ekr import requests,optparse,re parse = optpar ...
- 禁用 Cortana 的解决办法
1. GPedit.msc 2. 然后在本地组策略编辑器中,点击“用户配置”中的“管理模版”,接着双击右侧的“Windows 组件”. 3. 下拉滚动条,并找到“文件资源管理器”,双击进入. 找到“在 ...
- centos7安装libvirt支持xen
另外还有一个非常棒的用法 假如我要执行iostat这个命令来查看CPU与存储设备状态,可是执行却发现没有这个命令 于是执行yum install iostat,结果说找不到该软件,使用下面的办法可以解 ...
- python基础===进程,线程,协程的区别(转)
本文转自:http://blog.csdn.net/hairetz/article/details/16119911 进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度. 线程拥有自 ...