如何为ASP.NET Core添加多认证?解决API外部调用无用户输入问题
实现无用户交互的API调用解决方案
你的问题根源在于当前配置的OpenID Connect用户认证是面向用户交互场景的,当匿名请求触发认证逻辑时会重定向到Azure AD登录页,而Postman这类无浏览器客户端无法处理这种跳转。下面是几种可行的解决方案,按推荐优先级排序:
一、Azure AD客户端凭据(服务账号)认证(推荐生产环境使用)
这是Azure生态中标准的服务对服务调用方式,无需用户参与:
1. Azure AD侧配置
- 给你的API注册Azure AD应用,设置应用ID URI(例如
api://your-api-client-id) - 添加应用权限(选择
Application类型,而非Delegated),并完成管理员同意 - 注册一个服务账号(独立Azure AD应用),生成客户端密钥或证书,用于获取令牌
2. 修改Startup.cs的认证配置
保留原有用户认证逻辑的同时,添加Bearer认证以支持服务令牌验证:
services.AddAuthentication() // 保留原有的用户认证(用于Swagger/用户交互场景) .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => { options.Cookie.Path = Configuration["SiteConfiguration:BasePath"]; options.Cookie.Domain = Configuration["SiteConfiguration:Domain"]; }) .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"), OpenIdConnectDefaults.AuthenticationScheme, "V3Cookie") // 新增服务对服务的Bearer认证 .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd")); // 配置授权策略,允许两种认证方式 services.AddAuthorization(options => { options.DefaultPolicy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .AddAuthenticationSchemes( CookieAuthenticationDefaults.AuthenticationScheme, JwtBearerDefaults.AuthenticationScheme) .Build(); });
3. 配置appsettings.json的Azure AD参数
确保AzureAd节点包含以下内容:
"AzureAd": { "Instance": "https://login.microsoftonline.com/", "TenantId": "你的租户ID", "ClientId": "API的Azure AD应用ID", "Audience": "api://你的API应用ID" // 和之前设置的应用ID URI一致 }
4. Postman调用步骤
- 先获取令牌:向
https://login.microsoftonline.com/{租户ID}/oauth2/v2.0/token发送POST请求,参数:grant_type:client_credentialsclient_id: 服务账号的应用IDclient_secret: 服务账号的客户端密钥scope:api://你的API应用ID/.default
- 调用API时,在请求头添加
Authorization: Bearer {获取到的令牌}
二、API密钥认证(快速临时方案)
如果不需要Azure AD的复杂配置,可以快速实现密钥验证:
1. 自定义API密钥认证逻辑
在Startup.cs中添加:
// 注册API密钥认证方案 services.AddAuthentication("ApiKey") .AddScheme<ApiKeyAuthOptions, ApiKeyAuthHandler>("ApiKey", options => { options.ValidApiKey = Configuration["ApiSettings:ValidKey"]; }); // 配置授权策略,支持多种认证方式 services.AddAuthorization(options => { options.DefaultPolicy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .AddAuthenticationSchemes( CookieAuthenticationDefaults.AuthenticationScheme, "ApiKey") .Build(); }); // 自定义认证选项和处理器 public class ApiKeyAuthOptions : AuthenticationSchemeOptions { public string ValidApiKey { get; set; } } public class ApiKeyAuthHandler : AuthenticationHandler<ApiKeyAuthOptions> { public ApiKeyAuthHandler(IOptionsMonitor<ApiKeyAuthOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) { } protected override Task<AuthenticateResult> HandleAuthenticateAsync() { if (!Request.Headers.TryGetValue("X-Api-Key", out var headerValues)) return Task.FromResult(AuthenticateResult.NoResult()); var providedKey = headerValues.FirstOrDefault(); if (providedKey != Options.ValidApiKey) return Task.FromResult(AuthenticateResult.Fail("无效的API密钥")); var identity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, "服务账号") }, Scheme.Name); var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), Scheme.Name); return Task.FromResult(AuthenticateResult.Success(ticket)); } }
2. 配置API密钥
在appsettings.json中添加:
"ApiSettings": { "ValidKey": "生成一个随机的复杂密钥" }
3. Postman调用
在请求头添加X-Api-Key: 你的密钥即可调用API
三、临时关闭特定接口认证(仅测试用)
如果只是临时测试,可以给目标接口添加[AllowAnonymous]属性,跳过认证重定向:
[AllowAnonymous] [HttpGet("your-endpoint")] public IActionResult GetYourData() { // 接口逻辑 }
注意:生产环境禁止大量使用该方式,会引入安全风险。
内容的提问来源于stack exchange,提问作者kpolewaczyk
相关产品推荐
相关产品推荐

