美文网首页利用Flask搭建微电影视频网站
利用Flask搭建微电影视频网站(五):访问控制器

利用Flask搭建微电影视频网站(五):访问控制器

作者: 啃饼小白 | 来源:发表于2018-09-07 09:22 被阅读26次

关于博主

努力与运动兼备~~~有任何问题可以加我好友或者关注微信公众号,欢迎交流,我们一起进步!

                                      微信公众号:  啃饼思录
                                    QQ: 2810706745(啃饼小白)

写在前面

本篇笔记,我们开始介绍后台页面逻辑的开发,里面涉及的知识点很多,请跟紧我的步伐,先说访问控制器(视图装饰器)。

本篇笔记对应上传的仓库为:https://github.com/licheetools/movie对应第五篇。

管理员登录

1、app/--init--.py 中创建db对象
2、app/models.py 中导入db对象
3、app/admin/forms.py 定义表单验证
4、app/templates/admin/login.html 中使用表单字段,信息验证,消息闪现
5、app/admin/views.py 中处理登录请求,保存会话
6、app/admin/views.py 定义登录装饰器,访问控制
使用到的模型:
模型: Admin
表单: LoginForm
请求方法: GET POST
访问控制: 无

然后进行代码的调整和优化,具体如下:打开app/--init--.py和models.py文件,将models.py中涉及app的代码,全部粘贴到--init--.py中,models.py只保留datetime的导入部分和db的引入部分,再删除--init--.py中重复包的导入部分即可,这么说你可能不明白,我直接贴上修改后的代码:

# --init--.py

from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
import pymysql

app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:root@127.0.0.5/movie"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS  "] = True
app.debug = True
db = SQLAlchemy(app)

from app.home import home as home_blueprint
from app.admin import admin as admin_blueprint

app.register_blueprint(home_blueprint)
app.register_blueprint(admin_blueprint, url_prefix="/admin")


# 404页面
@app.errorhandler(404)
def page_not_found(error):
    return render_template("home/404.html"), 404

# models.py

from datetime import datetime
from app import db

其余代码不变

然后运行一下我们的项目,你会发现出现一个警告:

FSADeprecationWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True or False to suppress this warning.
  'SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and '

那是因为默认这里是None,我们需要设定为True或者False,点击出现问题的文件:


我们把这里的None修改为True即可!然后重新启动就没有问题了。
Python3中Flask使用flask_sqlalchemy的的问题以及解决

开始定义后段登录表单

首先安装flask-wtf,你可以选择pip install flask-wtf或者在Pycharm里面安装。
然后打开forms.py文件,新增以下代码:



from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired


# 后台管理员登录表单
class LoginForm(FlaskForm):
    account = StringField(
        label="账号",
        validators=[
            DataRequired("账号不能为空!")
        ],
        description="账号",
        render_kw={
            "class": "form-control",
            "placeholder": "请输入账号!",
            "required": "required"
        }
    )

    pwd = PasswordField(
        label="密码",
        validators=[
            DataRequired("密码不能为空!")
        ],
        description="密码",
        render_kw={
            "class": "form-control",
            "placeholder": "请输入密码!",
            "required": "required"
        }
    )

    submit = SubmitField(
        '登录',
        render_kw={
            "class": "btn btn-primary btn-block btn-flat",
        }
    )

其中validators是进行数据合法性判断,render_kw 顾名思义就是与html相关,其作用就是渲染生成html代码,通过该参数可以加上各种class属性。

我们知道Flask这个框架也是符合MVC的网页设计模式的,M(models)数据库字段的定义我们已经完成了,C(controller)控制器就是处理url相关的业务逻辑,也写完了,现在就是只剩下V(view)视图的编写了,它的作用就是负责显示信息,让用户读取。如果你不熟悉MVC,这里推荐你去学习Python中MVC模式的使用

现在我们打开admin/views.py文件,我们导入刚才定义的LoginForm,并且实例化一个对象,然后传给我们的html即可:

from app.admin.forms import LoginForm

# 登入
@admin.route('/login/')
def login():
    form = LoginForm()
    return render_template("admin/login.html", form=form)

然后打开login.html页面,进行form字段的页面显示:

将<input name="user" type="text" class="form-control" placeholder="请输入账号!">

   修改为 {{ form.account }}即可

然后密码,提交都是这样:

 {{ form.pwd }}

{{ form.submit }}

接着运行一下我们的manage.py文件,发现出了这么一个错误:

KeyError: 'A secret key is required to use CSRF.'

说我们缺少csrf,关于常见的网络攻击,请点击我的另外一个专题里面的:零基础使用Django2.0.1打造在线教育网站(二十五):常见的网络攻防,这里就不细说了。

而关于CSRF的详细,可以点击这里CSRF 保护,我们需要两步操作:第一步:打开我们app/--init--.py文件(注意不是admin/--init--.py),新增一行代码:

app.config["SECRET_KEY"] = "movie_licheetools_top"  # 这里的SECRET_KEY可以随意设置,但最好是英文

第二步,所有的form表单都要在submit提交之前添加csrf_token。

{{ form.csrf_token }}

刷新一下,发现错误没有了!

视图的处理

修改views.py里面的登录函数:

# 登入
@admin.route('/login/')
def login():
    form = LoginForm()
    if form.validate_on_submit():
        data = form.data
    return render_template("admin/login.html", form=form)
然后是错误信息的提示:

最后是把from提交表单里面的action去掉,只保留method="post"即可!
因为我们默认请求方式是GET,所以需要去登录函数进行配置:

# 登入
@admin.route('/login/', methods=["GET", "POST"])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        data = form.data
    return render_template("admin/login.html", form=form)

现在重新运行一下我们的项目,在浏览器地址栏输入:http://127.0.0.1:5000/admin/login/


什么都不填,点击登录就出现这个提示字段,此处效果是由forms.py中"required": "required" 实现的,如果把这个注释掉就会显示我们自己定义的forms报错信息。

账号和密码的验证

首先我们来定义对账号字段的验证:打开admin/forms.py文件,在底部输入以下代码:

    def validate_account(self, field):
        account = field.data
        admin = Admin.query.filter_by(name=account).count()
        if admin == 0:
            raise ValidationError("你输入的账号不存在!")

但是对于密码的验证我们需要,进行HASH加密,打开models.py文件,找到管理员函数Admin,我们在函数内部新增几行代码:


    def check_pwd(self, pwd):
        from werkzeug.security import check_password_hash
        return check_password_hash(self.pwd, pwd)

接着我们打开views.py文件,修改Login函数:

from flask import  flash, session, request
from app.models import Admin

# 登入
@admin.route('/login/', methods=["GET", "POST"])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        data = form.data
        admin = Admin.query.filter_by(name=data["account"]).first()
        if not admin.check_pwd(data["pwd"]):  # 切记密码错误时,check_pwd返回false,但此时not check_pwd(data["pwd"])为真!
            flash("密码错误!")
            return redirect(url_for('admin.login'))
        session["admin"] = data["account"]   # 如果密码正确,就定义session的会话把数据保存到数据库。
        return redirect(request.args.get("next") or redirect(url_for("admin.index")))
    return render_template("admin/login.html", form=form)

接下来我们需要在前端页面中进行错误信息的flash闪现,打开login.html页面:

注销账号

# 登出
@admin.route('/logout/')
def logout():
    session.pop("admin, None)
    return redirect(url_for('admin.login'))

我们发现退出登陆之后,还可以访问我们的后台,这是不允许的,所以我们这里需要用到装饰器,用于对访问进行控制。关于装饰器,你可以点击查看这里视图装饰器
打开views.py文件,我们在最前面新增代码:

from functools import wraps


# 登录装饰器
def admin_login_req(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if "admin" not in session:
            return redirect(url_for("admin.login", next=request.url))
        return f(*args, **kwargs)
    return decorated_function

然后在所有函数(登录函数除外)路由下面添加@admin_login_req,注意顺序不能放错,访问控制装饰器一定要写在路由装饰器之后,否则访问控制将不起作用。!

# 后台首页
@admin.route("/")
@admin_login_req
def index():
    return render_template("admin/index.html")

注意:登录函数(Login)路由函数下面是不能添加装饰器的,否则会造成重定向次数过多,无法进行登录的!

但是到目前为止,你还登入不了后台(登入都是密码错误),为什么呢,因为你后台数据库里面是没有数据的,那有人就问了,我在数据库里自己加一个不就可以了么,是的,但是还是不可以登录,因为我们开启了登录验证,那怎么办呢?我提供两种方法!

登入后台系统

方法一:目前先去掉所有的登录验证

我们之前不是在后台每个页面都增加了@admin_login_req,为了后续开发的需要,我们先去掉这个@admin_login_req,等所有功能开发完了之后再加上,这是可以的,但是怕后面会忘记,我这里推荐使用第二种方法!

方法二:自己生成加密密码然后使用

因为我们是采用hash加密,你不懂hash加密没关系,你可以这样想,因为密码可以保存很长时间,而且一旦输入并确认就是惟一的,多了一个空格或者大小写都会报错,那么这样我们可以先定义一个自己后台的账号。例如,账号:admin,密码也是:admin,我们可以自己先对密码admin进行加密,然后保存到数据库里,不就可以登入了么?

我们在movie里面新建一个python文件,里面写入下面2行代码:

from werkzeug.security import generate_password_hash

print(generate_password_hash('admin'))

结果就是这样:

pbkdf2:sha256:50000$TBmI1Hmu$c85b1b204d96f47f3807e54a5cd599cc4e7d83e0f617dd1d86e4b0904670bbca

你自己试试看,是不是也是这个加密密码!现在你就可以把这个加密密码保存到你数据库admin的pwd里面了,然后就可以后台登录了。

问题解答

有小伙伴出现这个问题:

sqlalchemy.exc.InvalidRequestError: Table 'user' is already defined for this MetaData instance.  Specify 'extend_existing=True' to redefine options and columns on an existing Table object.

报错说你缺少extend_existing=True,解决办法是:在所有的models里面添加

__table_args__ = {"useexisting": True}

就是这样:

# 定义会员数据模型
class User(db.Model):
    __tablename__ = "user"
    __table_args__ = {"useexisting": True}
    id = db.Column(db.Integer, primary_key=True)  # 编号
......................

至此,本篇关于访问控制器的介绍就到此为止了,感谢你的赏阅!

本篇笔记对应上传的仓库为:https://github.com/licheetools/movie对应第五篇。

相关文章

网友评论

    本文标题:利用Flask搭建微电影视频网站(五):访问控制器

    本文链接:https://www.haomeiwen.com/subject/dzpnwftx.html