简介这份资源是面向高校计算机相关专业毕业设计的完整项目包主题为基于Python与Django的Web服务统一身份认证协议设计适合正在准备毕设或需要学习单点登录与身份认证实现的学生及开发者参考。项目采用B/S架构后端基于Django框架配合MySQL数据库完成数据持久化核心功能涵盖用户信息管理查看、修改、删除以及单点登录机制通过一次服务器认证即可访问相互信任的站点并按权限分配策略实现自动登录与差异化访问。压缩包共603个文件约8.34MB包含105个py源码文件、13个html页面、52个js脚本、21个css样式以及大量png、gif等界面素材另附数据库文件、说明文档与演示视频便于理解整体结构与运行流程。目前已有904人学习下载可作为毕设选题落地的参考方案帮助读者快速掌握统一身份认证系统的设计思路与关键实现细节。1. 从一份毕业设计压缩包说起Web 服务统一身份认证到底在解决什么你拿到手的这个(基于python的毕业设计)web服务统一身份认证协议设计(源码说明演示视频).zip名字很长但核心就一件事让多个 Web 服务共用一套登录态而不是每个子系统各存一份用户名密码。做过课程设计的人都懂教务系统、图书馆、选课平台各登一次密码还要求不一样这就是典型的身份孤岛。统一身份认证协议要做的是把「你是谁」这件事从各个业务系统里抽出来交给一个独立的认证中心业务系统只负责拿着令牌去问「这个人合法吗」。这个方向适合两类人一类是正在做计算机毕业设计、需要一套能跑起来、能讲清楚原理、还能录演示视频的完整方案另一类是想理解 SSO单点登录和令牌校验机制、但不想一上来就啃 CAS 或 OAuth2 全量规范的开发者。标题里的「协议设计」不是让你去发明新协议而是让你基于现有成熟协议常见做法是 OAuth2 的授权码模式或简化版 CAS做一套可落地的实现。Python 在这里的角色是认证中心服务端和客户端 SDK 的实现语言选它是因为生态里 Flask、requests、PyJWT 这些库足够把协议流程串起来代码量可控答辩时也讲得清。我见过太多毕业设计卡在「能演示但说不清协议流程」这一步。演示视频里点一下登录就跳转了老师问一句「令牌怎么防篡改」就答不上来。所以这篇笔记不按论文目录走而是按一个真实可复现的落地路径来拆先讲清协议选型和令牌设计再动手把认证中心、业务客户端、令牌校验三块跑通最后把踩过的坑和进阶验证方法摊开。你照着做至少能拿到一个能讲、能改、能扩展的工程骨架。2. 协议选型与令牌设计为什么不用 Session 共享而用令牌2.1 三种常见方案的取舍Session 共享、CAS、OAuth2 简化模式做 Web 服务统一身份认证绕不开的第一个决策就是「登录态存在哪、怎么传」。最省事的做法是 Session 共享把多个服务的 Session 存到同一个 Redis 里浏览器带着同一个 Cookie 就能识别。这个方案在单机或内网小规模场景下确实能用但它有两个硬伤一是跨域场景下 Cookie 的 SameSite 和 Domain 限制会让你反复翻车二是业务系统直接依赖 Session 存储认证中心和业务系统耦合太深扩展性差。毕业设计如果只做 Session 共享答辩时很难体现「协议设计」四个字。CASCentral Authentication Service是经典的单点登录协议流程清晰用户访问业务系统业务系统发现没登录就重定向到 CAS 服务端服务端认证后带 ticket 跳回业务系统拿 ticket 去服务端校验。它的优点是协议简单、票据一次性、安全性好缺点是移动端和前后端分离场景下重定向流程比较别扭而且 CAS 的 ticket 校验是服务端到服务端的同步调用高并发时认证中心压力集中。OAuth2 的授权码模式是当前更通用的选择虽然它本意是授权而非认证但加上openid或自定义用户信息接口后完全可以承担统一身份认证的职责。它的核心是业务系统引导用户到认证中心用户认证后认证中心返回授权码业务系统用授权码换令牌再用令牌获取用户信息。这个流程前后端分离友好令牌可以自包含JWT业务系统本地就能校验不必每次都回认证中心。对于毕业设计我一般建议选 OAuth2 授权码模式的简化版保留授权码换令牌的核心流程令牌用 JWT 自包含业务系统本地校验签名和过期时间。这样既体现了协议设计又不会因为引入完整 OAuth2 的刷新令牌、作用域、同意页而把代码量撑到失控。2.2 JWT 令牌的结构与签名参数怎么定选 JWT 作为令牌载体是因为它把用户标识、过期时间、签发者都编码进令牌本身业务系统不需要查库就能完成校验。一个典型的 JWT 由三部分组成Header、Payload、Signature用点号连接。Header 声明签名算法Payload 放声明claimsSignature 是对前两部分的签名。下面是一个用 Python 生成 JWT 的最小代码依赖PyJWT库import jwt import time # 签名密钥生产环境必须从环境变量读取不能硬编码 SECRET_KEY your-256-bit-secret-change-in-production # 签名算法HS256 是对称加密认证中心和业务系统共享密钥 ALGORITHM HS256 def create_token(user_id: str, username: str, expire_seconds: int 3600) - str: 生成 JWT 令牌 :param user_id: 用户唯一标识 :param username: 用户名用于业务系统展示 :param expire_seconds: 过期时间默认 1 小时 :return: 编码后的 JWT 字符串 now int(time.time()) payload { iss: auth-center, # 签发者业务系统可校验 sub: user_id, # 主题通常是用户 ID name: username, # 自定义声明用户展示名 iat: now, # 签发时间 exp: now expire_seconds, # 过期时间必须设置 jti: f{user_id}-{now} # 令牌唯一 ID可用于黑名单 } token jwt.encode(payload, SECRET_KEY, algorithmALGORITHM) return token def verify_token(token: str) - dict: 校验 JWT 令牌失败会抛异常 :param token: 待校验的令牌 :return: 解码后的 payload try: payload jwt.decode( token, SECRET_KEY, algorithms[ALGORITHM], issuerauth-center, # 校验签发者 options{require: [exp, sub, iss]} # 强制要求这些声明存在 ) return payload except jwt.ExpiredSignatureError: raise ValueError(令牌已过期) except jwt.InvalidTokenError as e: raise ValueError(f令牌无效: {e})这段代码里几个参数值得展开说。SECRET_KEY的长度和随机性直接决定签名强度HS256 要求密钥至少 256 位也就是 32 字节。很多毕业设计里直接写secret或者123456这在答辩时是明显的扣分点因为攻击者拿到密钥就能伪造任意用户令牌。exp过期时间必须设置不设过期时间的令牌一旦泄露就是永久后门。iss签发者声明用于业务系统确认令牌确实来自认证中心而不是其他服务签发的。jti是令牌唯一 ID如果你要做登出或强制下线就需要维护一个黑名单把未过期但已登出的jti记下来校验时额外查一次。提示HS256 是对称算法认证中心和所有业务系统共享同一个密钥。如果业务系统数量多、部署环境不可控建议换成 RS256 非对称算法认证中心用私钥签名业务系统用公钥验签私钥不出认证中心。2.3 授权码换令牌的完整时序与接口约定协议流程要落地必须把接口约定清楚。简化版 OAuth2 授权码模式涉及四个角色用户浏览器、业务系统客户端、认证中心、用户信息接口。核心时序是用户访问业务系统受保护页面业务系统发现无令牌重定向到认证中心授权页带上client_id和redirect_uri。用户在认证中心登录认证中心生成一次性授权码code重定向回redirect_uri?codexxx。业务系统后端拿code调用认证中心令牌接口换取access_token。业务系统用access_token调用用户信息接口拿到用户标识建立本地会话或直接返回给前端。接口约定用表格列清楚避免前后端联调时扯皮接口方法路径关键参数返回授权页GET/oauth/authorizeclient_id, redirect_uri, state重定向带 code令牌接口POST/oauth/tokencode, client_id, client_secretaccess_token, token_type, expires_in用户信息GET/oauth/userinfoAuthorization: Bearer tokenuser_id, username令牌校验POST/oauth/verifytokenvalid, payloadstate参数是防 CSRF 的关键业务系统生成随机字符串存在本地回调时比对不一致就拒绝。client_secret是业务系统的凭证必须后端保存绝不能出现在前端代码里。授权码code必须一次性使用用过即失效且有效期建议不超过 5 分钟。3. 用 Flask 把认证中心跑起来路由、授权码与令牌签发3.1 认证中心的最小工程结构与依赖认证中心是整个方案的核心它负责用户登录、授权码生成、令牌签发和用户信息提供。用 Flask 来实现是因为它轻量、路由清晰、和 PyJWT 配合简单。工程结构不需要复杂毕业设计阶段四个文件足够auth-center/ ├── app.py # 主应用路由和业务逻辑 ├── models.py # 用户模型和授权码存储 ├── config.py # 配置项密钥、过期时间 └── requirements.txt # 依赖清单依赖清单里核心是三个库Flask提供 Web 框架PyJWT负责令牌编解码flask-cors处理跨域前后端分离时业务系统域名和认证中心域名不同。安装命令pip install Flask PyJWT flask-corsconfig.py里把密钥、授权码有效期、令牌有效期集中管理避免散落在各处import os class Config: # 生产环境从环境变量读取开发环境给默认值 SECRET_KEY os.environ.get(AUTH_SECRET_KEY, dev-secret-key-32-bytes-long!!!) JWT_ALGORITHM HS256 # 授权码有效期单位秒 AUTH_CODE_EXPIRE 300 # 令牌有效期单位秒 TOKEN_EXPIRE 3600 # 允许的业务系统 client_id 和 secret 映射 CLIENTS { web-app-1: {secret: app1-secret, redirect_uris: [http://localhost:5001/callback]}, web-app-2: {secret: app2-secret, redirect_uris: [http://localhost:5002/callback]}, }CLIENTS字典模拟了业务系统注册表每个业务系统有独立的client_id和client_secret以及允许的回调地址白名单。回调地址白名单是防开放重定向的关键如果不对redirect_uri做校验攻击者可以构造恶意回调地址窃取授权码。3.2 授权码的生成、存储与一次性消费授权码是连接授权页和令牌接口的临时凭证它的安全性要求是随机、短有效期、一次性。用 Python 的secrets模块生成随机码比random模块更适合安全场景。import secrets import time from threading import Lock class AuthCodeStore: 授权码存储内存实现生产环境应换成 Redis def __init__(self, expire_seconds300): self._store {} # code - {user_id, client_id, expire_at} self._lock Lock() self._expire expire_seconds def generate(self, user_id: str, client_id: str) - str: 生成授权码并存储 code secrets.token_urlsafe(32) # 32 字节随机URL 安全 with self._lock: self._store[code] { user_id: user_id, client_id: client_id, expire_at: time.time() self._expire } return code def consume(self, code: str, client_id: str) - str: 消费授权码返回 user_id 一次性取出即删除校验 client_id 和过期时间 with self._lock: record self._store.pop(code, None) if record is None: raise ValueError(授权码不存在或已使用) if record[client_id] ! client_id: raise ValueError(授权码与客户端不匹配) if time.time() record[expire_at]: raise ValueError(授权码已过期) return record[user_id]secrets.token_urlsafe(32)生成的是 32 字节随机数的 URL 安全 Base64 编码长度约 43 个字符暴力猜测不可行。consume方法里pop操作保证了一次性无论后续校验是否通过授权码都已经被移除攻击者无法重放。client_id校验防止一个业务系统拿另一个业务系统的授权码去换令牌。过期时间校验放在最后是因为即使授权码泄露5 分钟后也自动失效。3.3 令牌接口与用户信息接口的实现令牌接口接收code、client_id、client_secret校验通过后签发 JWT。用户信息接口从Authorization头里取令牌校验后返回用户信息。from flask import Flask, request, jsonify, redirect from config import Config from models import AuthCodeStore, UserStore import jwt import time app Flask(__name__) app.config.from_object(Config) code_store AuthCodeStore(expire_secondsapp.config[AUTH_CODE_EXPIRE]) user_store UserStore() app.route(/oauth/token, methods[POST]) def token(): 授权码换令牌接口 data request.get_json() code data.get(code) client_id data.get(client_id) client_secret data.get(client_secret) # 校验客户端身份 client app.config[CLIENTS].get(client_id) if not client or client[secret] ! client_secret: return jsonify({error: invalid_client}), 401 # 消费授权码 try: user_id code_store.consume(code, client_id) except ValueError as e: return jsonify({error: str(e)}), 400 # 签发令牌 now int(time.time()) payload { iss: auth-center, sub: user_id, iat: now, exp: now app.config[TOKEN_EXPIRE], jti: f{user_id}-{now} } access_token jwt.encode(payload, app.config[SECRET_KEY], algorithmapp.config[JWT_ALGORITHM]) return jsonify({ access_token: access_token, token_type: Bearer, expires_in: app.config[TOKEN_EXPIRE] }) app.route(/oauth/userinfo, methods[GET]) def userinfo(): 用户信息接口从 Bearer 令牌中解析用户 auth_header request.headers.get(Authorization, ) if not auth_header.startswith(Bearer ): return jsonify({error: missing_token}), 401 token auth_header[7:] try: payload jwt.decode( token, app.config[SECRET_KEY], algorithms[app.config[JWT_ALGORITHM]], issuerauth-center ) except jwt.ExpiredSignatureError: return jsonify({error: token_expired}), 401 except jwt.InvalidTokenError: return jsonify({error: invalid_token}), 401 user user_store.get(payload[sub]) if not user: return jsonify({error: user_not_found}), 404 return jsonify({user_id: user[id], username: user[username]})令牌接口里客户端身份校验放在最前面避免无效请求消耗授权码。jwt.encode的 payload 里sub是用户 IDjti用于后续黑名单。用户信息接口的Authorization头格式必须是Bearer token解析时注意空格。jwt.decode的issuer参数会校验iss声明防止其他服务签发的令牌混入。注意内存存储的授权码和用户数据在服务重启后会丢失毕业设计演示时如果中途重启服务需要重新登录。生产环境或需要持久化的场景把AuthCodeStore换成 Redis 实现UserStore换成数据库查询。4. 业务系统接入客户端 SDK 与令牌本地校验4.1 业务系统如何发起授权跳转与处理回调业务系统接入统一身份认证核心是三件事未登录时跳转认证中心、处理回调拿令牌、本地校验令牌。用 Flask 写一个业务系统的最小实现from flask import Flask, request, redirect, session, jsonify import requests import jwt import secrets app Flask(__name__) app.secret_key business-app-session-secret AUTH_CENTER http://localhost:5000 CLIENT_ID web-app-1 CLIENT_SECRET app1-secret REDIRECT_URI http://localhost:5001/callback # 与认证中心共享的 JWT 密钥用于本地校验 JWT_SECRET dev-secret-key-32-bytes-long!!! JWT_ALGORITHM HS256 app.route(/protected) def protected(): 受保护页面未登录则跳转认证中心 token session.get(access_token) if not token: # 生成 state 防 CSRF state secrets.token_urlsafe(16) session[oauth_state] state auth_url ( f{AUTH_CENTER}/oauth/authorize f?client_id{CLIENT_ID} fredirect_uri{REDIRECT_URI} fstate{state} fresponse_typecode ) return redirect(auth_url) # 本地校验令牌 try: payload jwt.decode(token, JWT_SECRET, algorithms[JWT_ALGORITHM], issuerauth-center) return jsonify({message: 访问成功, user_id: payload[sub]}) except jwt.ExpiredSignatureError: session.pop(access_token, None) return redirect(/protected) except jwt.InvalidTokenError: return jsonify({error: invalid_token}), 401 app.route(/callback) def callback(): 认证中心回调用 code 换令牌 code request.args.get(code) state request.args.get(state) # 校验 state if not state or state ! session.pop(oauth_state, None): return jsonify({error: state_mismatch}), 400 # 用 code 换令牌 resp requests.post(f{AUTH_CENTER}/oauth/token, json{ code: code, client_id: CLIENT_ID, client_secret: CLIENT_SECRET }) if resp.status_code ! 200: return jsonify({error: token_exchange_failed}), 400 data resp.json() session[access_token] data[access_token] return redirect(/protected)/protected路由先检查 session 里有没有令牌没有就生成state并跳转。state存在 session 里回调时比对防止攻击者伪造回调请求。/callback路由拿到code后用requests.post调用认证中心令牌接口注意这里是后端到后端的调用client_secret不会暴露给浏览器。拿到令牌后存入 session重定向回受保护页面。4.2 本地校验与远程校验的边界什么时候必须回认证中心业务系统拿到 JWT 后有两种校验方式本地校验和远程校验。本地校验就是用共享密钥或公钥验证签名和过期时间不访问认证中心远程校验是调用认证中心的/oauth/verify接口。本地校验的优点是快、无网络开销适合高频接口。但它有两个边界一是无法感知令牌被提前吊销比如用户登出或管理员强制下线因为 JWT 自包含签发后到过期前一直有效二是如果密钥泄露所有业务系统都受影响。远程校验能解决吊销问题但每次请求都调认证中心认证中心会成为瓶颈。折中方案是本地校验为主维护一个短期的吊销黑名单比如 Redis 里存被吊销的jti过期时间与令牌一致本地校验通过后再查一次黑名单。黑名单查询是内存操作比远程调用轻量得多。import redis redis_client redis.Redis(hostlocalhost, port6379, db0) def is_token_revoked(jti: str) - bool: 检查令牌是否在黑名单中 return redis_client.exists(frevoked:{jti}) 1 def revoke_token(jti: str, expire_seconds: int): 将令牌加入黑名单过期时间与令牌剩余有效期一致 redis_client.setex(frevoked:{jti}, expire_seconds, 1)setex的过期时间很关键如果设得太长黑名单会无限增长设得太短令牌还没过期黑名单就失效了。正确做法是设为令牌的剩余有效期令牌自然过期后黑名单自动清理。4.3 多业务系统接入时的配置管理当业务系统从两个变成五个、十个配置管理就成了问题。每个业务系统都要配CLIENT_ID、CLIENT_SECRET、AUTH_CENTER地址、JWT_SECRET散落在各处的配置文件里改一个密钥要改所有系统。常见做法是抽一个共享的配置中心或环境变量模板。毕业设计阶段不需要上配置中心但至少要做到认证中心的CLIENTS注册表是唯一权威来源业务系统的client_secret从环境变量读取不写死在代码里。下面是一个环境变量模板# 业务系统环境变量 export AUTH_CENTER_URLhttp://localhost:5000 export OAUTH_CLIENT_IDweb-app-1 export OAUTH_CLIENT_SECRETapp1-secret export OAUTH_REDIRECT_URIhttp://localhost:5001/callback export JWT_SECRETdev-secret-key-32-bytes-long!!!业务系统代码里用os.environ.get读取本地开发用.env文件加载生产环境由部署平台注入。这样认证中心轮换密钥时只需要更新环境变量并重启业务系统不需要改代码。5. 避坑与排查授权码、令牌、跨域和时钟的五个血泪教训5.1 授权码被重复使用导致令牌重复签发现象同一个code连续调用两次/oauth/token两次都返回了有效的access_token。原因授权码存储用了字典查询但没有删除或者删除操作在异常分支里被跳过。有些实现先校验client_id和过期时间校验通过后才删除如果校验失败就不删除攻击者可以反复尝试。解决consume方法里用pop而不是get取出即删除无论后续校验是否通过都不再保留。校验顺序调整为先pop取出再校验client_id和过期时间校验失败直接抛异常授权码已经不在存储里了。5.2 令牌过期后业务系统陷入重定向循环现象令牌过期后业务系统跳转认证中心认证中心发现用户已登录直接回调业务系统拿到新令牌但页面还是提示未登录反复跳转。原因业务系统在/callback里把令牌存入了 session但/protected里校验令牌失败后只清除了 session 里的令牌没有清除认证中心的登录态。认证中心认为用户已登录直接签发新授权码但业务系统可能因为state不匹配或 session 写入失败而拿不到令牌。解决在/protected里校验失败时除了清除本地令牌还要跳转认证中心的登出接口或者带上promptlogin参数强制重新认证。更简单的做法是确保state生成和校验逻辑正确session 写入成功后再重定向。5.3 跨域场景下 Authorization 头丢失现象前后端分离时前端用fetch调用业务系统接口带上Authorization: Bearer xxx后端收不到这个头。原因跨域请求默认不发送自定义头浏览器会先发OPTIONS预检请求如果后端没有正确响应Access-Control-Allow-Headers实际请求就不会带上Authorization。解决后端 CORS 配置里明确允许Authorization头from flask_cors import CORS CORS(app, resources{r/api/*: {origins: [http://localhost:3000]}}, allow_headers[Content-Type, Authorization], methods[GET, POST, OPTIONS])allow_headers必须包含Authorizationorigins不要用*配合credentials否则浏览器会拒绝。5.4 服务器时钟偏差导致令牌校验失败现象认证中心签发的令牌在业务系统校验时报ImmatureSignatureError或ExpiredSignatureError但令牌明明刚签发。原因认证中心和业务系统部署在不同机器上时钟没有同步偏差超过令牌的iat和exp容差。解决部署时用 NTP 同步时钟。代码层面jwt.decode可以设置leeway参数容忍一定偏差jwt.decode(token, SECRET_KEY, algorithms[HS256], leeway10)leeway10表示允许 10 秒的时钟偏差。但这不是根治办法生产环境必须同步时钟。5.5 回调地址白名单校验不严导致开放重定向现象攻击者构造redirect_urihttp://evil.com/callback认证中心校验通过后把授权码发到了恶意站点。原因认证中心只校验了client_id存在没有校验redirect_uri是否在该客户端的白名单里。解决在授权页路由里取出client_id对应的redirect_uris列表精确匹配redirect_uri不匹配就拒绝。不要用startswith做前缀匹配因为http://localhost:5001.evil.com会绕过http://localhost:5001的前缀检查。精确匹配或解析 URL 后比对 host 和 path。6. 进阶验证用脚本模拟攻击面确认协议真的扛得住6.1 写一个令牌篡改检测脚本协议设计得再好不验证就是纸上谈兵。我一般会写一个小脚本模拟几种常见攻击看认证中心能不能挡住。第一种是篡改令牌 payload把sub改成别的用户 ID看签名校验是否失败。import jwt import requests AUTH_CENTER http://localhost:5000 SECRET_KEY dev-secret-key-32-bytes-long!!! def test_tampered_token(): 篡改 payload 后签名失效应被拒绝 # 用错误密钥签发一个令牌 fake_token jwt.encode( {iss: auth-center, sub: admin, exp: 9999999999}, wrong-secret, algorithmHS256 ) resp requests.get( f{AUTH_CENTER}/oauth/userinfo, headers{Authorization: fBearer {fake_token}} ) assert resp.status_code 401, f篡改令牌未被拒绝: {resp.status_code} print(篡改令牌检测通过) def test_expired_token(): 过期令牌应被拒绝 import time expired_token jwt.encode( {iss: auth-center, sub: user1, exp: int(time.time()) - 100}, SECRET_KEY, algorithmHS256 ) resp requests.get( f{AUTH_CENTER}/oauth/userinfo, headers{Authorization: fBearer {expired_token}} ) assert resp.status_code 401, f过期令牌未被拒绝: {resp.status_code} print(过期令牌检测通过) def test_reused_code(): 授权码重复使用应失败 # 先正常获取一个 code需要模拟登录流程这里省略 # 然后连续两次调用 token 接口 pass if __name__ __main__: test_tampered_token() test_expired_token()test_tampered_token用错误密钥签发令牌认证中心用正确密钥校验签名不匹配返回 401。test_expired_token签发一个exp在过去的令牌校验时抛ExpiredSignatureError返回 401。这两个测试跑通说明签名和过期校验生效。6.2 授权码一次性与 state 防 CSRF 的验证方法授权码一次性验证需要模拟完整流程先登录拿到code然后用同一个code调两次令牌接口第二次应该失败。state防 CSRF 验证是构造一个不带state或state不匹配的回调请求业务系统应该拒绝。def test_code_single_use(): 授权码只能用一次 # 假设已经通过登录流程拿到了 code code test-code-from-login # 第一次换令牌 resp1 requests.post(f{AUTH_CENTER}/oauth/token, json{ code: code, client_id: web-app-1, client_secret: app1-secret }) # 第二次换令牌应该失败 resp2 requests.post(f{AUTH_CENTER}/oauth/token, json{ code: code, client_id: web-app-1, client_secret: app1-secret }) assert resp1.status_code 200, 首次换令牌失败 assert resp2.status_code 400, 授权码被重复使用 print(授权码一次性检测通过)这个测试的关键是resp2必须返回 400如果返回 200 说明授权码没有被正确消费。state验证在业务系统的/callback里构造一个state不匹配的请求应该返回 400。6.3 压测令牌接口看认证中心瓶颈在哪毕业设计答辩时老师可能会问「并发怎么样」你可以用locust或简单的ab命令压一下令牌接口。但令牌接口依赖授权码不能直接压所以压测对象选用户信息接口或令牌校验接口。# 用 ab 压测用户信息接口100 并发1000 次请求 ab -n 1000 -c 100 -H Authorization: Bearer valid-token http://localhost:5000/oauth/userinfo关注两个指标Requests per second和Time per request。如果 QPS 上不去检查是不是每次请求都在查数据库或做复杂计算。用户信息接口应该只做 JWT 解码和一次用户查询如果用户查询是瓶颈加缓存。认证中心的令牌签发接口因为涉及授权码消费和 JWT 编码QPS 会低一些但毕业设计场景下通常够用。我自己的习惯是每做完一个认证流程先跑一遍篡改和过期测试再跑一次授权码一次性测试最后压一下用户信息接口。这三步走完协议的基本安全性就有底了。希望帮到你。本文还有配套的精品资源点击获取