c# - 将 Web 应用身份验证转发到 API 服务
问题描述
我有一个应用程序被分解成一个 Web 应用程序(Asp .net MVC),它与一个用 C# .net core 2.2 编写的 API 服务对话。我有使用内置 AZure AD 身份验证的 Web 应用程序。这很好用,因为它会提示用户输入他们的 Azure 域 ID 和密码,并且只允许特定用户进入。
我对 API 服务做了同样的事情。所有的 startup.cs 代码都已正确设置。
我想使用来自 web 应用程序的身份验证并转发到 api 服务,但无法找到一种方法来做到这一点,甚至无法访问它。
我尝试添加不同的身份验证方案(azureadbearer 和 jwtbearer),但这些方案只是让 Web 应用程序无法工作,从未提示进行身份验证
在 Web 应用程序中,这使用 Azure AD 并要求对用户进行身份验证:
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options =>
{
Configuration.Bind("AzureAd", options);
});
在 API 服务中,我有
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
.AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
但我无法弄清楚网络应用程序应该如何/调用什么来授权或获取 api 服务的令牌。如果我为 api 控制器添加 [Authorize] 属性,我会从 Web 应用程序调用它时收到未经授权的错误。
我希望能够使用或获取在用户授权 Web 应用程序并将其转发到 api 服务时创建的令牌,但在标头中没有看到任何类似于 jwt 令牌的内容。
我还尝试在 Web 应用程序中创建 jwt 令牌并设置授权标头(承载令牌)并发送到 api 服务,并将 api 服务更改为使用 jwtbearer,但我仍然会得到未经授权的。
我花了几天的时间试图找到示例并让这个工作没有运气,任何建议都将不胜感激......希望能够使用内置的 AzureAD 中间件,如果可能的话,不必编写任何代码来处理这个问题。
这是我在 api 服务中尝试过的,但没有验证我发送的令牌:s
services.AddAuthentication(AzureADDefaults.JwtBearerAuthenticationScheme).AddJwtBearer(cfg =>
{
cfg.RequireHttpsMetadata = true;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
{
ValidIssuer = Configuration["ServiceAd:Issuer"],
ValidAudience = Configuration["ServiceAd:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["ServiceAd:ClientSecret"]))
};
});
解决方案
我建议使用OAuth2.0 代表 flow。根据您的要求,您希望在 Web 应用程序中对用户进行身份验证,并为 Web api 创建一个令牌并从 Web 应用程序控制器调用 Web api。
首先创建 2 个服务主体,一个用于 web 应用程序,第二个用于 web api。然后转到 web 应用服务主体 --> 权限部分并添加 web api(服务主体)并授予权限。
创建服务主体后,您需要在 Web 应用控制器中使用 OAuth 2.0 代流。运行 Web 应用程序后,您必须使用用户名和密码对用户进行身份验证,在对用户进行身份验证后,您可以在控制器操作方法中使用 HttpContext 获取 access_token,然后使用代表流程获取另一个令牌web api 并调用 web api 来访问资源。
您可以查看以下代流文档: OAuth2.0 代流
在 web app--> HomeController.cs --> Index() 方法中获取当前令牌(第一次登录时获取访问令牌),使用该令牌为 web api 创建另一个令牌。
以下是代表流程的代码:
private async Task<string> GetOnBehalfToken()
{
// Get User Assertion
var authenticateInfo = await HttpContext.Authentication.GetAuthenticateInfoAsync("Bearer");
string incomingToken = authenticateInfo.Properties.Items[".Token.access_token"];
UserAssertion userAssertion = new UserAssertion(incomingClientToken, "urn:ietf:params:oauth:grant-type:jwt-bearer");
string token = string.Empty;
string authString = string.Format(this.azureAd.AadInstance, this.azureAd.TenantId);
AuthenticationContext authenticationContext = new AuthenticationContext(authString, false);
// config for oauth client credentials
// Use Web app client id and secret key
ClientCredential clientCredential = new ClientCredential(this.azureAd.ClientId, this.azureAd.AppKey);
// App ID uri of web api service principal
var resource = "https://<tenant>.onmicrosoft.com/45854ee0-608a-4dff-xxx-xxxxxxxxxxx";
AuthenticationResult result = await authenticationContext.AcquireTokenAsync(resource, clientCredential);
return result.AccessToken;
}
获取 web api 的令牌后,将其添加到 http 客户端的 Authorization 标头并调用 api。
如果您只想使用 Azure AD 对 Web api 进行身份验证。在启动时使用下面的代码,看看它是否适合你:
public static void ConfigureAuthentication(IAppBuilder app)
{
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Tenant = Configuration["AzureAD.TenantId"],
TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidIssuer = Configuration["AzureAD.Issuer"],
ValidAudience = Configuration["AzureAD.Audience"],
ValidateLifetime = true
}
});
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidIssuer = Configuration["AzureAD.Issuer"],
ValidAudience = Configuration["AzureAD.Audience"],
ValidateLifetime = true
}
});
}
还要验证 Issuer({tenant-name}.onmicrosoft.com) 和 Audience(App Id uri of service principal) 值是否正确。
我希望这能解决你的问题。
推荐阅读
- amazon-web-services - 在 AWS Route 53 中重定向电子邮件(添加 MX 记录)
- autodesk-forge - 在聚合查看器中使用 Viewer3D 方法
- elasticsearch - 将 Elastic Search 查询合并为一个
- react-native - react-native-gifted-chat inputToolbar 后面的 ImageBackground
- hybris - 斯巴达克斯店面升级后智能编辑不稳定
- python - Pytorch 通过入口值张量有效地索引重复张量
- php - 在带有 MVC NATIVE 的 PHP 中使用 AJAX
- javascript - 使用数组中的键值对创建对象
- html - API 调用后 HTML 视频不适合 - next.js 和 styled-components
- exchangewebservices - 如何在 Windows 2019 中使用 GACUTIL 安装 Microsoft.Exchange.WebServices.2.2.nupkg