我目前对如何实现身份验证/授权流程感到困惑。
我正在开发两个应用程序,一个是前端/ Web应用程序,另一个是后端/ API,都使用ASP.NET Core。目标是使用AzureAD并使用域中的用户/组。我已经在两个应用程序上都实现了身份验证,并且能够根据登录状态登录和限制内容。
作为参考,我以Microsoft开发人员的this为例。我应该做的正是这件事。有一个WebApp和API。使用的身份验证流程是授权代码流程。首先,用户需要登录,然后,当需要从API请求一些数据时,将请求访问令牌。
问题1:这是正确的身份验证流程吗?对我来说,这似乎是双重身份验证,因为首先我在前端对自己进行身份验证,当Webapp需要一些数据时,我需要在后端再次进行身份验证。使用相同的Azure AD租户,那么您在这里怎么看?
接下来的一点看起来非常“丑陋”是获取一些数据的过程。在该示例中,当首先请求某些数据时,将请求令牌,然后请求数据。但是我认为有很多样板。对于所有待办事项中的一个请求,仅需以下示例代码。
// GET: /<controller>/
public async Task<IActionResult> Index()
{
AuthenticationResult result = null;
List<TodoItem> itemList = new List<TodoItem>();
try
{
// 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);
// Return the To Do List in the view.
if (response.IsSuccessStatusCode)
{
List<Dictionary<String, String>> responseElements = new List<Dictionary<String, String>>();
JsonSerializerSettings settings = new JsonSerializerSettings();
String responseString = await response.Content.ReadAsStringAsync();
responseElements = JsonConvert.DeserializeObject<List<Dictionary<String, String>>>(responseString, settings);
foreach (Dictionary<String, String> responseElement in responseElements)
{
TodoItem newItem = new TodoItem();
newItem.Title = responseElement["title"];
newItem.Owner = responseElement["owner"];
itemList.Add(newItem);
}
return View(itemList);
}
//
// If the call failed with access denied, then drop the current access token from the cache,
// and show the user an error indicating they might need to sign-in again.
//
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
return ProcessUnauthorized(itemList, authContext);
}
}
catch (Exception)
{
if (HttpContext.Request.Query["reauth"] == "True")
{
//
// Send an OpenID Connect sign-in request to get a new set of tokens.
// If the user still has a valid session with Azure AD, they will not be prompted for their credentials.
// The OpenID Connect middleware will return to this controller after the sign-in response has been handled.
//
return new ChallengeResult(OpenIdConnectDefaults.AuthenticationScheme);
}
//
// The user needs to re-authorize. Show them a message to that effect.
//
TodoItem newItem = new TodoItem();
newItem.Title = "(Sign-in required to view to do list.)";
itemList.Add(newItem);
ViewBag.ErrorMessage = "AuthorizationRequired";
return View(itemList);
}
//
// If the call failed for any other reason, show the user an error.
//
return View("Error");
}
问题2:如果Q1中的流程正确,是否存在“不太丑陋”的方法来访问数据?