Search code examples
asp.net-mvcadal

Store authentification data in MVC


I have created a custom Authorize attribute where I use the Office Graph to get AAD groups the current user is member of, and based on those I reject or authorize the user. I want to save the groups, because the call to Office Graph takes some performance. What would be the correct way to save that kind of data? I can see some people saves it to a SQL server, but then I would need to ensure cleanup etc.

Also I can see in some threads the session state is stated to be a bad choice due to concurrency. So the question is what options do you have to store this kind of information?

All suggestions are welcome.


Solution

  • If you were only using the group_id info, there is no need to use Office Graph and store it at all. We can enable Azure AD issue the groups claims by change the manifest of Azure AD like below:(refer this code sample)

    "groupMembershipClaims": "All",
    

    And if you are also using other info about groups, you can store these info into claims. Here is a code sample that add the name of groups into claims for your reference:

    AuthorizationCodeReceived = async context =>
    {
        ClientCredential credential = new ClientCredential(ConfigHelper.ClientId, ConfigHelper.AppKey);
        string userObjectId = context.AuthenticationTicket.Identity.FindFirst(Globals.ObjectIdClaimType).Value;
        AuthenticationContext authContext = new AuthenticationContext(ConfigHelper.Authority, new TokenDbCache(userObjectId));
        AuthenticationResult result = await authContext.AcquireTokenByAuthorizationCodeAsync(
            context.Code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, ConfigHelper.GraphResourceId);
    
        ActiveDirectoryClient graphClient = new ActiveDirectoryClient(new Uri(ConfigHelper.GraphServiceRoot),
      async () => { return await Task.FromResult(result.AccessToken); }
      );
    
        try
        {
            foreach (var groupClaim in context.AuthenticationTicket.Identity.FindAll("groups"))
            {
    
                var request = new HttpRequestMessage()
                {
                    RequestUri = new Uri($"https://graph.windows.net/adfei.onmicrosoft.com/groups/{groupClaim.Value}?api-version=1.6"),
                    Method = HttpMethod.Get,
                };
    
                request.Headers.Authorization = new AuthenticationHeaderValue("bearer", result.AccessToken);
    
                using (HttpClient httpClient = new HttpClient())
                {
                    HttpResponseMessage httpResponse = httpClient.SendAsync(request).Result;
                    var retJSON = httpResponse.Content.ReadAsStringAsync().Result;
    
                    var dict = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(retJSON);
                    ((ClaimsIdentity)context.AuthenticationTicket.Identity).AddClaim(new Claim("groupName", dict["displayName"].ToString()));
                }
            }
    
        }
        catch (Exception ex)
        {
    
        }
    },
    

    Then we can these info from controller using the code below:

    ClaimsPrincipal.Current.FindAll("groupName")