title: API安全大揭秘:认证与授权的双面舞会

date: 2025/05/28 12:14:35

updated: 2025/05/28 12:14:35

author: cmdragon

excerpt:

API安全的核心需求包括认证与授权机制。认证验证用户身份,如用户名密码登录;授权验证用户是否有权限执行特定操作,如管理员删除数据。典型安全威胁包括未授权访问、凭证泄露和权限提升。FastAPI通过OpenAPI规范支持OAuth2、HTTP Basic等安全方案,依赖注入系统实现灵活验证。OAuth2协议通过授权请求、授权许可、访问令牌等步骤确保安全访问。FastAPI实现OAuth2密码流程示例包括环境准备、核心代码实现和运行测试,确保用户身份验证和权限控制。

categories:

  • 后端开发
  • FastAPI

tags:

  • API安全
  • 认证与授权
  • OAuth2协议
  • FastAPI
  • 安全威胁
  • 依赖注入
  • 访问令牌


扫描二维码

关注或者微信搜一搜:编程智域 前端至全栈交流与成长

探索数千个预构建的 AI 应用,开启你的下一个伟大创意https://tools.cmdragon.cn/

第一章:理解API安全的基本需求

为什么需要认证与授权机制

认证(Authentication)与授权(Authorization)的区别

  • 认证:验证用户身份的过程(例如:用户名密码登录)。

    类比:进入公司大楼时出示工牌(证明你是员工)

  • 授权:验证用户是否有权限执行特定操作(例如:管理员删除数据)。

    类比:不同工牌对应不同的门禁权限(普通员工不能进入机房)

典型安全威胁场景

  1. 未授权访问:攻击者直接调用/admin/delete-data接口删除数据
  2. 凭证泄露:用户密码在传输过程中被窃取
  3. 权限提升:普通用户越权访问管理员接口

FastAPI的安全设计原则

  • 内置支持OpenAPI规范的安全方案(OAuth2、HTTP Basic等)
  • 通过依赖注入系统实现灵活的安全验证逻辑
  • 自动生成交互式API文档中的安全测试界面

OAuth2协议在Web服务中的应用场景

OAuth2核心概念图解

+--------+                               +---------------+
| |--(A) 授权请求 ->---------------| 资源所有者 |
| | | (用户) |
| |<-(B) 授权许可 ----------------| |
| | +---------------+
| |
| | +---------------+
| |--(C) 授权许可 ->---------------| 授权服务器 |
| 客户端 | | (签发令牌) |
| |<-(D) 访问令牌 ----------------| |
| | +---------------+
| |
| | +---------------+
| |--(E) 访问令牌 ->---------------| 资源服务器 |
| | | (存储数据) |
| |<-(F) 受保护资源 --------------| |
+--------+ +---------------+

FastAPI实现OAuth2密码流程示例

环境准备

# 安装依赖库(指定版本保证兼容性)
pip install fastapi==0.68.0 uvicorn==0.15.0
pip install python-jose[cryptography]==3.3.0
pip install passlib[bcrypt]==1.7.4

核心代码实现

from fastapi import Depends, FastAPI, HTTPException
from fastapi.security import OAuth2PasswordBearer
from jose import JWTError, jwt
from passlib.context import CryptContext
from pydantic import BaseModel
from datetime import datetime, timedelta # 安全配置常量
SECRET_KEY = "your-secret-key-here"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30 # 密码加密上下文
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") # OAuth2方案声明
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") # 用户数据模型
class User(BaseModel):
username: str
disabled: bool = False class UserInDB(User):
hashed_password: str # 令牌生成函数
def create_access_token(data: dict):
to_encode = data.copy()
expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) # 认证依赖项
async def get_current_user(token: str = Depends(oauth2_scheme)):
credential_exception = HTTPException(
status_code=401,
detail="无法验证凭证",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credential_exception
except JWTError:
raise credential_exception # 实际项目应查询数据库
user = UserInDB(
username=username,
hashed_password="fakehash",
disabled=False
)
if user.disabled:
raise HTTPException(status_code=400, detail="用户已被禁用")
return user app = FastAPI() @app.post("/token")
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
# 验证用户名密码(示例硬编码)
if form_data.username != "testuser" or form_data.password != "testpass":
raise HTTPException(
status_code=401,
detail="用户名或密码错误",
headers={"WWW-Authenticate": "Bearer"},
) access_token = create_access_token(
data={"sub": form_data.username}
)
return {"access_token": access_token, "token_type": "bearer"} @app.get("/protected/")
async def read_protected_route(current_user: User = Depends(get_current_user)):
return {"message": "已授权访问", "user": current_user.username}

运行与测试

uvicorn main:app --reload

打开浏览器访问 http://localhost:8000/docs,在Swagger界面中:

  1. 点击 /token 端点,输入测试凭证(username: testuser, password: testpass)
  2. 复制返回的access_token
  3. 点击 /protected/ 端点,在Authorization弹窗中输入 Bearer <your-token>

课后Quiz

Q1:认证与授权的根本区别是什么?

A) 认证确认身份,授权验证权限

B) 授权在前,认证在后

C) 两者是同义词

点击查看答案

正确答案:A
解析:认证是验证用户身份的过程(如登录),授权是验证该身份是否有权限执行特定操作(如访问管理员接口)。

Q2:OAuth2的授权码流程包含哪些主要步骤?

A) 客户端直接获取访问令牌

B) 用户授权 → 获取授权码 → 交换访问令牌

C) 用户名密码直接传递给资源服务器

点击查看答案

正确答案:B
解析:完整的授权码流程需要通过授权服务器中转授权码,避免客户端直接接触用户凭证。


常见报错解决方案

报错:422 Unprocessable Entity

{
"detail": [
{
"loc": [
"body",
"password"
],
"msg": "field required",
"type": "value_error.missing"
}
]
}

原因分析

  • 请求体缺少必填字段(如password字段)
  • 字段数据类型不匹配(例如数字传入了字符串)

解决方法

  1. 检查Swagger文档中的请求体模型
  2. 使用Postman验证请求体格式:
{
"username": "testuser",
"password": "testpass"
}
  1. 在Pydantic模型中使用...表示必填字段:
class LoginRequest(BaseModel):
username: str
password: str # 必填字段

预防建议

  • 启用Pydantic的严格模式:
from pydantic import StrictStr

class LoginRequest(BaseModel):
username: StrictStr
password: StrictStr
  • 在路由中使用response_model_exclude_unset=True过滤未设置字段

余下文章内容请点击跳转至 个人博客页面 或者 扫码关注或者微信搜一搜:编程智域 前端至全栈交流与成长,阅读完整的文章:API安全大揭秘:认证与授权的双面舞会 | cmdragon's Blog

往期文章归档:

API安全大揭秘:认证与授权的双面舞会的更多相关文章

  1. API代理网关和OAuth2.0授权认证框架

    API代理网关和OAuth2.0授权认证框架 https://www.cnblogs.com/bluedoctor/p/8967951.html 1,授权认证与微服务架构 1.1,由不同团队合作引发的 ...

  2. Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权(二)

    上文已经介绍了Identity Service的实现过程.今天我们继续,实现一个简单的Weather API和一个基于Ocelot的API网关. 回顾 <Angular SPA基于Ocelot ...

  3. 【高德地图API】汇润做爱地图技术大揭秘

    原文:[高德地图API]汇润做爱地图技术大揭秘 昨日收到了高德地图微信公众号的消息推送,说有[一大波免费情趣用品正在袭来],点进去看了一眼,说一个电商公司(估计是卖情趣用品的)用高德云图制作了一张可以 ...

  4. 【高德地图API】从零开始学高德JS API(七)——定位方式大揭秘

    原文:[高德地图API]从零开始学高德JS API(七)——定位方式大揭秘 摘要:关于定位,分为GPS定位和网络定位2种.GPS定位,精度较高,可达到10米,但室内不可用,且超级费电.网络定位,分为w ...

  5. 【从零开始搭建自己的.NET Core Api框架】(七)授权认证进阶篇

    系列目录 一.  创建项目并集成swagger 1.1 创建 1.2 完善 二. 搭建项目整体架构 三. 集成轻量级ORM框架——SqlSugar 3.1 搭建环境 3.2 实战篇:利用SqlSuga ...

  6. Web Api 2 认证与授权 2

    HTTP Message Handler 在 Web Api 2 认证与授权 中讲解了几种实现机制,本篇就详细讲解 Message Handler 的实现方式 关于 Message Handler 在 ...

  7. 关于 Web Api 2 认证与授权

    认证与授权 认证与授权,Authentication and Authorize,这个是两个不同的事.认证是对访问身份进行确认,如验证用户名和密码,而授权是在认证之后,判断是否具有权限进行某操作,如 ...

  8. .Netcore 2.0 Ocelot Api网关教程(5)- 认证和授权

    本文介绍Ocelot中的认证和授权(通过IdentityServer4),本文只使用最简单的IdentityServer,不会对IdentityServer4进行过多讲解. 1.Identity Se ...

  9. Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权(四)

    在上一讲中,我们已经完成了一个完整的案例,在这个案例中,我们可以通过Angular单页面应用(SPA)进行登录,然后通过后端的Ocelot API网关整合IdentityServer4完成身份认证.在 ...

  10. Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权(一)

    好吧,这个题目我也想了很久,不知道如何用最简单的几个字来概括这篇文章,原本打算取名<Angular单页面应用基于Ocelot API网关与IdentityServer4+ASP.NET Iden ...

随机推荐

  1. windows 配置java发布环境

    一.jdk安装 1.下载jdk安装文件 2.在"系统变量"下"新建"选项"JAVA_HOME"值为:"jdk"文件夹路径 ...

  2. python面向对象-我敢站在世界巅峰保证:这里可以找到几乎百分之九十python面向对象的内容(面向对象三大特性、成员、组合、特殊成员、反射、类的约束、自定义异常、多继承之C3算法)

    概要: 面向对象 2 面向对象 Java语言:只支持面向对象方式 python语言: 面向过程[不推荐] 函数式[推荐] 面向对象[比较推荐]了解.能看懂.看源码 函数式编程:代码重用性.可读性较好 ...

  3. 【Python】函数传参的方式

    学习笔记//20230402 edit 1.传参类型 值传递 引用传递 就像C++的参数传递: 值传递时值把实参的值传递给function, function 内对形参的修改不会影响实参; 引用传递时 ...

  4. stat() "/root/xxx/index.html" failed (13: Permission denied)

    前言 在 nginx 上部署静态网页报502,于是查看 nginx 错误日志 error_log /var/log/nginx/error.log;,却没有看到任何错误信息:访问 nginx活动日志 ...

  5. Pydantic配置继承抽象基类模式

    title: Pydantic配置继承抽象基类模式 date: 2025/3/21 updated: 2025/3/21 author: cmdragon excerpt: Pydantic模型配置系 ...

  6. 【JDBC】总结

    JDBC核心技术 第1章:JDBC概述 1.1 数据的持久化 持久化(persistence):把数据保存到可掉电式存储设备中以供之后使用.大多数情况下,特别是企业级应用,数据持久化意味着将内存中的数 ...

  7. lombok用法

    加入 maven 依赖 <dependency> <groupId>org.projectlombok</groupId> <artifactId>lo ...

  8. 多线程的waiting与notify

    一.waiting()与notify() /* 进入到TimeWaiting(计时等待)有两种方式 1.使用sleep(long m)方法,在毫秒值结束之后,线程睡醒进入到Runnable/Block ...

  9. jmeter结果断言的几种方法

    这篇文章里,我们已经知道了怎样实用json断言(https://www.cnblogs.com/becks/p/14951725.html) 接下来还有几种断言,一一介绍 一.响应断言,这种断言的逻辑 ...

  10. Linux系统搭建单机MySQL8.0.26版本

    概述 本文主要是写Ubuntu22.04搭建MySQL8.0.26版本 环境信息 IP 系统 规格 10.0.0.10 Ubuntu22.04 2c4g 数据库服务安装步骤 下载前置依赖 # 下载li ...