Получить токен для Microsoft Graph - PullRequest
0 голосов
/ 12 января 2019

Мне нужно веб-приложение, которое будет вызывать конечную точку Microsoft Graph в фоновом режиме. Я следую за документацией: https://docs.microsoft.com/en-us/graph/auth-v2-service?view=graph-rest-1.0

Итак, я получил tenantId и попытался сделать это с Почтальоном:

enter image description here

и я получаю токен доступа. Сейчас я хочу сделать это в приложении ASP.NET Core с помощью Microsoft Identity Client.

У меня есть следующий класс запуска:

    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<CookiePolicyOptions>(options =>
        {
            // This lambda determines whether user consent for non-essential cookies is needed for a given request.
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });


        services.AddAuthentication(sharedOptions =>
        {
            sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        })
        .AddAzureAd(options => Configuration.Bind("AzureAd", options))
        .AddCookie();

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

        services.AddMemoryCache();
        services.AddSession();

        // Add application services.
        //services.AddSingleton<IConfiguration>(Configuration);
        services.AddSingleton<IGraphAuthProvider, GraphAuthProvider>();

        var sp = services.BuildServiceProvider();

        services.AddSingleton<IGraphAuthProvider>(s => new GraphAuthProvider(
            sp.GetService<IMemoryCache>(),
            Configuration.GetSection("AzureAd:ClientId").Value,
            Configuration.GetSection("AzureAd:ClientSecret").Value,
            Configuration.GetSection("AzureAd:GraphScopes").Value.Split(new[] { ' ' }),
            Configuration.GetSection("AzureAd:BaseUrl").Value + Configuration.GetSection("AzureAd:CallbackPath").Value
            ));

        services.AddTransient<IGraphSdkHelper, GraphSdkHelper>();

        services.Configure<HstsOptions>(options =>
        {
            options.IncludeSubDomains = true;
            options.MaxAge = TimeSpan.FromDays(365);
        });

    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseCookiePolicy();
        app.UseSession();
        app.UseAuthentication();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }

GraphAuthProvider:

public class GraphAuthProvider : IGraphAuthProvider
{
    private readonly IMemoryCache _memoryCache;
    private TokenCache _userTokenCache;

    // Properties used to get and manage an access token.
    private readonly string _appId;
    private readonly ClientCredential _credential;
    private readonly string[] _scopes;
    private readonly string _redirectUri;

    public GraphAuthProvider(IMemoryCache memoryCache)
    {

        _memoryCache = memoryCache;
    }

    public GraphAuthProvider(IMemoryCache memoryCache, string clientId, string clientSecret, string[] graphScopes, string redirectUri) : this(memoryCache)
    {

        _appId = clientId;
        _credential = new ClientCredential(clientSecret);
        _scopes = graphScopes;
        _redirectUri = redirectUri;
    }

    // Gets an access token. First tries to get the access token from the token cache.
    // Using password (secret) to authenticate. Production apps should use a certificate.
    public async Task<string> GetUserAccessTokenAsync(string userId)
    {
        _userTokenCache = new SessionTokenCache(userId, _memoryCache).GetCacheInstance();

        var cca = new ConfidentialClientApplication(
            _appId,
            _redirectUri,
            _credential,
            _userTokenCache,
            null);

        var accounts = (await cca.GetAccountsAsync()).ToList();
        if (!accounts.Any()) throw new ServiceException(new Error
        {
            Code = "TokenNotFound",
            Message = "User not found in token cache. Maybe the server was restarted."
        });

        try
        {
            var result = await cca.AcquireTokenSilentAsync(_scopes, accounts.First());
            return result.AccessToken;
        }

        // Unable to retrieve the access token silently.
        catch (Exception)
        {
            throw new ServiceException(new Error
            {
                Code = GraphErrorCode.AuthenticationFailure.ToString(),
                Message = "Caller needs to authenticate. Unable to retrieve the access token silently."
            });
        }
    }
}

и попробуйте вызвать его с контроллера:

    public async Task<IActionResult> Index()
    {
        string identifier = "XXX";
        var graphClient = _graphSdkHelper.GetAuthenticatedClient(identifier);
        var user = await graphClient.Users.Request().GetAsync();
        return View();
    }

, где XXX такое же, как и в адресе Uri в Postman выше

Но это не работает, я получаю пустой список аккаунтов здесь GetUserAccessTokenAsync метод:

        var accounts = (await cca.GetAccountsAsync()).ToList();

что не так?

ДОБАВЛЕНО № 1:

Я получаю то же самое, когда пытаюсь это сделать:

        string authority = $"https://login.microsoftonline.com/{userId}/";

        var cca = new ConfidentialClientApplication(
            _appId,
            authority,
            _redirectUri,
            _credential,
            _userTokenCache,
            null);
...