0

0

如何在 Azure 函数中复用传入的 AAD 用户令牌访问受保护资源

霞舞

霞舞

发布时间:2026-03-17 14:56:06

|

466人浏览过

|

来源于php中文网

原创

如何在 Azure 函数中复用传入的 AAD 用户令牌访问受保护资源

本文详解如何在启用了 App Service 身份验证(AAD)的 Azure Linux 函数中,安全提取并复用前端(如静态 Web 应用)传递的 Bearer Token,构造 AuthorizationCodeCredential 或 ClientSecretCredential,从而以当前用户身份访问 Blob 存储等 Azure 资源,绕过 DefaultAzureCredential 在无托管身份环境下的失效问题。

本文详解如何在启用了 app service 身份验证(aad)的 azure linux 函数中,安全提取并复用前端(如静态 web 应用)传递的 bearer token,构造 `authorizationcodecredential` 或 `clientsecretcredential`,从而以当前用户身份访问 blob 存储等 azure 资源,绕过 `defaultazurecredential` 在无托管身份环境下的失效问题。

在 Azure Functions 中启用 App Service 身份验证(AAD)后,请求头中的 Authorization: Bearer <token> 会被自动解析,并通过 req.user 暴露用户声明(claims),但该 token 不会被 DefaultAzureCredential 自动识别或复用——因为 DefaultAzureCredential 仅尝试从环境变量、托管身份、Azure CLI 等后端可信源获取凭据,而不解析 HTTP 请求上下文中的用户令牌。因此,直接使用 new DefaultAzureCredential() 会抛出 CredentialUnavailableError: EnvironmentCredential is unavailable 错误。

要实现“以调用用户身份访问 Azure 资源”,核心思路是:将 req.headers.authorization 中的 Bearer Token 提取出来,结合 Azure AD 应用配置,构造一个能代表该用户的 TokenCredential 实例。推荐方案如下:

✅ 推荐方案:使用 ClientSecretCredential + 用户 Token(适用于服务到服务委托)

若你的函数应用已注册为 Azure AD 应用(建议启用 User.Read、Storage Blob Data Contributor 等委派权限),且你拥有该应用的 client_id、tenant_id 和 client_secret,可利用用户提供的 token 作为 authority 的上下文,配合 ClientSecretCredential 实现基于用户上下文的令牌交换(On-Behalf-Of 流)。但注意:JS SDK 当前(v3.x)原生不支持 OBO 流;更稳妥、广泛支持的方式是:

Picsart AI Image Generator
Picsart AI Image Generator

Picsart推出的AI图片生成器

下载

✅ 实用方案:提取并复用原始 Bearer Token(零额外鉴权开销)

由于 req.user 已证明认证成功,且你持有有效的 AAD 访问令牌(即 req.headers.authorization.split(' ')[1]),可直接将其封装为自定义 TokenCredential,供 Azure SDK 使用:

import { TokenCredential, AccessToken } from "@azure/identity";
import { BlobServiceClient } from "@azure/storage-blob";

// 自定义凭证:直接返回传入的用户访问令牌
class UserTokenCredential implements TokenCredential {
  private readonly token: string;

  constructor(token: string) {
    this.token = token;
  }

  async getToken(_: string[]): Promise<AccessToken | null> {
    return {
      token: this.token,
      expiresOnTimestamp: Date.now() + 3600 * 1000 // 安全起见,按典型 1h 过期设置(实际应解析 JWT exp 字段)
    };
  }
}

// 在函数主逻辑中使用
const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
  const authHeader = req.headers?.authorization;
  if (!authHeader || !authHeader.startsWith("Bearer ")) {
    context.res = { status: 401, body: "Unauthorized: Missing Bearer token" };
    return;
  }

  const userToken = authHeader.split(" ")[1];

  try {
    const credential = new UserTokenCredential(userToken);
    const blobServiceClient = new BlobServiceClient(
      `https://${accountName}.blob.core.windows.net`,
      credential
    );

    const containerClient = blobServiceClient.getContainerClient(containerName);
    const blobClient = containerClient.getBlobClient(blobName);
    const downloadResponse = await blobClient.download();

    // 处理流数据...
    const downloadedContent = await streamToBuffer(downloadResponse.readableStreamBody);

    context.res = { status: 200, body: { content: downloadedContent.toString() } };
  } catch (err) {
    context.log.error("Blob access failed:", err);
    context.res = { status: 500, body: "Failed to access storage" };
  }
};

// 辅助函数:流转 Buffer
async function streamToBuffer(readableStream: NodeJS.ReadableStream | undefined): Promise<Buffer> {
  if (!readableStream) throw new Error("ReadableStream is null");
  return new Promise((resolve, reject) => {
    const chunks: Uint8Array[] = [];
    readableStream.on("data", (data) => chunks.push(data));
    readableStream.on("end", () => resolve(Buffer.concat(chunks)));
    readableStream.on("error", reject);
  });
}

export default httpTrigger;

⚠️ 关键注意事项

  • 权限配置必须匹配:确保用于签发用户 token 的 Azure AD 应用(即你的静态 Web 应用所用的注册应用)已在目标存储账户上授予 Storage Blob Data Reader/Contributor 等 RBAC 角色,在 Storage 账户的 Access Control (IAM) 中为该应用的服务主体(而非用户)分配角色(推荐后者,更可控)。
  • Token 有效性校验:生产环境应解析 JWT(如使用 jsonwebtoken 库)验证 aud(受众是否为你的函数或目标资源)、iss(签发者)、exp(过期时间),避免凭据滥用。
  • 不要硬编码密钥:client_secret 等敏感信息务必存于 Function App 的 Application Settings(环境变量)中,通过 process.env.CLIENT_SECRET 读取。
  • 替代方案说明:若需更高安全性与标准协议支持,可考虑在函数中部署 Microsoft.Identity.Web 的轻量版中间件(Node.js 生态支持有限),或改用 Azure API Management 作为认证网关统一处理令牌委派。

✅ 总结

DefaultAzureCredential 不适用于解析 HTTP 请求中的用户令牌场景。正确路径是:显式提取 Authorization 头中的 Bearer Token → 封装为 TokenCredential → 传入 Azure SDK 客户端。该方法零依赖外部凭据源,完全复用已有认证链,既简洁又符合最小权限原则。只需确保后端资源(如 Blob 存储)已为对应 AAD 应用或用户组配置了正确的 RBAC 权限,即可实现安全、可审计的用户级资源访问。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
什么是中间件
什么是中间件

中间件是一种软件组件,充当不兼容组件之间的桥梁,提供额外服务,例如集成异构系统、提供常用服务、提高应用程序性能,以及简化应用程序开发。想了解更多中间件的相关内容,可以阅读本专题下面的文章。

184

2024.05.11

Golang 中间件开发与微服务架构
Golang 中间件开发与微服务架构

本专题系统讲解 Golang 在微服务架构中的中间件开发,包括日志处理、限流与熔断、认证与授权、服务监控、API 网关设计等常见中间件功能的实现。通过实战项目,帮助开发者理解如何使用 Go 编写高效、可扩展的中间件组件,并在微服务环境中进行灵活部署与管理。

226

2025.12.18

登录token无效
登录token无效

登录token无效解决方法:1、检查token的有效期限,如果token已经过期,需要重新获取一个新的token;2、检查token的签名,如果签名不正确,需要重新获取一个新的token;3、检查密钥的正确性,如果密钥不正确,需要重新获取一个新的token;4、使用HTTPS协议传输token,建议使用HTTPS协议进行传输 ;5、使用双因素认证,双因素认证可以提高账户的安全性。

6684

2023.09.14

登录token无效怎么办
登录token无效怎么办

登录token无效的解决办法有检查Token是否过期、检查Token是否正确、检查Token是否被篡改、检查Token是否与用户匹配、清除缓存或Cookie、检查网络连接和服务器状态、重新登录或请求新的Token、联系技术支持或开发人员等。本专题为大家提供token相关的文章、下载、课程内容,供大家免费下载体验。

846

2023.09.14

token怎么获取
token怎么获取

获取token值的方法:1、小程序调用“wx.login()”获取 临时登录凭证code,并回传到开发者服务器;2、开发者服务器以code换取,用户唯一标识openid和会话密钥“session_key”。想了解更详细的内容,可以阅读本专题下面的文章。

1112

2023.12.21

token什么意思
token什么意思

token是一种用于表示用户权限、记录交易信息、支付虚拟货币的数字货币。可以用来在特定的网络上进行交易,用来购买或出售特定的虚拟货币,也可以用来支付特定的服务费用。想了解更多token什么意思的相关内容可以访问本专题下面的文章。

2251

2024.03.01

js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

532

2023.06.20

js获取当前时间
js获取当前时间

JS全称JavaScript,是一种具有函数优先的轻量级,解释型或即时编译型的编程语言;它是一种属于网络的高级脚本语言,主要用于Web,常用来为网页添加各式各样的动态功能。js怎么获取当前时间呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

576

2023.07.28

抖漫入口地址合集
抖漫入口地址合集

本专题整合了抖漫入口地址相关合集,阅读专题下面的文章了解更多详细地址。

12

2026.03.17

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号