当前位置: 首页 > news >正文

Flask 实现Token认证机制

在Flask框架中,实现Token认证机制并不是一件复杂的事情。除了使用官方提供的flask_httpauth模块或者第三方模块flask-jwt,我们还可以考虑自己实现一个简易版的Token认证工具。自定义Token认证机制的本质是生成一个令牌(Token),并在用户每次请求时验证这个令牌的有效性。

整个过程可以分为以下几个步骤:

  1. 用户登录时生成Token,并将Token与用户关联存储在服务器端。
  2. 用户在请求时携带Token。
  3. 服务器在收到请求后,验证Token的有效性。
  4. 如果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实现了数据库表结构的创建,主要包括两张表,分别是UserAuthDBSessionAuthDB

@app.route("/create",methods=["GET"])
def create():conn = sqlite3.connect("./database.db")cursor = conn.cursor()create_auth = "create table UserAuthDB(" \"id INTEGER primary key AUTOINCREMENT not null unique," \"username varchar(64) not null unique," \"password varchar(64) not null" \")"cursor.execute(create_auth)create_session = "create table SessionAuthDB(" \"id INTEGER primary key AUTOINCREMENT not null unique," \"username varchar(64) not null unique," \"token varchar(128) not null unique," \"invalid_date int not null" \")"cursor.execute(create_session)conn.commit()cursor.close()conn.close()return "create success"

验证函数

该验证函数用于保证传入的用户名和密码满足一定的安全性和格式要求。通过对长度和字符内容的检查,确保了传入的参数不会导致潜在的安全问题。这样的验证机制在用户注册、登录等场景中可以有效地防止一些常见的安全漏洞。

参数验证:

  • 接受不定数量的参数*kwargs,可传入多个参数。
  • 对于每个传入的参数,首先验证其长度是否在合法范围内(小于128个字符且不为空)。

字符串处理:

  • 将参数转换为小写形式,然后去除两侧空格,并移除所有空格。

字符内容验证:

  • 遍历处理后的字符串,检查其中的字符是否仅包含大写字母、小写字母和数字。如果出现其他字符,则认为非法。

返回结果:

  • 如果所有参数验证通过,即长度合法且字符内容符合要求,则返回True,表示参数合法。
  • 如果有任何一个参数不合法,则返回False,表示参数存在非法字符或超出长度限制。

代码定义了一个名为CheckParameters的验证函数,该函数用于验证传入的参数是否合法。主要验证的对象是用户名和密码,具体概述如下:

def CheckParameters(*kwargs):for item in range(len(kwargs)):# 先验证长度if len(kwargs[item]) >= 128 or len(kwargs[item]) == 0:return False# 先小写,然后去掉两侧空格,去掉所有空格local_string = kwargs[item].lower().strip().replace(" ","")# 判断是否只包含 大写 小写 数字for kw in local_string:if kw.isupper() != True and kw.islower() != True and kw.isdigit() != True:return Falsereturn True

登录认证函数

该函数实现了用户登录认证的核心逻辑。首先对输入的用户名和密码进行验证,然后检查用户是否存在以及是否已经有生成的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,作为登录成功的标识。
@app.route("/login",methods=["POST"])
def login():if request.method == "POST":# 获取参数信息obtain_dict = request.form.to_dict()if len(obtain_dict) != 0 and len(obtain_dict) == 2:username = obtain_dict["username"]password = obtain_dict["password"]# 验证是否合法is_true = CheckParameters(username,password)if is_true == True:# 查询是否存在该用户select = RunSqlite("./database.db", "UserAuthDB", "select", "username,password", f"username='{username}'")if select[0][0] == username and select[0][1] == password:# 查询Session列表是否存在select_session = RunSqlite("./database.db","SessionAuthDB","select","token",f"username='{username}'")if select_session != []:ref = {"message": ""}ref["message"] = select_session[0][0]return json.dumps(ref, ensure_ascii=False)# Session不存在则需要重新生成else:# 生成并写入token和过期时间戳token = ''.join(random.sample(string.ascii_letters + string.digits, 32))# 设置360秒周期,过期时间time_stamp = int(time.time()) + 360insert = RunSqlite("./database.db", "SessionAuthDB", "insert", "username,token,invalid_date", f"'{username}','{token}',{time_stamp}")if insert == True:ref = {"message": ""}ref["message"] = tokenreturn json.dumps(ref, ensure_ascii=False)else:return json.dumps("{'message': '用户名或密码错误'}", ensure_ascii=False)else:return json.dumps("{'message': '输入参数不可用'}", ensure_ascii=False)return json.dumps("{'message': '未知错误'}", ensure_ascii=False)

登录认证装饰器

检查用户登录状态Token是否过期的装饰器,装饰器用于装饰某一些函数,当主调函数被调用时,会优先执行装饰器内的代码,执行后根据装饰器执行结果返回或退出,装饰器分为两种模式,一种是FBV模式,另一种是CBV模式。

FBV(Function-Based Views)和CBV(Class-Based Views)是两种不同的视图设计模式,用于处理Web框架中的请求和生成响应。这两种模式在Django框架中被广泛使用。

FBV(Function-Based Views)
  • 定义: FBV是指使用普通的Python函数来处理请求和生成响应的视图设计模式。
  • 特点:
    • 每个视图对应一个函数,函数接收请求作为参数,返回响应。
    • 简单,易于理解和使用。
    • 视图的逻辑和处理集中在一个函数中。

示例:

def my_view(request):# 处理逻辑return HttpResponse("Hello, World!")
CBV(Class-Based Views)
  • 定义: CBV是指使用基于类的Python类来处理请求和生成响应的视图设计模式。
  • 特点:
    • 视图是类,每个类中可以包含多个方法来处理不同HTTP方法(GET、POST等)的请求。
    • 提供了更多的代码组织和复用的可能性,可以使用类的继承、Mixin等方式。
    • 更灵活,适用于复杂的业务逻辑和共享逻辑。

示例:

class MyView(View):def get(self, request):# 处理 GET 请求的逻辑return HttpResponse("Hello, World!")def post(self, request):# 处理 POST 请求的逻辑return HttpResponse("Received a POST request")
FBV与CBV区别
  1. 结构差异: FBV使用函数,逻辑较为集中;CBV使用类,允许通过类的继承和Mixin等方式更好地组织代码。
  2. 代码复用: CBV更容易实现代码复用,可以通过继承和Mixin在不同的类之间共享逻辑;而FBV需要显式地将共享逻辑提取为函数。
  3. 装饰器: 在FBV中,使用装饰器来添加额外的功能;而在CBV中,通过类的继承和Mixin来实现相似的功能。
  4. 可读性: 对于简单的视图逻辑,FBV可能更直观易懂;对于较为复杂的业务逻辑,CBV提供了更好的组织和扩展性。

在Flask中,两种设计模式都可以使用,开发者可以根据项目的需求和个人喜好选择使用FBV或CBV。

基于FBV的装饰器设置使用时,需要注意装饰器嵌入的位置,装饰器需要在请求进入路由之前,即在请求未走原逻辑代码的时候介入,对原业务逻辑进行业务拓展。

from flask import Flask, request,render_template
from functools import wrapsapp = Flask(__name__)def login(func):@wraps(func)def wrapper(*args, **kwargs):print("登录请求: {}".format(request.url))value = request.form.get("value")if value == "lyshark":# 调用原函数,并返回function_ptr = func(*args, **kwargs)return function_ptrelse:return "登录失败"return wrapper@app.route('/', methods=['GET', 'POST'])
@login
def index():if request.method == "POST":value = request.form.get("value")return "index"if __name__ == '__main__':app.run()

而基于CBV的装饰器设置,使用就显得更加细分化,可以定制管理专属功能,在外部定义装饰器可以全局使用,内部定义可以针对特定路由函数特殊处理。

from flask import Flask, request,render_template,views
from functools import wrapsapp = Flask(__name__)# 装饰器
def login(func):@wraps(func)def wrapper(*args, **kwargs):print("登录请求: {}".format(request.url))value = request.form.get("value")if value == "lyshark":# 调用原函数,并返回function_ptr = func(*args, **kwargs)return function_ptrelse:return "登录失败"return wrapper# 类视图
class index(views.MethodView):@logindef get(self):return request.args@logindef post(self):return "success"# 增加路由
app.add_url_rule(rule='/', view_func=index.as_view('index'))if __name__ == '__main__':app.run()

此处为了实现起来更简单一些此处直接使用FBV模式,我们实现的login_check装饰器通过FVB模式构建,代码中取得用户的Token以及用户名对用户身份进行验证。

def login_check(func):@wraps(func)def wrapper(*args, **kwargs):print("处理登录逻辑部分: {}".format(request.url))# 得到token 验证是否登陆了,且token没有过期local_timestamp = int(time.time())get_token = request.headers.get("token")# 验证传入参数是否合法if CheckParameters(get_token) == True:select = RunSqlite("database.db","SessionAuthDB","select","token,invalid_date",f"token='{get_token}'")print(select)# 判断是否存在记录,如果存在,在判断时间戳是否合理if select != []:# 如果当前时间与数据库比对,大于说明过期了需要删除原来的,让用户重新登录if local_timestamp >= int(select[0][1]):print("时间戳过期了")# 删除原来的Tokendelete = RunSqlite("database.db","SessionAuthDB","delete",f"token='{get_token}'","none")if delete == True:return json.dumps("{'token': 'Token 已过期,请重新登录获取'}", ensure_ascii=False)else:return json.dumps("{'token': '数据库删除异常,请联系开发者'}", ensure_ascii=False)else:# 验证Token是否一致if select[0][0] == get_token:print("Token验证正常,继续执行function_ptr指向代码.")# 返回到原函数return func(*args, **kwargs)else:print("Token验证错误 {}".format(select))return json.dumps("{'token': 'Token 传入错误'}", ensure_ascii=False)# 装饰器调用原函数# function_ptr = func(*args, **kwargs)return json.dumps("{'token': 'Token 验证失败'}", ensure_ascii=False)return wrapper

调用演示

主调用函数则是具体的功能实现可以自定义扩展,当用户访问该路由时会优先调用login_check装饰器来验证用户携带Token的合法性,如果合法则会通过return func(*args, **kwargs)返回执行主调函数,否则直接返回验证失败的消息。

# 获取参数函数
@app.route("/GetPage", methods=["POST"])
@login_check
def GetPage():if request.method == "POST":# 获取参数信息obtain_dict = request.form.to_dict()if len(obtain_dict) != 0 and len(obtain_dict) == 1:pagename = obtain_dict["pagename"]print("查询名称: {}".format(obtain_dict["pagename"]))# 相应头的完整写法req = Response(response="ok", status=200, mimetype="application/json")req.headers["Content-Type"] = "text/json; charset=utf-8"req.headers["Server"] = "LyShark Server 1.0"req.data = json.dumps("{'message': 'hello world'}")return reqelse:return json.dumps("{'message': '传入参数错误,请携带正确参数请求'}", ensure_ascii=False)return json.dumps("{'token': '未知错误'}", ensure_ascii=False)# 用户注册函数
@app.route("/register", methods=["POST"])
def Register():if request.method == "POST":obtain_dict = request.form.to_dict()if len(obtain_dict) != 0 and len(obtain_dict) == 2:print("用户名: {} 密码: {}".format(obtain_dict["username"], obtain_dict["password"]))reg_username = obtain_dict["username"]reg_password = obtain_dict["password"]# 验证是否合法if CheckParameters(reg_username, reg_password) == False:return json.dumps("{'message': '传入用户名密码不合法'}", ensure_ascii=False)# 查询用户是否存在select = RunSqlite("database.db","UserAuthDB","select","id",f"username='{reg_username}'")if select != []:return json.dumps("{'message': '用户名已被注册'}", ensure_ascii=False)else:insert = RunSqlite("database.db","UserAuthDB","insert","username,password",f"'{reg_username}','{reg_password}'")if insert == True:return json.dumps("{'message': '注册成功'}", ensure_ascii=False)else:return json.dumps("{'message': '注册失败'}", ensure_ascii=False)else:return json.dumps("{'message': '传入参数个数不正确'}", ensure_ascii=False)return json.dumps("{'message': '未知错误'}", ensure_ascii=False)# 密码修改函数
@app.route("/modify", methods=["POST"])
@login_check
def modify():if request.method == "POST":obtain_dict = request.form.to_dict()if len(obtain_dict) != 0 and len(obtain_dict) == 1:mdf_password = obtain_dict["password"]get_token = request.headers.get("token")print("获取token: {} 修改后密码: {}".format(get_token,mdf_password))# 验证是否合法if CheckParameters(get_token, mdf_password) == False:return json.dumps("{'message': '传入密码不合法'}", ensure_ascii=False)# 先得到token对应用户名select = RunSqlite("database.db","SessionAuthDB","select","username",f"token='{get_token}'")if select != []:# 接着直接修改密码即可modify_username = str(select[0][0])print("得到的用户名: {}".format(modify_username))update = RunSqlite("database.db","UserAuthDB","update",f"username='{modify_username}'",f"password='{mdf_password}'")if update == True:# 删除原来的token,让用户重新获取delete = RunSqlite("database.db","SessionAuthDB","delete",f"username='{modify_username}'","none")print("删除token状态: {}".format(delete))return json.dumps("{'message': '修改成功,请重新登录获取Token'}", ensure_ascii=False)else:return json.dumps("{'message': '修改失败'}", ensure_ascii=False)else:return json.dumps("{'message': '不存在该Token,无法修改密码'}", ensure_ascii=False)else:return json.dumps("{'message': '传入参数个数不正确'}", ensure_ascii=False)return json.dumps("{'message': '未知错误'}", ensure_ascii=False)

FBV模式下的完整代码,以下是对代码的概述:

主要功能:
  1. 数据库操作: 封装了对 SQLite 数据库的基本增删改查操作(RunSqlite 函数)。
  2. 用户认证: 提供了用户登录、注册和密码修改的功能。使用了 Token 机制进行登录认证,并通过装饰器 login_check 来验证 Token 的有效性。
  3. 创建数据库表: 提供了一个用于初始化数据库表结构的接口 /create
  4. 获取页面信息: 通过 /GetPage 接口,使用了 login_check 装饰器来验证用户登录状态,仅对已登录用户提供页面信息。

主要路由

  • /create:创建数据库表结构。
  • /login:用户登录接口,返回用户的 Token。
  • /GetPage:获取页面信息,需要用户登录并携带有效 Token。
  • /register:用户注册接口。
  • /modify:修改用户密码接口,需要用户登录并携带有效 Token。

代码结构

  1. 数据库操作:
    • 提供了对 SQLite 数据库的基本操作,包括插入、更新、查询和删除。
  2. 用户认证:
    • 使用了装饰器 login_check 对需要登录的路由进行认证。
    • 提供了用户登录、注册和密码修改的路由。
  3. 创建数据库表:
    • 提供了一个用于初始化数据库表结构的路由。
  4. 获取页面信息:
    • 提供了一个用于获取页面信息的路由,需要用户登录并携带有效 Token。
from flask import Flask,render_template,request,Response,redirect,jsonify
from functools import wraps
import json,sqlite3,random,string,timeapp = Flask(__name__)# 增删改查简单封装
def RunSqlite(db,table,action,field,value):connect = sqlite3.connect(db)cursor = connect.cursor()# 执行插入动作if action == "insert":insert = f"insert into {table}({field}) values({value});"if insert == None or len(insert) == 0:return Falsetry:cursor.execute(insert)except Exception:return False# 执行更新操作elif action == "update":update = f"update {table} set {value} where {field};"if update == None or len(update) == 0:return Falsetry:cursor.execute(update)except Exception:return False# 执行查询操作elif action == "select":# 查询条件是否为空if value == "none":select = f"select {field} from {table};"else:select = f"select {field} from {table} where {value};"try:ref = cursor.execute(select)ref_data = ref.fetchall()connect.commit()connect.close()return ref_dataexcept Exception:return False# 执行删除操作elif action == "delete":delete = f"delete from {table} where {field};"if delete == None or len(delete) == 0:return Falsetry:cursor.execute(delete)except Exception:return Falsetry:connect.commit()connect.close()return Trueexcept Exception:return False@app.route("/create",methods=["GET"])
def create():conn = sqlite3.connect("./database.db")cursor = conn.cursor()create_auth = "create table UserAuthDB(" \"id INTEGER primary key AUTOINCREMENT not null unique," \"username varchar(64) not null unique," \"password varchar(64) not null" \")"cursor.execute(create_auth)create_session = "create table SessionAuthDB(" \"id INTEGER primary key AUTOINCREMENT not null unique," \"username varchar(64) not null unique," \"token varchar(128) not null unique," \"invalid_date int not null" \")"cursor.execute(create_session)conn.commit()cursor.close()conn.close()return "create success"# 验证用户名密码是否合法
def CheckParameters(*kwargs):for item in range(len(kwargs)):# 先验证长度if len(kwargs[item]) >= 256 or len(kwargs[item]) == 0:return False# 先小写,然后去掉两侧空格,去掉所有空格local_string = kwargs[item].lower().strip().replace(" ","")# 判断是否只包含 大写 小写 数字for kw in local_string:if kw.isupper() != True and kw.islower() != True and kw.isdigit() != True:return Falsereturn True# 登录认证模块
@app.route("/login",methods=["POST"])
def login():if request.method == "POST":# 获取参数信息obtain_dict = request.form.to_dict()if len(obtain_dict) != 0 and len(obtain_dict) == 2:username = obtain_dict["username"]password = obtain_dict["password"]# 验证是否合法is_true = CheckParameters(username,password)if is_true == True:# 查询是否存在该用户select = RunSqlite("./database.db", "UserAuthDB", "select", "username,password", f"username='{username}'")if select[0][0] == username and select[0][1] == password:# 查询Session列表是否存在select_session = RunSqlite("./database.db","SessionAuthDB","select","token",f"username='{username}'")if select_session != []:ref = {"message": ""}ref["message"] = select_session[0][0]return json.dumps(ref, ensure_ascii=False)# Session不存在则需要重新生成else:# 生成并写入token和过期时间戳token = ''.join(random.sample(string.ascii_letters + string.digits, 32))# 设置360秒周期,过期时间time_stamp = int(time.time()) + 360insert = RunSqlite("./database.db", "SessionAuthDB", "insert", "username,token,invalid_date", f"'{username}','{token}',{time_stamp}")if insert == True:ref = {"message": ""}ref["message"] = tokenreturn json.dumps(ref, ensure_ascii=False)else:return json.dumps("{'message': '用户名或密码错误'}", ensure_ascii=False)else:return json.dumps("{'message': '输入参数不可用'}", ensure_ascii=False)return json.dumps("{'message': '未知错误'}", ensure_ascii=False)# 检查登录状态 token是否过期的装饰器
def login_check(func):@wraps(func)def wrapper(*args, **kwargs):print("处理登录逻辑部分: {}".format(request.url))# 得到token 验证是否登陆了,且token没有过期local_timestamp = int(time.time())get_token = request.headers.get("token")# 验证传入参数是否合法if CheckParameters(get_token) == True:select = RunSqlite("./database.db","SessionAuthDB","select","token,invalid_date",f"token='{get_token}'")print(select)# 判断是否存在记录,如果存在,在判断时间戳是否合理if select != []:# 如果当前时间与数据库比对,大于说明过期了需要删除原来的,让用户重新登录if local_timestamp >= int(select[0][1]):print("时间戳过期了")# 删除原来的Tokendelete = RunSqlite("./database.db","SessionAuthDB","delete",f"token='{get_token}'","none")if delete == True:return json.dumps("{'token': 'Token 已过期,请重新登录获取'}", ensure_ascii=False)else:return json.dumps("{'token': '数据库删除异常,请联系开发者'}", ensure_ascii=False)else:# 验证Token是否一致if select[0][0] == get_token:print("Token验证正常,继续执行function_ptr指向代码.")# 返回到原函数return func(*args, **kwargs)else:print("Token验证错误 {}".format(select))return json.dumps("{'token': 'Token 传入错误'}", ensure_ascii=False)# 装饰器调用原函数# function_ptr = func(*args, **kwargs)return json.dumps("{'token': 'Token 验证失败'}", ensure_ascii=False)return wrapper# 获取参数函数
@app.route("/GetPage", methods=["POST"])
@login_check
def GetPage():if request.method == "POST":# 获取参数信息obtain_dict = request.form.to_dict()if len(obtain_dict) != 0 and len(obtain_dict) == 1:pagename = obtain_dict["pagename"]print("查询名称: {}".format(obtain_dict["pagename"]))# 相应头的完整写法req = Response(response="ok", status=200, mimetype="application/json")req.headers["Content-Type"] = "text/json; charset=utf-8"req.headers["Server"] = "LyShark Server 1.0"req.data = json.dumps("{'message': 'hello world'}")return reqelse:return json.dumps("{'message': '传入参数错误,请携带正确参数请求'}", ensure_ascii=False)return json.dumps("{'token': '未知错误'}", ensure_ascii=False)# 用户注册函数
@app.route("/register", methods=["POST"])
def Register():if request.method == "POST":obtain_dict = request.form.to_dict()if len(obtain_dict) != 0 and len(obtain_dict) == 2:print("用户名: {} 密码: {}".format(obtain_dict["username"], obtain_dict["password"]))reg_username = obtain_dict["username"]reg_password = obtain_dict["password"]# 验证是否合法if CheckParameters(reg_username, reg_password) == False:return json.dumps("{'message': '传入用户名密码不合法'}", ensure_ascii=False)# 查询用户是否存在select = RunSqlite("database.db","UserAuthDB","select","id",f"username='{reg_username}'")if select != []:return json.dumps("{'message': '用户名已被注册'}", ensure_ascii=False)else:insert = RunSqlite("database.db","UserAuthDB","insert","username,password",f"'{reg_username}','{reg_password}'")if insert == True:return json.dumps("{'message': '注册成功'}", ensure_ascii=False)else:return json.dumps("{'message': '注册失败'}", ensure_ascii=False)else:return json.dumps("{'message': '传入参数个数不正确'}", ensure_ascii=False)return json.dumps("{'message': '未知错误'}", ensure_ascii=False)# 密码修改函数
@app.route("/modify", methods=["POST"])
@login_check
def modify():if request.method == "POST":obtain_dict = request.form.to_dict()if len(obtain_dict) != 0 and len(obtain_dict) == 1:mdf_password = obtain_dict["password"]get_token = request.headers.get("token")print("获取token: {} 修改后密码: {}".format(get_token,mdf_password))# 验证是否合法if CheckParameters(get_token, mdf_password) == False:return json.dumps("{'message': '传入密码不合法'}", ensure_ascii=False)# 先得到token对应用户名select = RunSqlite("./database.db","SessionAuthDB","select","username",f"token='{get_token}'")if select != []:# 接着直接修改密码即可modify_username = str(select[0][0])print("得到的用户名: {}".format(modify_username))update = RunSqlite("database.db","UserAuthDB","update",f"username='{modify_username}'",f"password='{mdf_password}'")if update == True:# 删除原来的token,让用户重新获取delete = RunSqlite("./database.db","SessionAuthDB","delete",f"username='{modify_username}'","none")print("删除token状态: {}".format(delete))return json.dumps("{'message': '修改成功,请重新登录获取Token'}", ensure_ascii=False)else:return json.dumps("{'message': '修改失败'}", ensure_ascii=False)else:return json.dumps("{'message': '不存在该Token,无法修改密码'}", ensure_ascii=False)else:return json.dumps("{'message': '传入参数个数不正确'}", ensure_ascii=False)return json.dumps("{'message': '未知错误'}", ensure_ascii=False)if __name__ == '__main__':app.run(debug=True)

首先需要在Web页面访问http://127.0.0.1/create路径实现对数据库的初始化,并打开Postman工具,通过传入参数来使用这个案例。

相关文章:

Flask 实现Token认证机制

在Flask框架中,实现Token认证机制并不是一件复杂的事情。除了使用官方提供的flask_httpauth模块或者第三方模块flask-jwt,我们还可以考虑自己实现一个简易版的Token认证工具。自定义Token认证机制的本质是生成一个令牌(Token)&…...

MATLAB 和 Simulink 官方文档下载地址

MATLAB 官方文档中文版下载网址: https://ww2.mathworks.cn/help/pdf_doc/matlab/index.html 如图: MATLAB 官方文档英文版下载网址: https://ww2.mathworks.cn/help/pdf_doc/matlab/index.html?langen 如图: Simulink 官…...

【Element】el-switch开关 点击弹窗确认框时状态先改变----点击弹窗取消框失效

一、背景 需求:在列表中添加定期出账的开关按钮,点击开关时,原来的状态不改变,弹出弹窗;点击弹窗取消按钮:状态不改变,点击弹窗确定按钮:状态改变,并调取列表数据刷新页…...

Java 中最常用的设计模式之一,工厂模式模式的写法,

文章目录 工厂模式1、简单工厂模式2、工厂模式3、抽象工厂4、总结 工厂模式 工厂模式是 Java 中最常用的设计模式之一,工厂模式模式的写法有好几种,这里主要介绍三种:简单工厂模式、工厂模式、抽象工厂模式 1、简单工厂模式 这里以制造cof…...

HTML的学习

知己知彼百战不殆 打算学习一下javascript 所以先从基础的html语言开始 其实就是头部 和身体 头部控制整个 html的语言 title等 <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"width…...

JS设计模式 — 行为委托

回顾一下原型&#xff0c;发现[[Prototype]]机制就是指对象中的一个内部链接引用另一个对象&#xff0c;这个机制的本质就是对象之间的关联关系 1、面相委托的设计 Task {setID: function(ID) { this.id ID; },outputID: function() { console.log( this.id ); } }; // 让 …...

Microsoft Expression Web - 网页布局

在本章中&#xff0c;我们将介绍网页的基本布局。在创建我们的网页布局之前&#xff0c;我们需要考虑我们的内容&#xff0c;然后设计我们希望如何呈现该内容&#xff0c;因为它是在我们的网站上可见的内容。 由我们如何呈现我们的内容&#xff0c;以便我们的观众找到我们的网…...

Java SpringBoot Controller常见写法

文章目录 环境Controller调用脚本运行结果总结 环境 系统: windows 11 工具: java, idea, git bash Controller 接口常见有以下几种方式 其中&#xff1a; Tobj 调用脚本 我的是windows 系统&#xff0c;使用 git bash 窗口运行, 用 cmd 或者 power shell 会有问题 curl …...

【驱动】SPI驱动分析(五)-模拟SPI驱动

简介 模拟SPI驱动是一种软件实现的SPI总线驱动。在没有硬件SPI控制器的系统中&#xff0c;通过软件模拟实现SPI总线的功能。它允许在不修改硬件的情况下&#xff0c;通过GPIO&#xff08;通用输入/输出&#xff09;引脚模拟SPI总线的通信&#xff0c;从而与SPI设备进行数据交换…...

人工智能_机器学习056_拉格朗日乘子法原理推导_公式由来详解_原理详解---人工智能工作笔记0096

https://blog.csdn.net/Soft_Po/article/details/118332454 这里有老师的一篇文章介绍拉格朗日乘子法的原理推导 结合老师的这篇文章我们来看一下详细的推导过程 可以看到上一节我们说,一个有条件的,函数,可以转换为一个,无条件的函数, 根据拉格朗日乘子法,可以创建出一个等…...

记RocketMQ本地开发环境搭建始末

前言 最近工作中涉及到了RocketMQ的应用&#xff0c;为方便开发决定本地搭建一套RocketMQ的使用环境。 果然实践是个好东西... VMware虚拟环境搭建 这个网上有很多教程&#xff0c;只会比我写的详细有条理&#xff0c;这里就不在赘述了。 虚拟机搭建好之后每次重启电脑都无…...

2023年全国职业院校技能大赛“ 信息安全管理与评估” 测试题2

一.单选题 1、下列不属于口令安全威胁的是&#xff1f;&#xff08; &#xff09; A、 弱口令 B、 明文传输 C、 MD5 加密 D、 多账户共用一个密码 2、在学校或单位如果发现自己的计算机感染了病毒,应首先采取什么措施 ( )。 A、断开网络 B、告知领导 C、杀毒 D、重…...

flutter开发实战-readmore长文本展开和收缩控件

flutter开发实战-readmore长文本展开和收缩控件 当长文本展开和收缩控件&#xff0c;我们需要使用readmore来处理长文本展开和收缩&#xff0c;方便阅读 一、引入readmore 在工程的pubspec.yaml中引入插件 readmore: ^2.1.0ReadMoreText的属性如下 const ReadMoreText(this.…...

如何使用简单的分支策略来保护您的 Git 项目

良好的分支策略可以使项目源代码获得一致且安全的数据&#xff0c;所有协作者可以在更短的生命周期内共享和访问这些数据。 您必须以灵活的方式设计项目模型&#xff0c;以便对所有成员角色和权限进行良好的管理。 我要谈论的并没有什么令人惊讶的新鲜事。您可能已经知道一些…...

vue3的 nextTick()的使用

引言&#xff1a; 当你修改了响应式状态时&#xff0c;DOM 会被自动更新。但是需要注意的是&#xff0c;DOM 更新不是同步的。Vue 会在“next tick”更新周期中缓冲所有状态的修改&#xff0c;以确保不管你进行了多少次状态修改&#xff0c;每个组件都只会被更新一次。 要等待…...

Redis Lua沙盒绕过 命令执行(CVE-2022-0543)漏洞复现

Redis Lua沙盒绕过 命令执行(CVE-2022-0543)漏洞复现 Redis如果在没有开启认证的情况下&#xff0c;可以导致任意用户在可以访问目标服务器的情况下未授权访问Redis以及读取Redis的数据。–那么这也就是redis未授权访问了 Redis的默认端口是6379 可以用空间测绘搜索&#xff…...

react中useState、useRef、变量之间的区别

函数组件有函数作用域&#xff0c;每次render时&#xff0c;声明的方法会生成新的引用&#xff0c;声明的普通变量会重新声明并赋值初始值&#xff0c;而useRef和useState会保留状态。 useState、useRef、变量的区别 1. useState 组件更新不会改变之前的状态&#xff0c;可以保…...

企业软件的分类|app小程序网站定制开发

企业软件的分类|app小程序网站定制开发 企业软件是指为满足企业管理和运营需求而设计和开发的一类软件&#xff0c;它通常用于支持企业的各项业务活动和流程。根据其功能和应用领域的不同&#xff0c;可以将企业软件分为以下几类。 1. 企业资源计划&#xff08;ERP&#xff09…...

Flink(八)【窗口】

前言 终于忙完了四门专业课的期末&#xff0c;确实挺累啊。今天开始继续学习 Flink &#xff0c;接着上次的内容。 今日摘录&#xff1a; 他觉得一个人奋斗更轻松自在。跟没有干劲的人在一起厮混&#xff0c;只会徒增压力。 -《解忧杂货店》 1、窗口 之前我们已经了解了…...

云轴科技ZStack信创云平台助力国泰君安期货实现信创改造

信创是数字中国建设的重要组成部分&#xff0c;也是数字经济发展的关键推动力量。作为云基础软件企业&#xff0c;云轴科技ZStack 产品矩阵全面覆盖数据中心云基础设施&#xff0c;ZStack信创云首批通过可信云《一云多芯IaaS平台能力要求》先进级&#xff0c;是其中唯一兼容四种…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)

船舶制造装配管理现状&#xff1a;装配工作依赖人工经验&#xff0c;装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书&#xff0c;但在实际执行中&#xff0c;工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战&#xff0c;克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释

以Module Federation 插件详为例&#xff0c;Webpack.config.js它可能的配置和含义如下&#xff1a; 前言 Module Federation 的Webpack.config.js核心配置包括&#xff1a; name filename&#xff08;定义应用标识&#xff09; remotes&#xff08;引用远程模块&#xff0…...

Monorepo架构: Nx Cloud 扩展能力与缓存加速

借助 Nx Cloud 实现项目协同与加速构建 1 &#xff09; 缓存工作原理分析 在了解了本地缓存和远程缓存之后&#xff0c;我们来探究缓存是如何工作的。以计算文件的哈希串为例&#xff0c;若后续运行任务时文件哈希串未变&#xff0c;系统会直接使用对应的输出和制品文件。 2 …...

图解JavaScript原型:原型链及其分析 | JavaScript图解

​​ 忽略该图的细节&#xff08;如内存地址值没有用二进制&#xff09; 以下是对该图进一步的理解和总结 1. JS 对象概念的辨析 对象是什么&#xff1a;保存在堆中一块区域&#xff0c;同时在栈中有一块区域保存其在堆中的地址&#xff08;也就是我们通常说的该变量指向谁&…...