获取Microsoft Graph的令牌

时间:2019-01-12 18:03:04

标签: c# oauth token microsoft-graph

我需要一个Web应用程序,它将在后台模式下调用Microsoft Graph端点。 我遵循以下文档:https://docs.microsoft.com/en-us/graph/auth-v2-service?view=graph-rest-1.0

所以,我得到了一个tenantId,并尝试使用Postman:

enter image description here

,我得到一个访问令牌。现在,我想使用Microsoft Identity Client在ASP.NET Core应用程序中完成此操作。

我有以下启动类:

    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地址相同

但是它不起作用,我在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);

0 个答案:

没有答案