- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
PyJWT 和 python-jose 是两个用于处理 JSON Web Tokens (JWT) 的 Python 库。它们都有助于生成、解码、验证和管理 JWT,但它们在功能范围和设计哲学上有一些重要的区别。本篇介绍它们之间的一些差异,以及在项目中使用FastAPI+ python-jose 来处理访问令牌的生成以及一些例子代码供参考.
PyJWT
和 python-jose的差异
PyJWT 是一个专门处理 JWT 的 Python 库,它旨在简化 JWT 的创建和验证.
特点:
主要用法示例:
import jwt import datetime # 创建一个JWT payload = { "user_id": 123, "exp": datetime.datetime.utcnow() + datetime.timedelta(hours=1) } secret = 'your-secret-key' token = jwt.encode(payload, secret, algorithm='HS256') # 解码JWT decoded = jwt.decode(token, secret, algorithms=['HS256']) print(decoded)
python-jose 是一个更广泛的加密库,它不仅支持 JWT,还支持多种 JOSE (JSON Object Signing and Encryption) 标准,包括 JWS (JSON Web Signature)、JWE (JSON Web Encryption)、JWK (JSON Web Key)、JWA (JSON Web Algorithms) 等.
特点:
python-jose
还支持其他 JOSE 标准,因此功能更强大、更灵活。python-jose
的使用复杂度比 PyJWT 更高。主要用法示例:
from jose import jwt from jose.exceptions import JWTError # 创建一个JWT payload = { "user_id": 123, "exp": datetime.datetime.utcnow() + datetime.timedelta(hours=1) } secret = 'your-secret-key' token = jwt.encode(payload, secret, algorithm='HS256') # 解码JWT try: decoded = jwt.decode(token, secret, algorithms=['HS256']) print(decoded) except JWTError as e: print(f"Token is invalid: {e}")
PyJWT
专注于 JWT,适合需要简单 JWT 处理的项目;python-jose
则支持整个 JOSE 标准,适合需要更复杂加密和签名操作的项目。PyJWT
API 简单,易于上手;python-jose
更强大,但同时也更复杂。python-jose
支持的算法更广泛,尤其是在需要高级加密或签名场景时更具优势。PyJWT
是一个不错的选择;如果你需要全面的 JOSE 支持,包括 JWS、JWE 等,或者需要复杂的加密和签名,python-jose
是更好的选择。。
python-jose
处理 JWT 在使用 python-jose 处理 JWT 时,捕获和处理异常是一个重要的环节.
python-jose
首先,确保你已经安装了 python-jose:
pip install python-jose
python-jose
的 JWT 模块以下是一个使用 python-jose 的 JWT 处理的示例,包括如何捕获异常:
from jose import jwt, JWTError from jose.exceptions import ExpiredSignatureError # 定义密钥和有效负载 secret = 'your-secret-key' payload = { "user_id": 123, "exp": datetime.datetime.utcnow() + datetime.timedelta(hours=1) } # 生成 JWT token = jwt.encode(payload, secret, algorithm='HS256') # 解码 JWT 并处理可能的异常 try: decoded = jwt.decode(token, secret, algorithms=['HS256']) print(decoded) except ExpiredSignatureError: print("Token has expired") except JWTError: print("Token is invalid")
在处理 python-jose 的 JWT 时,正确地捕获和处理异常是关键。确保你的环境和工具能够正确识别异常类型,将有助于你更好地管理 JWT 错误.
如果我们需要再JWT的playload里面承载更多的信息,可以再claim中声明键值即可,你可以使用 python-jose 和 FastAPI 来实现 JWT 令牌生成操作。如下所示代码.
使用 FastAPI 和 python-jose 生成 JWT 令牌:
from fastapi import FastAPI, Depends, HTTPException, status, Request from fastapi.responses import JSONResponse from jose import JWTError, jwt from datetime import datetime, timedelta app = FastAPI() # 配置项,通常从配置文件中加载 JWT_SECRET_KEY = 'your_jwt_secret_key' JWT_ISSUER = 'your_issuer' JWT_AUDIENCE = 'your_audience' JWT_EXPIRED_DAYS = 7 ALGORITHM = 'HS256' def generate_token(user_info: dict, role_type: str): # 获取IP地址 ip = user_info.get('ip', '') # 定义声明 claims = { 'id': user_info['id'], 'email': user_info['email'], 'name': user_info['name'], 'nickname': user_info.get('nickname', ''), 'phone_number': user_info.get('mobile_phone', ''), 'gender': user_info.get('gender', ''), 'full_name': user_info.get('full_name', ''), 'company_id': user_info.get('company_id', ''), 'company_name': user_info.get('company_name', ''), 'dept_id': user_info.get('dept_id', ''), 'dept_name': user_info.get('dept_name', ''), 'role_type': role_type, 'ip': ip, 'mac_addr': '', # 无法获得Mac地址 'channel': '' } # 定义token过期时间 expiration = datetime.utcnow() + timedelta(days=JWT_EXPIRED_DAYS) # 创建JWT token to_encode = { **claims, 'iss': JWT_ISSUER, 'aud': JWT_AUDIENCE, 'exp': expiration } token = jwt.encode(to_encode, JWT_SECRET_KEY, algorithm=ALGORITHM) return token
@app.post('/token') async def get_token(request: Request): # 模拟的用户信息 user_info = { 'id': 123, 'email': 'user@example.com', 'name': 'John Doe', 'nickname': 'Johnny', 'mobile_phone': '123-456-7890', 'gender': 'Male', 'full_name': 'Johnathan Doe', 'company_id': 'ABC123', 'company_name': 'ABC Corp', 'dept_id': 'Dept001', 'dept_name': 'IT', 'ip': request.client.host } role_type = 'Admin' token = generate_token(user_info, role_type) headers = { 'access-token': token, 'Authorization': f'Bearer {token}' } return JSONResponse(content={'token': token}, headers=headers) if __name__ == "__main__": import uvicorn uvicorn.run(app, host="127.0.0.1", port=8000)
FastAPI
: 用于构建快速、现代的 Web API。Request
: 从 FastAPI
中导入,用于获取客户端的 IP 地址。generate_token
函数:
claims
,包含用户信息和额外的字段,如 IP 地址、角色类型等。exp
字段定义 JWT 的过期时间。jwt.encode
创建并签名 JWT。get_token
路由:
generate_token
生成 JWT。。
在 Python 的 FastAPI 框架中,你可以通过以下方式实现类似于 ASP.NET 中的 AllowAnonymous 和授权验证功能.
首先,你需要一个依赖项来检查请求中是否包含有效的 JWT 令牌。如果令牌无效或缺失,依赖项将拒绝请求。通过这种方式,只有标记为“允许匿名”的路由才会跳过验证.
确保安装了 python-jose 用于处理 JWT,以及 fastapi:
你可以创建一个名为 get_current_user 的依赖项,用于验证 JWT 令牌并提取用户信息。如果没有提供或验证失败,抛出 HTTPException.
from fastapi import Depends, HTTPException, status from jose import JWTError, jwt from typing import Optional JWT_SECRET_KEY = 'your_jwt_secret_key' ALGORITHM = 'HS256' def get_current_user(token: str = Depends(oauth2_scheme)): try: payload = jwt.decode(token, JWT_SECRET_KEY, algorithms=[ALGORITHM]) user_id: str = payload.get("id") if user_id is None: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials", headers={"WWW-Authenticate": "Bearer"}, ) return payload except JWTError: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials", headers={"WWW-Authenticate": "Bearer"}, )
get_current_user:用于解析和验证 JWT。如果令牌无效或缺失,会抛出 HTTPException,返回 401 状态码.
具体使用的时候,我们可能把用户信息缓存在Redis里面提高处理效率.
AllowAnonymous
功能在 FastAPI 中,你可以通过 Depends 来实现条件授权。对于需要授权的路由,只需将 get_current_user 作为依赖传递给路由函数。而无需授权的路由,可以直接定义.
from fastapi import FastAPI, Depends, HTTPException, status from fastapi.security import OAuth2PasswordBearer app = FastAPI() oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") # 允许匿名访问的路由 @app.get("/public") def read_public_data(): return {"message": "This is a public endpoint"} # 需要授权的路由 @app.get("/protected") def read_protected_data(current_user: dict = Depends(get_current_user)): return {"message": f"Hello, {current_user['name']}"} # 模拟登录生成 JWT 令牌的路由 @app.post("/token") def login(): # 这里省略了身份验证过程,只是直接生成一个 JWT 令牌 token = jwt.encode({"id": 1, "name": "John Doe"}, JWT_SECRET_KEY, algorithm=ALGORITHM) return {"access_token": token, "token_type": "bearer"}
/public
):可以直接访问,不需要任何身份验证。/protected
):必须提供有效的 JWT 令牌才能访问。/token
):生成一个 JWT 令牌,可以用于受保护的路Depends(get_current_user):在需要保护的路由中,通过依赖项注入 get_current_user,确保只有通过身份验证的用户才能访问.
在 FastAPI 中,建议通过依赖项注入(Depends)来获取当前用户的信息,而不是直接访问 request.user。这种方式更加灵活并且与 FastAPI 的设计哲学更一致.
在具体项目中,我们为了方便,往往通过中间件的方式进行定义和处理授权的过程.
通过authentiate函数处理验证用户令牌的有效性.
我们一般再main.py入口中加入中间件的处理即可.
# JWT auth, required app.add_middleware( AuthenticationMiddleware, backend=JwtAuthMiddleware(), on_error=JwtAuthMiddleware.auth_exception_handler, )
。
当你在解码 JWT 时遇到 "Invalid audience" 错误,通常意味着在生成或解码 JWT 时,aud (audience) 声明没有正确设置或验证。以下是解决这个问题的步骤和说明:
aud
(Audience) 声明aud
是 JWT 中的一个可选声明,通常用于指定 JWT 的接收者(受众)。在解码 JWT 时,jwt.decode
会检查这个声明是否与预期的值匹配。设置和检查 aud 声明,生成 Token 时设置 aud 。
。
如果你希望 JWT 包含 aud 声明,可以在生成 token 时传递它。例如:
to_encode = { "sub": "user_id", "aud": "your_audience", # 设置aud声明 "exp": datetime.utcnow() + timedelta(minutes=30) } token = jwt.encode(to_encode, settings.TOKEN_SECRET_KEY, algorithm=settings.TOKEN_ALGORITHM)
解码 Token 时验证 aud 。
在解码 JWT 时,指定 audience 参数以匹配生成时的 aud:
try: payload = jwt.decode( token, settings.TOKEN_SECRET_KEY, algorithms=[settings.TOKEN_ALGORITHM], audience="your_audience" # 验证aud声明 ) print(f"Decoded payload: {payload}") except JWTError as e: print(f"Token decode failed: {e}")
"Token decode failed: Subject must be a string" 错误通常是由于 sub (subject) 声明的值不是字符串引起的。sub 是 JWT 中常用的一个声明,用来标识 token 的主体,比如用户 ID 或用户名。JWT 标准要求 sub 的值必须是字符串.
检查 sub 声明的值 。
首先,确保在生成 token 时,sub 声明的值是一个字符串:
to_encode = { "sub": str(user_id), # 确保 user_id 是字符串 "aud": "your_audience", # 其他字段 "exp": datetime.utcnow() + timedelta(minutes=30) } token = jwt.encode(to_encode, settings.TOKEN_SECRET_KEY, algorithm=settings.TOKEN_ALGORITHM)
如果 sub 的值是一个非字符串类型(如整数或其他对象),请将其转换为字符串:
user_id = 123 # 假设 user_id 是一个整数 to_encode = { "sub": str(user_id), # 将 user_id 转换为字符串 "aud": "your_audience", "exp": datetime.utcnow() + timedelta(minutes=30) } token = jwt.encode(to_encode, settings.TOKEN_SECRET_KEY, algorithm=settings.TOKEN_ALGORITHM)
。
在处理数据模型和模式(schema)时,特别是当涉及到敏感信息(如密码、身份信息等)时,有时需要从输出或序列化结果中移除这些敏感字段。根据你使用的库或框架,处理敏感字段的方法会有所不同。以下是一些常见的方法来移除敏感字段:
使用 Pydantic 的 exclude 参数 。
如果你在使用 Pydantic(例如在 FastAPI 中),你可以使用模型的 dict 方法的 exclude 参数来排除敏感字段.
from pydantic import BaseModel class User(BaseModel): username: str email: str password: str # 敏感字段 user = User(username="user1", email="user1@example.com", password="secret") # 创建一个不包含敏感字段的字典 user_dict = user.dict(exclude={"password"}) print(user_dict)
使用 SQLAlchemy 的 __mapper_args__ 。
如果你使用 SQLAlchemy 并且希望从序列化结果中排除敏感字段,可以使用模型的 __mapper_args__ 进行配置。例如:
from sqlalchemy import Column, String from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class User(Base): __tablename__ = 'users' id = Column(String, primary_key=True) username = Column(String) email = Column(String) password = Column(String) # 敏感字段 def to_dict(self): # 移除敏感字段 return {c.name: getattr(self, c.name) for c in self.__table__.columns if c.name != 'password'} user = User(id="1", username="user1", email="user1@example.com", password="secret") print(user.to_dict())
自定义序列化方法 。
如果你使用自定义模型或类,并且没有使用特定的库,你可以实现自定义序列化方法来排除敏感字段.
class User: def __init__(self, username, email, password): self.username = username self.email = email self.password = password # 敏感字段 def to_dict(self): # 移除敏感字段 return { "username": self.username, "email": self.email } user = User(username="user1", email="user1@example.com", password="secret") print(user.to_dict())
。
最后此篇关于PyJWT和python-jose在处理JWT令牌处理的时候的差异和具体使用的文章就讲到这里了,如果你想了解更多关于PyJWT和python-jose在处理JWT令牌处理的时候的差异和具体使用的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我从NVIDIA手册Eg中复制了以下代码:__threadfence()。他们为什么有 在以下代码中使用了__threadfence()。我认为使用__syncthreads()而不是__thread
我在使用 SVN 更改列表和 svn diff 时遇到了一些麻烦.特别是我想获取特定修订范围的特定文件列表的更改历史记录。 SVN 变更列表似乎是完美的解决方案,所以我的方法是: svn change
我有两个 IP 地址列表。我需要将它们合并到三个文件中,交集,仅来自 list1 的文件和仅来自 list2 的文件。 我可以用 awk/diff 或任何其他简单的 unix 命令来做到这一点吗?如何
假设自上次更新(恢复)到我的 a.b 文件以来我做了一些更改。 此 a.b 文件也在存储库中更改。 现在我想将我所做的更改与 repos 更改进行比较。 如果我 svn revert 文件,我可以看到
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
我使用的是 openssl 1.0.1c , linux x86_64 我正在创建包含“hello”的文件(没有换行符) openssl dgst -sha256 hello_file i get :
假设我们有几个库。 有什么区别核心和 普通 图书馆?他们应该如何被认可,我们是否组织了两者的职责? +Common -Class1 +Core -Class2 +Lib1 has : Comm
如何在 SQLite 中计算以毫秒为单位的最小时间间隔? 好的,提供一些背景信息, 这是我的 table 的样子: link_budget table 所以有这个时间列,我想发出一个请求,以毫秒为单位
我想知道,乐观并发控制 (OCC) 和多版本并发控制 (MVCC) 之间的区别是什么? 到目前为止,我知道两者都是基于更新的版本检查。 在 OCC 中,我读到了没有获取读取访问锁的事务,仅适用于以后的
说到 SignalR,我有点菜鸟。刚刚开始四处探索和谷歌搜索它,我想知道是否有人可以向我解释完成的事情之间的一些差异。 在我见过的一些示例中,人们需要创建一个 Startup 类并定义 app.Map
我在 Ogre 工作,但这是一个一般的四元数问题。 我有一个对象,我最初对其应用旋转四元数 Q1。后来,我想让它看起来好像我最初通过不同的四元数 Q2 旋转了对象。 我如何计算四元数,该四元数将采用已
我了解 javascript 模块模式,但我使用两种类型的模块模式,并且想从架构 Angular 了解它们之间的区别。 // PATTERN ONE var module = (function()
我有两个具有完全相同键的 JSON。 val json1 = """{ 'name': 'Henry', 'age' : 26, 'activities' : {
我发现使用 VBA 在 Excel 中复制单个文件有两种不同的方法。一是文件复制: FileCopy (originalPath), (pathToCopyTo) 另一个是名称: Name (orig
我想知道查找两个 float 组之间差异的绝对值的最有效方法是什么? 是否是以下内容: private float absDifference(float[] vector1, float[] vec
我有一个关于 wicket getApplication 的问题。 getApplication() 和 getSession().getApplication 有什么区别? 部署 wicket 应用
我刚刚开始使用activemq,我有一个关于追溯消费者的问题,为了启用这个功能,你需要有一个持久的订阅。但是在主题上启用和不启用追溯的持久订阅有什么区别? activemq 文档说。 http://a
我有两个具有完全相同键的 JSON。 val json1 = """{ 'name': 'Henry', 'age' : 26, 'activities' : {
得到另一个 Erlang 二进制表示查询('因为这就是我最近正在阅读的内容,并且需要二进制协议(protocol)实现)。 如果我正确理解了类型说明符,那么对于“浮点”类型值,8 字节表示似乎很好(这
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 4 年前。 Improve this ques
我是一名优秀的程序员,十分优秀!