复用Azure身份提供者实现网站与API通信:如何规避重定向引发的CORS问题?
问题根源
当浏览器跨域调用API时,API的Azure AD认证模块检测到请求未携带有效凭证,直接重定向至login.microsoftonline.com。但该登录域名未配置允许网站源的CORS响应头,导致浏览器拦截重定向请求,触发CORS错误。新标签页访问API正常是因为浏览器携带了AD会话Cookie,而AJAX跨域请求默认不会携带第三方Cookie(受SameSite策略限制),因此API判定请求未认证。
配置调整步骤
1. 修改API的认证行为,禁止重定向
将API的auth_settings_v2中unauthenticated_action从RedirectToLoginPage改为Return401,这样API会返回401 Unauthorized而非重定向,让前端可以主动处理令牌获取逻辑:
resource "azurerm_linux_web_app" "this" { // ... 其他配置不变 auth_settings_v2 { auth_enabled = true require_authentication = true runtime_version = "~2" unauthenticated_action = "Return401" // 修改此处 default_provider = "azureactivedirectory" // ... 其他AD配置不变 } // ... 其他配置不变 }
2. 补充应用注册的权限配置,让网站能获取API的访问令牌
在azuread_application的required_resource_access中添加对自身API的权限,确保网站可以请求API的访问令牌:
resource "azuread_application" "api_registration" { // ... 其他配置不变 required_resource_access { resource_app_id = azuread_application.api_registration.client_id // 自身API的Client ID resource_access { id = random_uuid.widgets_scope_id.result // 对应之前定义的user_impersonation范围的ID type = "Scope" } } // ... 其他配置不变 }
3. 前端代码调整:携带访问令牌调用API
从网站的Azure AD认证模块中获取访问令牌(Access Token),并在API请求的Authorization头中携带:
// 示例:从Azure AD Auth模块获取令牌 const token = await window.msalInstance.acquireTokenSilent({ scopes: ["api://<API_CLIENT_ID>/user_impersonation"] }); // 调用API时携带令牌 fetch("https://api-***.azurewebsites.net/api/v1/***", { headers: { "Authorization": `Bearer ${token.accessToken}` } });
4. 可选:优化API的CORS配置(若需要携带凭证)
如果前端需要携带Cookie(不推荐,跨域场景下令牌更安全),可以在API的CORS配置中启用允许凭证:
resource "azurerm_linux_web_app" "this" { // ... 其他配置不变 site_config { cors { allowed_origins = ["https://webapp-***.azurewebsites.net"] allowed_credentials = true // 启用此选项 } } }
架构评估
当前复用同一应用注册的架构并非根本性缺陷,但更优实践是拆分两个应用注册:
- 一个作为客户端应用(网站):类型设为SPA/Public Client,负责用户登录和获取API令牌
- 一个作为资源服务器(API):类型设为Web API,定义权限范围并验证令牌
拆分后权限边界更清晰,便于后续扩展和安全管控。但当前复用配置通过上述调整也能正常工作。
内容的提问来源于stack exchange,提问作者poklaassen
相关产品推荐
相关产品推荐

