Asp.net

.Net Core 2.0 - 獲取 AAD 訪問令牌以與 Microsoft Graph 一起使用

  • October 4, 2017

使用 Azure AD 身份驗證啟動新的 .Net Core 2.0 項目時,您將獲得一個可以登錄租戶的工作範例,太棒了!

現在我想為登錄使用者獲取一個訪問令牌,並使用它來使用 Microsoft Graph API。

我沒有找到任何關於如何實現這一目標的文件。我只想要一種簡單的方法來獲取訪問令牌並訪問圖形 API,使用啟動新 .NET Core 2.0 項目時創建的模板。從那裡我應該能夠弄清楚其餘的。

非常重要的是,它與在 Visual Studio 中創建新的 2.0 MVC Core 應用程序時遵循選擇工作和學校帳戶進行身份驗證的過程時創建的項目一起使用。

我寫了一篇部落格文章,展示瞭如何做到這一點:ASP.NET Core 2.0 Azure AD Authentication

TL;DR 是當您從 AAD 收到授權碼時,您應該添加這樣的處理程序:

.AddOpenIdConnect(opts =>
{
   Configuration.GetSection("Authentication").Bind(opts);

   opts.Events = new OpenIdConnectEvents
   {
       OnAuthorizationCodeReceived = async ctx =>
       {
           var request = ctx.HttpContext.Request;
           var currentUri = UriHelper.BuildAbsolute(request.Scheme, request.Host, request.PathBase, request.Path);
           var credential = new ClientCredential(ctx.Options.ClientId, ctx.Options.ClientSecret);

           var distributedCache = ctx.HttpContext.RequestServices.GetRequiredService<IDistributedCache>();
           string userId = ctx.Principal.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;

           var cache = new AdalDistributedTokenCache(distributedCache, userId);

           var authContext = new AuthenticationContext(ctx.Options.Authority, cache);

           var result = await authContext.AcquireTokenByAuthorizationCodeAsync(
               ctx.ProtocolMessage.Code, new Uri(currentUri), credential, ctx.Options.Resource);

           ctx.HandleCodeRedemption(result.AccessToken, result.IdToken);
       }
   };
});

這是我context.Options.Resourcehttps://graph.microsoft.com(Microsoft Graph),我從配置與其他設置(客戶端 ID 等)綁定。

我們使用 ADAL 兌換令牌,並將生成的令牌儲存在令牌記憶體中。

令牌記憶體是您必須要做的事情,這是範例應用程序中的範例:

public class AdalDistributedTokenCache : TokenCache
{
   private readonly IDistributedCache _cache;
   private readonly string _userId;

   public AdalDistributedTokenCache(IDistributedCache cache, string userId)
   {
       _cache = cache;
       _userId = userId;
       BeforeAccess = BeforeAccessNotification;
       AfterAccess = AfterAccessNotification;
   }

   private string GetCacheKey()
   {
       return $"{_userId}_TokenCache";
   }

   private void BeforeAccessNotification(TokenCacheNotificationArgs args)
   {
       Deserialize(_cache.Get(GetCacheKey()));
   }

   private void AfterAccessNotification(TokenCacheNotificationArgs args)
   {
       if (HasStateChanged)
       {
           _cache.Set(GetCacheKey(), Serialize(), new DistributedCacheEntryOptions
           {
               AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(1)
           });
           HasStateChanged = false;
       }
   }
}

此處的令牌記憶體使用分佈式記憶體來儲存令牌,以便為您的應用提供服務的所有實例都可以訪問令牌。它們按使用者記憶體,因此您可以稍後為任何使用者檢索令牌。

然後,當您想獲取令牌並使用 MS 圖形時,您會執行類似(重要的事情GetAccessTokenAsync()):

[Authorize]
public class HomeController : Controller
{
   private static readonly HttpClient Client = new HttpClient();
   private readonly IDistributedCache _cache;
   private readonly IConfiguration _config;

   public HomeController(IDistributedCache cache, IConfiguration config)
   {
       _cache = cache;
       _config = config;
   }

   [AllowAnonymous]
   public IActionResult Index()
   {
       return View();
   }

   public async Task<IActionResult> MsGraph()
   {
       HttpResponseMessage res = await QueryGraphAsync("/me");

       ViewBag.GraphResponse = await res.Content.ReadAsStringAsync();

       return View();
   }

   private async Task<HttpResponseMessage> QueryGraphAsync(string relativeUrl)
   {
       var req = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0" + relativeUrl);

       string accessToken = await GetAccessTokenAsync();
       req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

       return await Client.SendAsync(req);
   }

   private async Task<string> GetAccessTokenAsync()
   {
       string authority = _config["Authentication:Authority"];

       string userId = User.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
       var cache = new AdalDistributedTokenCache(_cache, userId);

       var authContext = new AuthenticationContext(authority, cache);

       string clientId = _config["Authentication:ClientId"];
       string clientSecret = _config["Authentication:ClientSecret"];
       var credential = new ClientCredential(clientId, clientSecret);

       var result = await authContext.AcquireTokenSilentAsync("https://graph.microsoft.com", credential, new UserIdentifier(userId, UserIdentifierType.UniqueId));

       return result.AccessToken;
   }
}

在那裡,我們靜默獲取令牌(使用令牌記憶體),並將其附加到對 Graph 的請求。

引用自:https://stackoverflow.com/questions/46566717