Closed eisenreich closed 6 years ago
@eisenreich Please elaborate a bit more on what boilerplate you are referring to?
Sorry for this inaccuracy.
I'm talking about this part:
// 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");
}
When requesting some data form the API to just every time this code is very redundant.
But I found a good solution from a different sample: Check out this. This doesn't comply to 100 percent, but the way how he handles the cache and request the access token works with charm.
@eisenreich : I'll provide something better in the coming weeks
Thank you alot!
Hey! Do you have any suggestions how to abstract the API token request in the controller to avoid the boilerplate each time I do a request to the API?