最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python中實現(xiàn)JWT認(rèn)證的完整指南(從生成到驗證)

 更新時間:2025年06月24日 09:14:31   作者:盛夏綻放  
JSON?Web?Tokens?(JWT)?是現(xiàn)代?Web?開發(fā)中廣泛使用的身份驗證機制,本文將用生動的方式帶你全面了解?JWT?在?Python?中的實現(xiàn),包括生成、驗證和各種相關(guān)方法,需要的朋友可以參考下

引言

JSON Web Tokens (JWT) 是現(xiàn)代 Web 開發(fā)中廣泛使用的身份驗證機制。本文將用生動的方式帶你全面了解 JWT 在 Python 中的實現(xiàn),包括生成、驗證和各種相關(guān)方法,通過豐富的比喻、表格和流程圖幫助你徹底掌握 JWT。

一、JWT 是什么?為什么需要它?

想象你去游樂園,入園時會得到一個手環(huán)。這個手環(huán):

  • 包含信息:顯示你的門票類型(VIP/普通)
  • 防偽設(shè)計:有特殊圖案難以偽造
  • 有效期:只在當(dāng)天有效

JWT 就是這樣的數(shù)字手環(huán):

游樂園手環(huán)JWT 令牌
門票類型用戶角色
入園時間簽發(fā)時間(iat)
閉園時間過期時間(exp)
防偽標(biāo)記數(shù)字簽名
手環(huán)材質(zhì)加密算法

傳統(tǒng) session 與 JWT 對比

特性SessionJWT
存儲位置服務(wù)器客戶端
擴展性需要共享session天然無狀態(tài)
跨域支持需要配置原生支持
移動端友好度需處理cookie直接使用header
安全性依賴cookie安全依賴token存儲方式
典型場景傳統(tǒng)Web應(yīng)用API/移動應(yīng)用/微服務(wù)

二、JWT 的結(jié)構(gòu)解析

一個 JWT 看起來像這樣:xxxxx.yyyyy.zzzzz

就像三明治分三層:

Header (面包上層)

{
  "alg": "HS256",  // 簽名算法(HMAC SHA256)
  "typ": "JWT"     // 類型標(biāo)識
}

Payload (餡料)

{
  "sub": "user123",  // 主題(用戶ID)
  "name": "張三",
  "admin": true,
  "iat": 1516239022  // 簽發(fā)時間
}

Signature (面包下層+防偽標(biāo)記)

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  密鑰
)

生成流程

[Header] → base64編碼 → xxxxx
[Payload] → base64編碼 → yyyyy
[xxxxx.yyyyy + 密鑰] → 簽名算法 → zzzzz
最終令牌:xxxxx.yyyyy.zzzzz

三、Python 中實現(xiàn) JWT

1. 安裝 PyJWT 包

pip install pyjwt

2. 生成 JWT

import jwt
import datetime
from datetime import timezone

# 建議從環(huán)境變量讀取
SECRET_KEY = "your_super_secret_key"

def generate_jwt(user_id: str, username: str, role: str) -> str:
    """生成JWT令牌"""
    payload = {
        "sub": user_id,  # 標(biāo)準(zhǔn)字段:主題
        "name": username,
        "role": role,
        "iat": datetime.datetime.now(tz=timezone.utc),  # 簽發(fā)時間
        "exp": datetime.datetime.now(tz=timezone.utc) + datetime.timedelta(hours=1)  # 過期時間
    }
    return jwt.encode(payload, SECRET_KEY, algorithm="HS256")

參數(shù)詳解表

參數(shù)類型必填說明示例
payloaddict負(fù)載數(shù)據(jù){“sub”: “user123”}
keystr簽名密鑰“secret”
algorithmstr簽名算法“HS256”
headersdict額外頭部{“kid”: “key1”}

標(biāo)準(zhǔn)聲明字段(建議)

字段全稱說明示例
subSubject主題(用戶ID)“user123”
expExpiration過期時間1735689600
iatIssued At簽發(fā)時間1735686000
audAudience接收方“mobile-app”
issIssuer簽發(fā)者“auth-server”

3. 驗證 JWT

def verify_jwt(token: str) -> dict:
    """驗證JWT令牌"""
    try:
        payload = jwt.decode(
            token, 
            SECRET_KEY, 
            algorithms=["HS256"],
            audience="your-app",  # 驗證接收方
            issuer="auth-server"  # 驗證簽發(fā)方
        )
        return payload
    except jwt.PyJWTError as e:
        print(f"Token驗證失敗: {type(e).__name__}: {e}")
        return None

驗證流程示意圖

4. 錯誤處理大全

from fastapi import HTTPException, status

def validate_token(token: str):
    try:
        return jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
    except jwt.ExpiredSignatureError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Token已過期",
            headers={"WWW-Authenticate": "Bearer"}
        )
    except jwt.InvalidTokenError as e:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=f"無效Token: {str(e)}",
            headers={"WWW-Authenticate": "Bearer"}
        )

異常類型表

異常類觸發(fā)條件HTTP狀態(tài)碼處理建議
ExpiredSignatureErrorToken過期401提示重新登錄
InvalidSignatureError簽名無效401拒絕訪問
InvalidTokenError通用錯誤401記錄日志
MissingRequiredClaimError缺少必要聲明400返回錯誤詳情
InvalidIssuerError簽發(fā)者不匹配403審計日志

四、高級應(yīng)用場景

1. 雙令牌系統(tǒng)(Access + Refresh)

以下是基于你的 JWT 認(rèn)證流程整理的表格表示:

步驟流程節(jié)點條件/判斷動作/響應(yīng)備注
1用戶登錄提交賬號密碼系統(tǒng)驗證憑證
2驗證結(jié)果驗證成功生成: - access_token(15分鐘) - refresh_token(7天)
驗證失敗返回錯誤信息HTTP 401
3返回響應(yīng)返回雙token給客戶端
4API訪問攜帶access_token驗證token有效性
5驗證結(jié)果access_token有效正常返回請求數(shù)據(jù)HTTP 200
access_token無效檢查是否存在refresh_token
6刷新檢查存在有效refresh_token發(fā)放新access_tokenHTTP 200 + 新token
無有效refresh_token要求重新登錄HTTP 401

詳細(xì)說明表格:

階段條件分支系統(tǒng)行為客戶端響應(yīng)HTTP狀態(tài)碼
登錄階段
1.1憑證正確生成雙token接收: - access_token - refresh_token200
1.2憑證錯誤終止流程收到錯誤提示401
API訪問階段
2.1access_token有效處理請求獲取正常數(shù)據(jù)200
2.2access_token過期檢查refresh_token
Token刷新階段
3.1refresh_token有效發(fā)放新access_token獲取新token200
3.2refresh_token無效終止流程要求重新登錄401

異常處理補充表:

異常情況系統(tǒng)處理客戶端表現(xiàn)
access_token格式錯誤直接拒絕請求收到"無效token"錯誤
refresh_token過期清除客戶端存儲跳轉(zhuǎn)登錄頁面
連續(xù)使用過期refresh_token標(biāo)記為安全事件強制登出所有設(shè)備

實現(xiàn)代碼:

def generate_token_pair(user_id: str):
    """生成令牌對"""
    access_payload = {
        "sub": user_id,
        "type": "access",
        "exp": datetime.datetime.now(tz=timezone.utc) + datetime.timedelta(minutes=15)
    }
    refresh_payload = {
        "sub": user_id,
        "type": "refresh",
        "exp": datetime.datetime.now(tz=timezone.utc) + datetime.timedelta(days=7)
    }
    
    access_token = jwt.encode(access_payload, SECRET_KEY, algorithm="HS256")
    refresh_token = jwt.encode(refresh_payload, SECRET_KEY, algorithm="HS256")
    
    return {
        "access_token": access_token,
        "refresh_token": refresh_token
    }

def refresh_access_token(refresh_token: str):
    """使用refresh_token獲取新access_token"""
    try:
        payload = jwt.decode(refresh_token, SECRET_KEY, algorithms=["HS256"])
        if payload.get("type") != "refresh":
            raise HTTPException(status_code=400, detail="無效的refresh token類型")
        
        new_payload = {
            "sub": payload["sub"],
            "type": "access",
            "exp": datetime.datetime.now(tz=timezone.utc) + datetime.timedelta(minutes=15)
        }
        return jwt.encode(new_payload, SECRET_KEY, algorithm="HS256")
    
    except jwt.PyJWTError as e:
        raise HTTPException(status_code=401, detail=f"refresh token無效: {str(e)}")

2. 與 FastAPI/Django 集成

FastAPI 示例

from fastapi import Depends, FastAPI, HTTPException
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials

security = HTTPBearer()

app = FastAPI()

async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)):
    token = credentials.credentials
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
        return payload
    except jwt.PyJWTError:
        raise HTTPException(status_code=401, detail="無效或過期的token")

@app.get("/protected")
async def protected_route(user: dict = Depends(get_current_user)):
    return {"message": f"你好, {user['sub']}!", "user_data": user}

Django 示例

from django.http import JsonResponse
from functools import wraps

def jwt_required(view_func):
    @wraps(view_func)
    def wrapper(request, *args, **kwargs):
        auth_header = request.headers.get('Authorization')
        if not auth_header or not auth_header.startswith('Bearer '):
            return JsonResponse({"error": "未提供token"}, status=401)
        
        token = auth_header.split(' ')[1]
        try:
            request.user = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
            return view_func(request, *args, **kwargs)
        except jwt.ExpiredSignatureError:
            return JsonResponse({"error": "token已過期"}, status=401)
        except jwt.InvalidTokenError:
            return JsonResponse({"error": "無效token"}, status=401)
    return wrapper

@jwt_required
def protected_view(request):
    return JsonResponse({"data": "受保護的內(nèi)容", "user": request.user})

五、安全最佳實踐

密鑰管理

  • 使用環(huán)境變量存儲密鑰
import os
SECRET_KEY = os.getenv("JWT_SECRET_KEY", "fallback-secret")
  • 定期輪換密鑰(密鑰版本控制)
keys = {
    "2023": "old-secret",
    "2024": "current-secret"
}

增強安全措施

def generate_secure_token(user, ip):
    """生成帶IP綁定的token"""
    payload = {
        "sub": user.id,
        "ip": ip,  # 綁定客戶端IP
        "jti": str(uuid.uuid4())  # 唯一標(biāo)識防止重放
    }
    return jwt.encode(payload, SECRET_KEY, algorithm="HS256")

def verify_secure_token(token, ip):
    payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
    if payload.get("ip") != ip:
        raise ValueError("IP地址不匹配")
    return payload

黑名單實現(xiàn)

from redis import Redis

redis = Redis(host='localhost', port=6379)

def revoke_token(jti: str, expire_in: int):
    """將token加入黑名單"""
    redis.setex(f"blacklist:{jti}", expire_in, "revoked")

def is_revoked(jti: str) -> bool:
    """檢查是否在黑名單"""
    return bool(redis.exists(f"blacklist:{jti}"))

六、性能優(yōu)化技巧

選擇更快的算法

算法性能比較表(執(zhí)行時間,越小越好)

算法類型性能指標(biāo)(單位:ms)備注
HS2561.2對稱加密算法
RS2563.8RSA 非對稱加密
ES2564.1ECDSA 非對稱加密

詳細(xì)對比表格:

特性對比HS256RS256ES256
算法類型對稱加密非對稱加密非對稱加密
密鑰管理共享密鑰公鑰/私鑰公鑰/私鑰
簽名速度?? 1.2ms?? 3.8ms?? 4.1ms
驗證速度?? 最快?? 慢?? 最慢
安全性中等最高
適用場景內(nèi)部服務(wù)公開API金融級應(yīng)用

減少payload大小

# 不推薦 - payload過大
payload = {**user.__dict__, "iat": ..., "exp": ...}

# 推薦 - 只存儲必要信息
payload = {
    "sub": user.id,
    "role": user.role,
    "iat": ...,
    "exp": ...
}

異步簽名驗證

import asyncio
from jwt import PyJWT

async def async_verify(token: str):
    loop = asyncio.get_event_loop()
    return await loop.run_in_executor(
        None, 
        lambda: jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
    )

七、完整示例:FastAPI 實現(xiàn)

from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pydantic import BaseModel
import jwt
import datetime
from datetime import timezone
from typing import Optional

app = FastAPI()
security = HTTPBearer()

# 配置
SECRET_KEY = "your-secret-key-here"  # 生產(chǎn)環(huán)境應(yīng)從環(huán)境變量獲取
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE = datetime.timedelta(minutes=15)
REFRESH_TOKEN_EXPIRE = datetime.timedelta(days=7)

# 模擬數(shù)據(jù)庫
fake_users_db = {
    "johndoe": {
        "username": "johndoe",
        "password": "secret123",
        "role": "user"
    },
    "admin": {
        "username": "admin",
        "password": "admin123",
        "role": "admin"
    }
}

class Token(BaseModel):
    access_token: str
    refresh_token: str
    token_type: str

class User(BaseModel):
    username: str
    role: Optional[str] = None

def create_tokens(username: str):
    """創(chuàng)建access和refresh令牌對"""
    access_payload = {
        "sub": username,
        "role": fake_users_db[username]["role"],
        "type": "access",
        "exp": datetime.datetime.now(tz=timezone.utc) + ACCESS_TOKEN_EXPIRE
    }
    refresh_payload = {
        "sub": username,
        "type": "refresh",
        "exp": datetime.datetime.now(tz=timezone.utc) + REFRESH_TOKEN_EXPIRE
    }
    
    access_token = jwt.encode(access_payload, SECRET_KEY, algorithm=ALGORITHM)
    refresh_token = jwt.encode(refresh_payload, SECRET_KEY, algorithm=ALGORITHM)
    
    return {
        "access_token": access_token,
        "refresh_token": refresh_token,
        "token_type": "bearer"
    }

async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)):
    """依賴項:驗證JWT并返回當(dāng)前用戶"""
    token = credentials.credentials
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        if payload.get("type") != "access":
            raise HTTPException(status_code=400, detail="需要access token")
        username = payload.get("sub")
        if username not in fake_users_db:
            raise HTTPException(status_code=404, detail="用戶不存在")
        return User(username=username, role=payload.get("role"))
    except jwt.ExpiredSignatureError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Token已過期",
            headers={"WWW-Authenticate": "Bearer"}
        )
    except jwt.InvalidTokenError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="無效Token",
            headers={"WWW-Authenticate": "Bearer"}
        )

@app.post("/login")
async def login(username: str, password: str):
    """登錄接口"""
    if username not in fake_users_db or fake_users_db[username]["password"] != password:
        raise HTTPException(status_code=400, detail="用戶名或密碼錯誤")
    return create_tokens(username)

@app.post("/refresh")
async def refresh_token(refresh_token: str):
    """刷新access token"""
    try:
        payload = jwt.decode(refresh_token, SECRET_KEY, algorithms=[ALGORITHM])
        if payload.get("type") != "refresh":
            raise HTTPException(status_code=400, detail="需要refresh token")
        return create_tokens(payload.get("sub"))
    except jwt.PyJWTError as e:
        raise HTTPException(status_code=401, detail=str(e))

@app.get("/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
    """獲取當(dāng)前用戶信息"""
    return current_user

@app.get("/admin")
async def admin_route(current_user: User = Depends(get_current_user)):
    """管理員專屬路由"""
    if current_user.role != "admin":
        raise HTTPException(status_code=403, detail="無權(quán)訪問")
    return {"message": "歡迎管理員"}

結(jié)語

通過本文,你已經(jīng)掌握了:

  • JWT 的核心原理和結(jié)構(gòu)
  • Python 中生成和驗證 JWT 的完整方法
  • 各種高級應(yīng)用場景和安全實踐
  • 與流行框架的集成方式

記住這些黃金法則:

  • 最小化payload:只存儲必要信息
  • 保護密鑰:像保護銀行密碼一樣保護你的密鑰
  • 合理設(shè)置有效期:平衡安全性和用戶體驗
  • 考慮刷新機制:提升用戶體驗同時保持安全

現(xiàn)在,你已經(jīng)準(zhǔn)備好為你的 Python 應(yīng)用實現(xiàn)強大的 JWT 認(rèn)證系統(tǒng)了!

以上就是Python中JWT認(rèn)證的完整指南(從生成到驗證)的詳細(xì)內(nèi)容,更多關(guān)于Python JWT認(rèn)證指南的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Caffe均值文件mean.binaryproto轉(zhuǎn)mean.npy的方法

    Caffe均值文件mean.binaryproto轉(zhuǎn)mean.npy的方法

    今天小編就為大家分享一篇Caffe均值文件mean.binaryproto轉(zhuǎn)mean.npy的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-07-07
  • 詳解pandas apply 并行處理的幾種方法

    詳解pandas apply 并行處理的幾種方法

    這篇文章主要介紹了詳解pandas apply 并行處理的幾種方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • Django框架靜態(tài)文件使用/中間件/禁用ip功能實例詳解

    Django框架靜態(tài)文件使用/中間件/禁用ip功能實例詳解

    這篇文章主要介紹了Django框架靜態(tài)文件使用/中間件/禁用ip功能,結(jié)合實例形式詳細(xì)分析了Django框架靜態(tài)文件的使用、中間件的原理、操作方法以及禁用ip功能相關(guān)實現(xiàn)技巧,需要的朋友可以參考下
    2019-07-07
  • Python中*args與**kwargs的高級應(yīng)用指南

    Python中*args與**kwargs的高級應(yīng)用指南

    在Python編程中,*args和**kwargs是兩個非常強大的功能,它們允許開發(fā)者構(gòu)建更加靈活和可擴展的函數(shù),下面就跟隨小編一起來看看它的具體應(yīng)用吧
    2024-03-03
  • Python實現(xiàn)基于TCP UDP協(xié)議的IPv4 IPv6模式客戶端和服務(wù)端功能示例

    Python實現(xiàn)基于TCP UDP協(xié)議的IPv4 IPv6模式客戶端和服務(wù)端功能示例

    這篇文章主要介紹了Python實現(xiàn)基于TCP UDP協(xié)議的IPv4 IPv6模式客戶端和服務(wù)端功能,結(jié)合實例形式分析了Python基于TCP UDP協(xié)議的IPv4 IPv6模式客戶端和服務(wù)端數(shù)據(jù)發(fā)送與接收相關(guān)操作技巧,需要的朋友可以參考下
    2018-03-03
  • Django零基礎(chǔ)入門之靜態(tài)文件的引用

    Django零基礎(chǔ)入門之靜態(tài)文件的引用

    這篇文章主要介紹了Django零基礎(chǔ)入門之靜態(tài)文件的引用,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • Python json解析庫jsonpath原理及使用示例

    Python json解析庫jsonpath原理及使用示例

    這篇文章主要介紹了Python json解析庫jsonpath原理及使用示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-11-11
  • Python 的 vars() 函數(shù)功能

    Python 的 vars() 函數(shù)功能

    本文將深入探討如何利用 vars() 函數(shù)的靈活性和功能,以提高代碼調(diào)試的效率和準(zhǔn)確性,感興趣的朋友跟隨小編一起看看吧
    2024-06-06
  • Python中OpenCV?Tutorials?20??高動態(tài)范圍成像的實現(xiàn)步驟

    Python中OpenCV?Tutorials?20??高動態(tài)范圍成像的實現(xiàn)步驟

    這篇文章主要介紹了OpenCV?Tutorials?20?-?高動態(tài)范圍成像,本文還給大家展示了一種稱為曝光融合的替代方法,它可以產(chǎn)生低動態(tài)范圍的圖像,需要的朋友可以參考下
    2022-06-06
  • 淺談python中真正關(guān)閉socket的方法

    淺談python中真正關(guān)閉socket的方法

    今天小編就為大家分享一篇淺談python中真正關(guān)閉socket的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-12-12

最新評論

太湖县| 安陆市| 元江| 湘乡市| 浠水县| 云南省| 宁陕县| 扶风县| 盐边县| 通州市| 宣威市| 隆化县| 双桥区| 手游| 佛冈县| 延边| 贵溪市| 拜城县| 高碑店市| 荆门市| 当阳市| 运城市| 新蔡县| 华池县| 时尚| 东明县| 新化县| 大邑县| 茌平县| 贵港市| 临湘市| 仁化县| 安国市| 栾城县| 乐安县| 邳州市| 吉林省| 北宁市| 鹤庆县| 蒙阴县| 普兰县|