JWT原理 FastAPI Vue3极简实现JWT登录鉴权

JWT原理 FastAPI Vue3极简实现JWT登录鉴权

前言

前后端分离项目中,传统的Session登录需要服务端存储会话信息,存在服务器集群无法共享、扩展性差的问题。而JWT作为目前最主流的无状态登录鉴权方案,彻底解决了这个痛点。

本文分为三部分:零基础看懂JWT底层原理、FastAPI后端极简实现登录签发令牌、Vue3前端单文件对接登录鉴权,所有代码极致精简,无数据库、无冗余业务逻辑,纯核心功能方便新手快速理解原理。


一、JWT是什么?

JWT全称:JSON Web Token,是一种轻量级、无状态的令牌校验规范。

核心特点:服务端不需要存储任何用户登录信息,用户登录后拿到加密令牌,后续每次请求携带令牌,服务端仅通过校验令牌合法性,就能完成身份认证,完美适配分布式、微服务架构。

二、JWT令牌三段式结构

完整JWT格式:Header.Payload.Signature,三部分通过小数点分隔,前两段均为Base64编码字符串,并非加密。

1. Header 头部

  • 作用:声明令牌类型、加密算法

  • 默认配置:令牌类型为JWT,默认对称加密算法 HS256

  • 注意:公开可解码,禁止存放任何敏感数据

2. Payload 载荷

  • 作用:存放用户自定义信息、JWT标准内置字段(过期时间、签发人等)

  • 常用内置字段:exp令牌过期时间、sub用户唯一标识

  • 核心避坑:载荷仅Base64编码,可直接解码查看,严禁存放密码、手机号等隐私数据

3. Signature 签名

  • 作用:防止令牌被篡改,保障令牌安全

  • 生成逻辑:头部 + 载荷拼接后,使用服务端专属密钥加密生成签名

  • 校验逻辑:服务端接收Token后,本地重新计算签名,和原签名比对,不一致直接判定令牌非法


三、JWT完整登录鉴权流程

  1. 前端输入账号密码,提交登录请求

  2. 后端校验账号密码合法,生成JWT令牌返回前端

  3. 前端本地存储Token(localStorage)

  4. 后续所有需要权限的接口,请求头携带 Authorization: Bearer Token

  5. 后端统一拦截校验Token:判断是否过期、签名是否合法

  6. 校验通过放行接口,失败直接返回401无权限


四、JWT优缺点

✅ 优点

  • 无状态:服务端无需保存会话数据,天然支持集群部署

  • 跨域友好:适配前后端分离、小程序、APP、移动端

  • 减少查库:Token内自带用户基础信息,无需重复查询数据库

❌ 缺点

  • 令牌签发后无法主动作废,只能等待过期,无法实现强制下线

  • 无法中途修改用户信息,必须重新签发新Token


五、FastAPI 后端极简实现

5.1 安装依赖

bash 复制代码
pip install fastapi uvicorn python-jose[cryptography]

5.2 完整后端代码

无数据库、无复杂模型,仅两个接口:登录发Token、鉴权获取用户信息,适配前端直接联调

python 复制代码
from fastapi import FastAPI, Depends, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from jose import jwt
from datetime import datetime, timedelta

# 初始化项目
app = FastAPI(title="JWT极简登录演示")

# 全局跨域配置(解决前端联调跨域报错)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# JWT配置
SECRET_KEY = "demo-secret-key-2026"  # 线上需放入环境变量
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30  # token过期时间30分钟

# 模拟测试用户
fake_user = {"username": "admin", "password": "123456"}

# 统一Token校验依赖函数
def get_current_user(token: str):
    try:
        # 解码并自动校验过期时间、签名合法性
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username = payload.get("sub")
        if username is None:
            raise HTTPException(status_code=401, detail="令牌无效")
        return username
    except Exception:
        raise HTTPException(status_code=401, detail="令牌过期或非法")

# 1. 登录接口:账号密码校验,返回JWT
@app.post("/login")
def login(username: str, password: str):
    if username != fake_user["username"] or password != fake_user["password"]:
        raise HTTPException(status_code=401, detail="账号或密码错误")
    # 计算过期时间
    expire_time = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    # 生成JWT令牌
    token = jwt.encode({"sub": username, "exp": expire_time}, SECRET_KEY, algorithm=ALGORITHM)
    return {"access_token": token, "token_type": "bearer"}

# 2. 受保护接口:必须携带合法Token才可访问
@app.get("/user/info")
def user_info(username: str = Depends(get_current_user)):
    return {"code": 200, "username": username, "msg": "接口访问成功,Token校验通过"}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=8000)

5.3 后端测试方式

启动项目后,直接访问官方自动接口文档:http://127.0.0.1:8000/docs


六、Vue3 前端极简实现(单HTML文件,零工程依赖)

无需Vite、无需npm、无需构建工具,CDN直接引入Vue3,双击html即可打开运行,全程标准请求头携带Token,符合真实业务规范,修复之前url拼接token的不安全写法。

6.1 前端完整代码

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Vue3 + FastAPI JWT登录演示</title>
    <!-- CDN引入Vue3,零依赖开箱即用 -->
    <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
    <style>
        div{margin: 20px 0;}
        input{padding: 6px; margin: 8px 0; width: 200px;}
        button{padding: 6px 16px; cursor: pointer;}
    </style>
</head>
<body>
    <div id="app" style="padding: 40px;">
        <!-- 未登录:展示登录表单 -->
        <div v-if="!token">
            <h3>用户登录</h3>
            <input v-model="username" placeholder="用户名:admin"><br>
            <input v-model="password" placeholder="密码:123456" type="password"><br>
            <button @click="login">立即登录</button>
        </div>

        <!-- 已登录:展示功能按钮 -->
        <div v-else>
            <p>✅ 登录成功,本地Token:</p>
            <p style="word-break: break-all;">{{token}}</p>
            <button @click="getUserInfo">访问需要鉴权的接口</button>
            <p>接口返回数据:{{resData}}</p>
            <button @click="logout" style="margin-left: 10px;">退出登录</button>
        </div>
    </div>

    <script setup>
        const { ref } = Vue
        // 表单数据 & 本地token
        const username = ref('admin')
        const password = ref('123456')
        const token = ref(localStorage.getItem('token') || '')
        const resData = ref('')
        const baseUrl = 'http://127.0.0.1:8000'

        // 1. 登录:获取token并存入本地缓存
        const login = async () => {
            const res = await fetch(`${baseUrl}/login?username=${username.value}&password=${password.value}`,{
                method: 'POST'
            })
            const data = await res.json()
            if(res.ok){
                token.value = data.access_token
                localStorage.setItem('token', data.access_token)
                alert('登录成功!')
            }else{
                alert(data.detail)
            }
        }

        // 2. 请求受保护接口:请求头携带标准Bearer Token
        const getUserInfo = async () => {
            const res = await fetch(`${baseUrl}/user/info`,{
                method: 'GET',
                headers: {
                    // 行业标准鉴权头
                    'Authorization': `Bearer ${token.value}`
                }
            })
            resData.value = await res.json()
        }

        // 3. 退出登录:清空本地token
        const logout = () => {
            token.value = ''
            localStorage.removeItem('token')
        }
    </script>
</body>
</html>

七、前后端联调步骤

  1. 运行FastAPI后端代码,保持服务常驻,端口8000不变

  2. 直接双击前端html文件打开页面,无需启动任何前端服务

  3. 点击登录,后端生成Token自动存入浏览器本地存储

  4. 点击访问鉴权接口,前端自动在请求头带上Token,后端校验通过返回数据


八、核心代码关键点讲解

  1. exp过期字段:JWT原生自带过期校验,解码时自动判断是否过期,无需手写时间判断逻辑

  2. Bearer标准格式 :所有接口鉴权统一使用 Bearer 空格+token,贴合行业通用规范

  3. FastAPI依赖注入:Token校验逻辑统一封装,所有鉴权接口直接复用,代码解耦

  4. 本地存储:前端使用localStorage持久化Token,刷新页面无需重复登录


九、生产环境必须补充的优化点

  • 密钥禁止硬编码,通过环境变量配置读取

  • 用户密码禁止明文存储,后端使用bcrypt加盐加密

  • 增加刷新令牌refresh_token,避免用户频繁登录

  • 敏感接口缩短Token有效期,提升接口安全性

  • 增加全局请求拦截器,前端统一处理401无权限、自动跳转登录页


十、总结

  1. JWT核心精髓:无状态、三段结构、签名防篡改,适配前后端分离架构

  2. 本次前后端代码均做到极致精简,剔除所有无关业务代码,专注讲解JWT鉴权核心流程

  3. 完整流程:登录发证 - 前端存证 - 请求带证 - 后端验证,覆盖企业项目最基础的登录鉴权全链路