Как реализовать пакетную обработку Graph API в MVC Core - PullRequest
0 голосов
/ 05 апреля 2019

Одно из моих приложений должно запросить API Graph для получения всех адресов электронной почты данного пользователя, его идентификатора Guid и идентификатора Guid для всех групп, в которые они входят. У меня это работает, но мне нужно сделать как минимум три звонка, что приводит к снижению производительности. Я попытался объединить его только в два запроса, один для токена авторизации и один для выполнения запроса, но до сих пор я не смог объединить параметры $ select с методом «transitiveMemberOf». Вот что у меня так далеко

public class GraphSearcher
{
    private readonly IConfiguration _configuration;
    private readonly string _clientId;
    private readonly string _clientSecret;
    private readonly string _tenantId;

    public GraphSearcher(IConfiguration configuration)
    {
        _configuration = configuration;
        _clientId = _configuration["AzureAd:ClientId"];
        _clientSecret = _configuration["GraphAPI:Secret"];
        _tenantId = _configuration["AzureAd:TenantId"];
    }

    /// <summary>
    /// Returns a list of email addresses and a list of group Ids.
    /// </summary>
    /// <param name="email"></param>
    /// <returns>AppUserAttributes object.</returns>
    public AppUserAttributes GetUserAttributes(string email)
    {
        var appUserAttributes = new AppUserAttributes();

        if (string.IsNullOrWhiteSpace(email))
            return appUserAttributes;

        appUserAttributes = GetUserData(email);

        return appUserAttributes;
    }

    // Had to invoke 2 queries, as "transitiveMemberOf" method can't be combined with the other select options.
    private AppUserAttributes GetUserData(string email)
    {
        if (string.IsNullOrWhiteSpace(email))
            return null;

        var username = email.Split('@')[0];

        // This query will return all the emails assigned to the current user, and the user's Active Directory id. 
        var graphQuery = $"https://graph.microsoft.com/v1.0/{_tenantId}/users?$select=proxyAddresses,mail,id&$filter=proxyAddresses/any(x:startswith(x,'smtp:{username}'))";

        var response = GenerateResponse(graphQuery);

        var resultString = response.Result.Content.ReadAsStringAsync().Result;

        var emailAddresses = ExtractEmailList(resultString);

        var json = JObject.Parse(resultString);

        var userId = json.SelectTokens("$.value[?(@.id)]").Select(j => j["id"].ToString()).FirstOrDefault();

        // This query returns all the groups the user is assigned to. 
        graphQuery = $"https://graph.microsoft.com/v1.0/{_tenantId}/users/{userId}/transitiveMemberOf";

        response = GenerateResponse(graphQuery);

        json = JObject.Parse(response.Result.Content.ReadAsStringAsync().Result);

        var groupIds = json.SelectTokens("$.value[?(@.id)]").Select(j => j["id"].ToString()).ToList();

        return new AppUserAttributes { EmailAddresses = emailAddresses, UserGroupIds = groupIds };
    }

    private Task<HttpResponseMessage> GenerateResponse(string graphQuery)
    {
        var authHeaderValue = GenerateAuthenticationHeader();

        var response = new HttpClient()
            .GetAsync(graphQuery, x => x.Headers.Authorization = authHeaderValue);

        return response;
    }

    private AuthenticationHeaderValue GenerateAuthenticationHeader()
    {
        var graphAuthenticationToken = GetGraphAuthToken(_clientId, _clientSecret, _tenantId);
        var authHeaderValue = new AuthenticationHeaderValue("Bearer", graphAuthenticationToken);

        return authHeaderValue;
    }

    private List<string> ExtractEmailList(string ldapResult)
    {
        var emailRegex = new Regex(@"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", RegexOptions.IgnoreCase);

        var emailList = emailRegex.Matches(ldapResult).Select(m => m.Value).ToList();

        return emailList;
    }

    private string GetGraphAuthToken(string clientId, string clientSecret, string tenant)
    {
        var authContext = new AuthenticationContext($"https://login.microsoftonline.com/{tenant}/", false);

        var tokenRequest = authContext.AcquireTokenAsync("https://graph.microsoft.com", new ClientCredential(clientId, clientSecret));

        return tokenRequest.Result.AccessToken;
    }
}

public static class HttpHelper
{
    public static Task<HttpResponseMessage> GetAsync(this HttpClient httpClient, string uri, Action<HttpRequestMessage> preAction)
    {
        var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, uri);

        preAction(httpRequestMessage);

        return httpClient.SendAsync(httpRequestMessage);
    }
}

Я не думаю, что смогу справиться с необходимостью выполнить запрос для получения токена авторизации, но я хотел бы избежать одного звонка, чтобы получить электронные письма и идентификатор пользователя, и другого, чтобы получить идентификаторы группы для этого пользователя. ,

Есть идеи?

...