内容简介:首先验证登陆需要确认账号和密码是否正确,那么在前面密码是加密过后保存在数据库中的,所以再读取之前需要解密,在进行对比,这一系列操作可以使用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('/'):
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 「Flask实战」鱼书项目实战一
- 「Flask实战」鱼书项目实战三
- 「Flask实战」鱼书项目实战四
- 「Flask实战」flask鱼书项目实战二
- go语言实战教程:Redis实战项目应用
- Runtime项目实战
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Pragmatic Programmer
Andrew Hunt、David Thomas / Addison-Wesley Professional / 1999-10-30 / USD 49.99
本书直击编程陈地,穿过了软件开发中日益增长的规范和技术藩篱,对核心过程进行了审视――即根据需求,创建用户乐于接受的、可工作和易维护的代码。本书包含的内容从个人责任到职业发展,直至保持代码灵活和易于改编重用的架构技术。从本书中将学到防止软件变质、消除复制知识的陷阱、编写灵活、动态和易适应的代码、避免出现相同的设计、用契约、断言和异常对代码进行防护等内容。一起来看看 《The Pragmatic Programmer》 这本书的介绍吧!