Flask 实现Token认证机制
在Flask框架中,实现Token认证机制并不是一件复杂的事情。除了使用官方提供的flask_httpauth
模块或者第三方模块flask-jwt
,我们还可以考虑自己实现一个简易版的Token认证工具。自定义Token认证机制的本质是生成一个令牌(Token),并在用户每次请求时验证这个令牌的有效性。
整个过程可以分为以下几个步骤:
- 用户登录时生成Token,并将Token与用户关联存储在服务器端。
- 用户在请求时携带Token。
- 服务器在收到请求后,验证Token的有效性。
- 如果Token有效,允许用户访问相应资源;否则,拒绝访问。
这种自定义的Token认证机制相对简单,适用于一些小型应用或者对于Token认证机制有特殊需求的场景。搭建这样一个简易的认证系统有助于理解Token认证的基本原理,并可以根据实际需求进行灵活的定制。
创建表结构
通过表结构的创建,建立用户认证和会话管理表。UserAuthDB
表存储了用户的账号密码信息,而SessionAuthDB
表则存储了用户登录后生成的Token
信息,包括用户名、Token本身以及Token的过期时间。这为后续实现用户注册、登录以及Token认证等功能提供了数据库支持。
UserAuthDB表:
- 用途:存储用户账号密码信息。
- 字段:
id
: 主键,自增,唯一标识每个用户。username
: 用户名,非空,唯一,用于登录时识别用户。password
: 密码,非空,用于验证用户身份。
SessionAuthDB表:
- 用途:存储登录成功后用户的Token信息。
- 字段:
id
: 主键,自增,唯一标识每个登录会话。username
: 用户名,非空,唯一,关联到UserAuthDB
表的用户名。token
: 用户登录后生成的Token,非空,唯一,用于身份验证。invalid_date
: Token的过期时间,用于判断Token是否过期。
代码通过Flask路由/create
实现了数据库表结构的创建,主要包括两张表,分别是UserAuthDB
和SessionAuthDB
。
|
验证函数
该验证函数用于保证传入的用户名和密码满足一定的安全性和格式要求。通过对长度和字符内容的检查,确保了传入的参数不会导致潜在的安全问题。这样的验证机制在用户注册、登录等场景中可以有效地防止一些常见的安全漏洞。
参数验证:
- 接受不定数量的参数
*kwargs
,可传入多个参数。 - 对于每个传入的参数,首先验证其长度是否在合法范围内(小于128个字符且不为空)。
字符串处理:
- 将参数转换为小写形式,然后去除两侧空格,并移除所有空格。
字符内容验证:
- 遍历处理后的字符串,检查其中的字符是否仅包含大写字母、小写字母和数字。如果出现其他字符,则认为非法。
返回结果:
- 如果所有参数验证通过,即长度合法且字符内容符合要求,则返回
True
,表示参数合法。 - 如果有任何一个参数不合法,则返回
False
,表示参数存在非法字符或超出长度限制。
代码定义了一个名为CheckParameters
的验证函数,该函数用于验证传入的参数是否合法。主要验证的对象是用户名和密码,具体概述如下:
def CheckParameters(*kwargs): |
登录认证函数
该函数实现了用户登录认证的核心逻辑。首先对输入的用户名和密码进行验证,然后检查用户是否存在以及是否已经有生成的Token。如果用户存在但Token不存在,生成一个新的Token并存入数据库,最终返回生成的Token。
路由定义:
- 使用
@app.route("/login", methods=["POST"])
定义了一个POST请求的路由,用于处理用户登录请求。
参数获取:
- 通过
request.form.to_dict()
获取POST请求中的参数,包括用户名(username)和密码(password)。
参数验证:
- 调用之前定义的
CheckParameters
函数对获取的用户名和密码进行合法性验证,确保其符合安全性和格式要求。
用户存在性验证:
- 调用
RunSqlite
函数查询UserAuthDB
表,验证用户名和密码是否匹配。如果存在匹配的用户,则继续执行下一步。
生成Token:
- 查询
SessionAuthDB
表,检查是否存在该用户的Token记录。如果存在,则直接返回该Token。 - 如果不存在Token记录,则生成一个32位的随机Token,并设置过期时间为当前时间戳加上360秒(6分钟)。
Token写入数据库:
- 将生成的Token和过期时间写入
SessionAuthDB
表。
返回结果:
- 返回生成的Token,作为登录成功的标识。
|
登录认证装饰器
检查用户登录状态Token是否过期的装饰器,装饰器用于装饰某一些函数,当主调函数被调用时,会优先执行装饰器内的代码,执行后根据装饰器执行结果返回或退出,装饰器分为两种模式,一种是FBV模式,另一种是CBV模式。
FBV(Function-Based Views)和CBV(Class-Based Views)是两种不同的视图设计模式,用于处理Web框架中的请求和生成响应。这两种模式在Django框架中被广泛使用。
FBV(Function-Based Views)
- 定义: FBV是指使用普通的Python函数来处理请求和生成响应的视图设计模式。
- 特点:
- 每个视图对应一个函数,函数接收请求作为参数,返回响应。
- 简单,易于理解和使用。
- 视图的逻辑和处理集中在一个函数中。
示例:
def my_view(request): |
CBV(Class-Based Views)
- 定义: CBV是指使用基于类的Python类来处理请求和生成响应的视图设计模式。
- 特点:
- 视图是类,每个类中可以包含多个方法来处理不同HTTP方法(GET、POST等)的请求。
- 提供了更多的代码组织和复用的可能性,可以使用类的继承、Mixin等方式。
- 更灵活,适用于复杂的业务逻辑和共享逻辑。
示例:
class MyView(View): |
FBV与CBV区别
- 结构差异: FBV使用函数,逻辑较为集中;CBV使用类,允许通过类的继承和Mixin等方式更好地组织代码。
- 代码复用: CBV更容易实现代码复用,可以通过继承和Mixin在不同的类之间共享逻辑;而FBV需要显式地将共享逻辑提取为函数。
- 装饰器: 在FBV中,使用装饰器来添加额外的功能;而在CBV中,通过类的继承和Mixin来实现相似的功能。
- 可读性: 对于简单的视图逻辑,FBV可能更直观易懂;对于较为复杂的业务逻辑,CBV提供了更好的组织和扩展性。
在Flask中,两种设计模式都可以使用,开发者可以根据项目的需求和个人喜好选择使用FBV或CBV。
基于FBV的装饰器设置使用时,需要注意装饰器嵌入的位置,装饰器需要在请求进入路由之前,即在请求未走原逻辑代码的时候介入,对原业务逻辑进行业务拓展。
from flask import Flask, request,render_template |
而基于CBV的装饰器设置,使用就显得更加细分化,可以定制管理专属功能,在外部定义装饰器可以全局使用,内部定义可以针对特定路由函数特殊处理。
from flask import Flask, request,render_template,views |
此处为了实现起来更简单一些此处直接使用FBV模式,我们实现的login_check
装饰器通过FVB模式构建,代码中取得用户的Token以及用户名对用户身份进行验证。
def login_check(func): |
调用演示
主调用函数则是具体的功能实现可以自定义扩展,当用户访问该路由时会优先调用login_check
装饰器来验证用户携带Token的合法性,如果合法则会通过return func(*args, **kwargs)
返回执行主调函数,否则直接返回验证失败的消息。
# 获取参数函数 |
FBV模式下的完整代码,以下是对代码的概述:
主要功能:
- 数据库操作: 封装了对 SQLite 数据库的基本增删改查操作(
RunSqlite
函数)。 - 用户认证: 提供了用户登录、注册和密码修改的功能。使用了 Token 机制进行登录认证,并通过装饰器
login_check
来验证 Token 的有效性。 - 创建数据库表: 提供了一个用于初始化数据库表结构的接口
/create
。 - 获取页面信息: 通过
/GetPage
接口,使用了login_check
装饰器来验证用户登录状态,仅对已登录用户提供页面信息。
主要路由
/create
:创建数据库表结构。/login
:用户登录接口,返回用户的 Token。/GetPage
:获取页面信息,需要用户登录并携带有效 Token。/register
:用户注册接口。/modify
:修改用户密码接口,需要用户登录并携带有效 Token。
代码结构
- 数据库操作:
- 提供了对 SQLite 数据库的基本操作,包括插入、更新、查询和删除。
- 用户认证:
- 使用了装饰器
login_check
对需要登录的路由进行认证。 - 提供了用户登录、注册和密码修改的路由。
- 使用了装饰器
- 创建数据库表:
- 提供了一个用于初始化数据库表结构的路由。
- 获取页面信息:
- 提供了一个用于获取页面信息的路由,需要用户登录并携带有效 Token。
from flask import Flask,render_template,request,Response,redirect,jsonify |
首先需要在Web页面访问http://127.0.0.1/create
路径实现对数据库的初始化,并打开Postman
工具,通过传入参数来使用这个案例。