「Flask实战」鱼书项目实战六

栏目: Python · 发布时间: 5年前

内容简介:首先验证登陆需要确认账号和密码是否正确,那么在前面密码是加密过后保存在数据库中的,所以再读取之前需要解密,在进行对比,这一系列操作可以使用flask中自带的验证成功后需要设置用户的登陆凭证,即然后使用验证

编写login的业务逻辑

首先验证登陆需要确认账号和密码是否正确,那么在前面密码是加密过后保存在数据库中的,所以再读取之前需要解密,在进行对比,这一系列操作可以使用flask中自带的 check_password_hash 来完成

# forms/sql_user.py
from werkzeug.security import generate_password_hash, check_password_hash

·····

#raw为传入的对比数据
def check_password(self, raw):
    return check_password_hash(self._password, raw)

验证成功后需要设置用户的登陆凭证,即 cookie ,设置 cookie 可以使用 flask 的插件 flask-login 来完成,使用 pip install flask-login 来安装插件,利用下面的 login_user 来设置 cookie
首先,先导入 flask-login ,并且注册到 app

#app/__init__.py
from flask import Flask
from app.models.sql_book import db
from flask_login import LoginManager

#实例化
login_manager = LoginManager()

def create_app():
    app = Flask(__name__)
    app.config.from_object('app.secure')
    app.config.from_object('app.setting')
    register_blueprint(app)

    db.init_app(app)
    db.create_all(app=app)

    #将login_manager注册到app上
    login_manager.init_app(app)

    return app

def register_blueprint(app):
    from app.web import web
    app.register_blueprint(web)

然后使用验证

·····

from flask_login import login_user

·····

@web.route('/login/', methods=['GET', 'POST'])
def login():
    form = LoginForm(request.form)
    if request.method == 'POST' and form.validate():
        # 从数据库中查询email这条记录
        user = User.query.filter_by(email=form.email.data).first()
        if user and user.check_password(form.password.data):
            #设置cookie
            login_user(user)
        else:
            flash('账号不存在或密码错误')
    return render_template('auth/login.html', form=form)

访问 127.0.0.1:5000/login/ ,登陆已经注册过的账户,在控制台中可以查看用户的 cookie 信息

访问权限控制

首先要安装 flask 的扩展 flask-login 使用 pip install flask_login 来安装,然后实例化并注册到 app

#app/__init__.py
from flask import Flask
from app.models.sql_book import db
from flask_login import LoginManager

# 实例化
login_manager = LoginManager()

def create_app():
    app = Flask(__name__)
    app.config.from_object('app.secure')
    app.config.from_object('app.setting')
    register_blueprint(app)

    db.init_app(app)
    db.create_all(app=app)

    #注册到app上
    login_manager.init_app(app)

    return app

def register_blueprint(app):
    from app.web import web
    app.register_blueprint(web)

你用来表示用户的类需要实现一些方法和属性

is_authenticated

当用户通过验证时,也即提供有效证明时返回 True 。(只有通过验证的用户会满足 login_required 的条件。)

is_active

如果这是一个活动用户且通过验证,账户也已激活,未被停用,也不符合任何你 的应用拒绝一个账号的条件,返回 True 。不活动的账号可能不会登入(当然, 是在没被强制的情况下)。

is_anonymous

如果是一个匿名用户,返回 True 。(真实用户应返回 False 。)

get_id()

返回一个能唯一识别用户的,并能用于从 user_loader 回调中加载用户的 unicode 。注意着 必须 是一个 unicode —— 如果 ID 原本是 一个 int 或其它类型,你需要把它转换为 unicode 。

但是可以通过 UserMixin 这个类来继承,并且你必须提供一个 user_loader 回调。这个回调用于从会话中存储的用户 ID 重新加载用户对象。它应该接受一个用户的 unicode ID 作为参数,并且返回相应的用户对象。

这个方法可以卸载 sql_user.py 下,但不是 User 的类方法

from sqlalchemy import Column, Integer, Float, String, Boolean
from werkzeug.security import generate_password_hash, check_password_hash

from app.models.base import Base, db
from app import login_manager

from flask_login import UserMixin


class User(Base, UserMixin):
    id = Column(Integer, primary_key=True)
    _password = Column('password', String(128), nullable=False)
    nickname = Column(String(24), nullable=False)
    phone_number = Column(String(18), unique=True)
    email = Column(String(50), unique=True, nullable=False)
    confirmed = Column(Boolean, default=False)
    beans = Column(Float, default=0)
    send_counter = Column(Integer, default=0)
    receive_counter = Column(Integer, default=0)
    wx_open_id = Column(String(50))
    wx_name = Column(String(32))

    @property
    def password(self):
        return self._password

    @password.setter
    def password(self, raw):
        self._password = generate_password_hash(raw)

    def check_password(self, raw):
        return check_password_hash(self._password, raw)

@login_manager.user_loader
def get_user(uid):
    return User.query.get(int(uid))

然后只需要在需要登陆才可以访问的页面前加上装饰器即可实现功能,例如在 gitf.py 下的一个视图函数

from . import web
#导入login_required模块
from flask_login import login_required


@web.route('/my/gifts')
@login_required
def my_gifts():
    return 'hello'

##未登录重定向和登陆后重定向

未登录当然不可能返回一个 hello ,一般网站的处理是重定向到登陆界面,并且登陆后再次跳转到未登录前的界面。

实现跳转登陆界面

# app/__init__.py
from flask import Flask
from app.models.sql_book import db
from flask_login import LoginManager

login_manager = LoginManager()

def create_app():
    app = Flask(__name__)
    app.config.from_object('app.secure')
    app.config.from_object('app.setting')
    register_blueprint(app)

    db.init_app(app)
    db.create_all(app=app)

    login_manager.init_app(app)
    login_manager.login_view = 'web.login'
    login_manager.login_message = '请先登录'

    return app

def register_blueprint(app):
    from app.web import web
    app.register_blueprint(web)

实现跳转到登陆前的页面

@web.route('/login/', methods=['GET', 'POST'])
def login():
    form = LoginForm(request.form)
    if request.method == 'POST' and form.validate():
        user = User.query.filter_by(email=form.email.data).first()
        if user and user.check_password(form.password.data):
            login_user(user)
            # 观察重定向登陆页面的url,跳转前的页面被加载了next参数上,所以只需要拿到这个参数即可
            next_page = request.args.get('next')
            # 判断是否为空,如果为空跳转到首页
            # 这里的首页在 web/main.py下,需要返回一个response不然就会报错。
            if not next_page:
                next_page = url_for('web.index')
            return redirect(next_page)
        else:
            flash('账号不存在或密码错误')
    return render_template('auth/login.html', form=form)

重定向攻击

上面的代码存在安全隐患,因为 next 的参数可控,存在重定向攻击的风险,所以我们需要判断这个 next 参数

这里给出简单判断,也可以使用白名单来校验

#将next_page的判断条件修改
if not next_page or not next_page.startswith('/'):

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

上瘾

上瘾

[美] 尼尔·埃亚尔、[美] 瑞安·胡佛 / 钟莉婷、杨晓红 / 中信出版集团 / 2017-5 / 49.00元

——为什么我们会习惯性地点开某个App? ——这种使用习惯到底是如何养成的? ——为什么有些产品能让我们戒不掉,而其他的产品却不行? ——是否有什么秘诀能让用户对你的产品形成使用习惯,欲罢不能? 《上瘾》揭示了很多让用户形成使用习惯,甚至“上瘾”的互联网产品服务背后的基 本设计原理,告诉你怎样打造一款让用户欲罢不能的产品。作者根据自己多年的研究、咨询及实际经验,提出了新颖而......一起来看看 《上瘾》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

URL 编码/解码
URL 编码/解码

URL 编码/解码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器