我很难理解如何重用用户的安全令牌,以便在他们的数据请求流经多个Web API时对其进行身份验证。
Console App
-C#/ Net Framework 4.7.x控制台应用程序。WebAPI 1
-C#/ .Net Core 2.2 MVC WebAPI应用程序。WebAPI 2
-C#/ .Net Core 2.2 MVC WebAPI应用程序。当前,它们都在运行在我的开发箱上的自己的Visual Studio 2019解决方案中配置为独立的应用程序,但是(一旦运行!)将各自作为独立的实体托管在Azure中。
本质上,用户在控制台应用程序中进行身份验证,从而从Azure Active Directory验证其凭据。在GitHub上的this sample之后,我有了控制台应用程序,可以成功调用WebAPI 1
,并返回数据。
但是,我希望WebAPI 1
在通话期间调用WebAPI 2
并检索其他数据作为Console App数据集的一部分,而这正是我所坚持的部分。
WebAPI 2
在Azure门户中的配置与WebAPI 1
完全相同,但不同的Application Client ID等除外。
作为示例的一部分(如上所述),我可以先将WebAPI 1
调用Microsoft的Graph API,然后再将数据返回给调用的Console App
,所以我认为离这很远。这是调用Graph API的代码:
public async Task<string> CallGraphApiOnBehalfOfUser()
{
string[] scopes = { "user.read" };
// we use MSAL.NET to get a token to call the API On Behalf Of the current user
try
{
string accessToken = await _tokenAcquisition.GetAccessTokenOnBehalfOfUser(HttpContext, scopes);
dynamic me = await CallGraphApiOnBehalfOfUser(accessToken);
return me.userPrincipalName;
}
catch (MsalUiRequiredException ex)
{
_tokenAcquisition.ReplyForbiddenWithWwwAuthenticateHeader(HttpContext, scopes, ex);
return string.Empty;
}
}
private static async Task<dynamic> CallGraphApiOnBehalfOfUserOriginal(string accessToken)
{
//
// Call the Graph API and retrieve the user's profile.
//
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
HttpResponseMessage response = await client.GetAsync("https://graph.microsoft.com/v1.0/me");
string content = await response.Content.ReadAsStringAsync();
if (response.StatusCode == HttpStatusCode.OK)
{
dynamic me = JsonConvert.DeserializeObject(content);
return me;
}
throw new Exception(content);
}
我的计划是将上述代码中的URL更改为指向WebAPI 2
的地址,但是在身份验证期间失败。 如果我删除了 WebAPI 2
中我控制器上的[Authorize]类属性,它确实成功建立了连接并返回了预期的数据,但是启用该属性后,它甚至没有命中Controller上的一个断点,向我提示问题出在我尝试使用 OR 的承载令牌上,而WebAPI 2的配置不正确。
获取安全令牌的副本并尝试重新使用该进程也无法正常工作,因为我认为该令牌用于WebAPI 1
,因此对于{{1 }}。
我应该像这样进行通过验证吗? (将用户凭据硬编码到能够访问WebAPI 2
的{{1}}中感觉很脏,所以我不想这样做。此外,如果用户凭据需要更改,我已经为此而重新部署。)
是否有更好的方法来做我想做的事情?
如果您需要我提供更多信息来解释我所做的任何事情,我当然可以。
更新1:这是Startup.cs:
WebAPI 1
更新2:类似的堆栈溢出信息 此后,我发现了this SO post,@ philippe-signoret在他的回答中对此进行了描述,而这正是我所追求的。
更新3:呼叫WebAPI 2
这是我从电话中收到的错误消息:
public void ConfigureServices(IServiceCollection services)
{
services.AddProtectWebApiWithMicrosoftIdentityPlatformV2(Configuration)
.AddProtectedApiCallsWebApis(Configuration, new string[] { "user.read", "offline_access" })
.AddInMemoryTokenCaches();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseMvc();
}
如前所述,如果我从控制器的类中删除[Authorize]属性,则调用将按预期进行。
答案 0 :(得分:0)
您应参考的示例是https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-openidconnect-aspnetcore。本示例包含在由Azure AD保护的ASP.NET Core 2.0上运行的Web API。 ASP.NET Core 2.0 Web应用程序代表登录用户访问Web API。
示例中的中间应用程序是Web应用程序,而不是Web api,但是基本原理是相同的。
我建议您首先严格遵循此示例,以便您了解如何代表用户从Web api 1调用Web api 2。请注意“ Register the TodoListWebApp web application”部分下的步骤6、7:
6, From the Settings blade, select Required permissions. Select + Add, and then select Select an API.
Type TodoListService in the textbox and press Enter. Select the web API from the list and then select the Select button. Select Select Permissions.
Tick the checkbox next to Access TodoListService and then select the Select button. Select the Done button.
7, In the Settings blade, under API Access, select Required permissions.
Click on the Grant Permissions and when prompted press Yes.
Once the web app is granted access to the webapi you should see the following message: Successfully granted permissions to the application for your account.
To grant permissions for all users, please have an admin consent to the application.
在Web应用程序中调用Web api的核心代码段如下:
// Because we signed-in already in the WebApp, the userObjectId is know
string userObjectID = (User.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier"))?.Value;
// Using ADAL.Net, get a bearer token to access the TodoListService
AuthenticationContext authContext = new AuthenticationContext(AzureAdOptions.Settings.Authority, new NaiveSessionCache(userObjectID, HttpContext.Session));
ClientCredential credential = new ClientCredential(AzureAdOptions.Settings.ClientId, AzureAdOptions.Settings.ClientSecret);
result = await authContext.AcquireTokenSilentAsync(AzureAdOptions.Settings.TodoListResourceId, credential, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
// Retrieve the user's To Do List.
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, AzureAdOptions.Settings.TodoListBaseAddress + "/api/todolist");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
HttpResponseMessage response = await client.SendAsync(request);