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工具,通过传入参数来使用这个案例。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/173959.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RPG项目01_UI登录

首先创建一个项目 将资源包导进Resources文件夹 创建一个Scripts脚本文件夹 然后再对Scripts脚本文件夹分门别类 导入UI资源包 创建一个Image 按住Alt 选择右下角 image就会覆盖整个面板 修改image名字为BG 将image图片放置背景栏 再创建一个image 改名为MainMenu 修改MainMenu…

一文读懂 | AI技术如何驱动企业供应链智能化,赋能企业降本增效?

近年以来,随着互联网技术的发展,AI的创新研究加速。随着大数据、云计算、物联网等信息技术的发展,以深度神经网络为代表的AI技术迅速发展,图像分类、语音识别、知识问答、无人驾驶等AI技术实现了从“不能用、不好用”到“可以用”…

HarmonyOS开发(七):构建丰富页面

1、组件状态管理 1.1、概述 在应用中,界面一般都是动态的。界面会根据不同状态展示不一样的效果。 ArkUI作为一种声明式UI,具有状态驱动UI更新的特点,当用户进行界面交互或有外部事件引起状态改变时,状态的变会会触发组件的自动…

2023.11.26 关于 Spring Boot 单元测试

目录 单元测试 优势 单元测试的使用 具体步骤 实现不污染数据库 阅读下面文章之前 建议点击下方链接了解 MyBatis 的创建与使用 MyBatis 的配置与使用 单元测试 单元测试 指对软件中的最小可测试单元进行检查和验证的过程单元测试 由开发人员在编码阶段完成,…

数据结构—树

文章目录 9.树(1).树的基本概念#1.基本定义#2.树的广义表表示法#3.基本术语 (2).树的存储结构#1.标准形式(常用)#2.逆存储形式#3.孩子兄弟存储法 (3).并查集#1.我们到底想解决什么问题#2.并查集结点#2.Find(查)#3.Union(并)#4.例子 (4).树的遍历#1.前序遍历#2.后序遍历#3.遍历的…

winform联合halcon读取图像出现问题

1.在Form1.cs和Form.Designer.cs中添加using HalconDotNet; 2. 3.添加Halcon导入.cs的程序 4.注释掉导出文件的主函数,不然会报错。 .

C#常见的设计模式-行为型模式

前言 行为型模式是面向对象设计中的一类设计模式,它关注对象之间的通信和相互作用,以实现特定的行为或功能。在C#中,有许多常见的行为型模式,下面将对其中10种行为型模式进行介绍,并给出相应的代码示例。 目录 前言1.…

ky10 server sp3 解决/boot/grub2/grub.cfg 找不到

现象 /boot/grub2 目录下不存在grub.cfg 配置文件 解决 执行下面脚本即可 yum install -y grub2 grub2-mkconfig -o /boot/grub2/grub.cfg 执行完成第一条命令 执行完成第二条命令 查看效果 已经生成这个文件了

Java抽象类和接口(2)

🐵本篇文章继续对接口相关知识进行讲解 一、排序 1.1 给一个对象数组排序: class Student {public String name;public int age;public Student(String name, int age) {this.name name;this.age age;}public String toString() {return "name:…

BetaFlight模块设计之三十七:SBUS

BetaFlight模块设计之三十七:SBUS 1. 源由2. sbus启动&动态任务3. 主要函数3.1 sbus初始化3.2 sbusFrameStatus更新3.3 rxFrameTimeUs3.4 sbusDataReceive接收数据 4. 辅助函数4.1 sbusChannelsDecode 5. 参考资料 1. 源由 接着BetaFlight模块设计之三十六&…

Leetcode—266.回文排列【简单】Plus

2023每日刷题&#xff08;四十&#xff09; Leetcode—266.回文排列 C语言实现代码 char chara[26] {0};int calculate(char *arr) {int nums 0;for(int i 0; i < 26; i) {nums arr[i];}return nums; }bool canPermutePalindrome(char* s) {int len strlen(s);for(in…

零基础在ubuntu上搭建rtmp服务器-srs

搭建服务器 搭建 SRS&#xff08;Simple-RTMP-Server&#xff09;服务器需要一些步骤&#xff0c;以下是一个简单的步骤指南。请注意&#xff0c;SRS 的配置可能会有所不同&#xff0c;具体取决于你的需求和环境。在开始之前&#xff0c;请确保你的 Ubuntu 系统已经连接到互联…

高效记账,轻松管理,批量记账与柱形图分析助你掌控收支明细

你是否曾经因为繁琐的记账过程而感到烦恼&#xff1f;是否曾经因为无法全面掌握个人或企业的收支情况而感到困惑&#xff1f;现在&#xff0c;我们为你带来了一种全新的高效记账方式&#xff0c;让你从此告别繁琐&#xff0c;轻松掌控收支明细。 首先第一步我们要打开晨曦记账…

商城免费搭建之java商城 鸿鹄云商 B2B2C产品概述

【B2B2C平台】&#xff0c;以传统电商行业为基石&#xff0c;鸿鹄云商支持“商家入驻平台自营”多运营模式&#xff0c;积极打造“全新市场&#xff0c;全新 模式”企业级B2B2C电商平台&#xff0c;致力干助力各行/互联网创业腾飞并获取更多的收益。从消费者出发&#xff0c;助…

pytest系列——pytest-xdist插件之多进程运行测试用例|| pytest-parallel插件之多线程运行测试用例

pytest之多进程运行测试用例(pytest-xdist) 前言 平常我们功能测试用例非常多时&#xff0c;比如有1千条用例&#xff0c;假设每个用例执行需要1分钟&#xff0c;如果单个测试人员执行需要1000分钟才能跑完当项目非常紧急时&#xff0c;会需要协调多个测试资源来把任务分成两…

警惕!AI正在“吞食”你的数据

视觉中国供图 □ 科普时报记者 陈 杰 AI大模型的热度&#xff0c;已然开始从产业向日常生活渗透&#xff0c;并引起不小的舆论旋涡。近日&#xff0c;网友指出国内某智能办软件有拿用户数据“投喂”AI之嫌&#xff0c;引发口水的同时&#xff0c;再度把公众对AI的关注转移到数…

使用paddledetection的记录

首先在这里使用的是是paddle--detection2.7的版本。 成功进行训练 目录&#xff1a; 目录 数据集准备 配置文件的修改 使用的是BML的平台工具&#xff1a; !python -m pip install paddlepaddle-gpu2.5 -i https://mirror.baidu.com/pypi/simple --user %cd /home/aistudio…

Rust语言入门教程(七) - 所有权系统

所有权系统是Rust敢于声称自己为一门内存安全语言的底气来源&#xff0c;也是让Rust成为一门与众不同的语言的所在之处。也正是因为这个特别的所有权系统&#xff0c;才使得编译器能够提前暴露代码中的错误&#xff0c;并给出我们必要且精准的错误提示。 所有权系统的三个规则…

Anaconda安装教程(超详细版)

目录 一、Anaconda简介 二、运行环境 三、安装Anaconda 四、手动配置环境变量&#xff08;重点&#xff09; 五、测试Anaconda环境是否配置成功 一、Anaconda简介 Anaconda&#xff0c;一个开源的Python发行版本&#xff0c;可用于管理Python及其相关包&#xff0c;包含了…

慕尼黑电子展采访全程 | Samtec管理层对话电子发烧友:虎家卓越服务

【摘要/前言】 今年的慕尼黑上海电子展上&#xff0c;Samtec大放异彩&#xff0c;特装展台一亮相就获得了大家的广泛关注&#xff0c;展台观众络绎不绝。 作为深耕连接器行业数十年的知名厂商以及Electronica的常客&#xff0c;Samtec毫无疑问地获得了大量媒体朋友的关注和报…