Asp.net-Mvc

如何使用 ASP.NET Identity (OWIN) 訪問 Facebook 私人資訊?

  • September 22, 2013

我正在用 ASP.NET MVC 5 開發一個網站(目前使用 RC1 版本)。該站點將使用 Facebook 進行使用者身份驗證和檢索初始配置文件數據。

對於身份驗證系統,我正在使用基於 OWIN 的新 ASP.NET 身份引擎(http://blogs.msdn.com/b/webdev/archive/2013/07/03/understanding-owin-forms-authentication-in-mvc -5.aspx),因為它極大地簡化了與外部提供商進行身份驗證的過程。

問題是,一旦使用者首次登錄,我想從 Facebook 個人資料中獲取其電子郵件地址,但此數據不包含在生成的聲明中。所以我考慮了這些替代方法來獲取地址:

  1. 指示 ASP.NET 身份引擎將電子郵件地址包含在從 Facebook 檢索然後轉換為聲明的數據集中。我不知道這是否可能。
  2. 使用 Facebook 圖形 API ( <https://developers.facebook.com/docs/getting-started/graphapi> ) 通過 Facebook 使用者 ID(包含在聲明數據中)檢索電子郵件地址。但是,如果使用者將他的電子郵件地址設置為私人,這將不起作用。
  3. 使用 Facebook 圖形 API,但指定“我”而不是 Facebook 使用者 ID ( <https://developers.facebook.com/docs/reference/api/user> )。但是需要訪問令牌,而且我不知道如何(或者是否可能)檢索 ASP.NET 用於獲取使用者數據的訪問令牌。

所以問題是:

  1. 如何指示 ASP.NET 身份引擎從 Facebook 檢索其他資訊並將其包含在聲明數據中?
  2. 或者,我怎樣才能檢索生成的訪問令牌,以便我可以自己詢問 Facebook?

謝謝!

注意:對於身份驗證系統,我的應用程序使用基於此 SO 答案中連結的範例項目的程式碼:https ://stackoverflow.com/a/18423474/4574

要從 facebook 檢索其他資訊,您可以在配置 facebook 身份驗證選項時指定要包含的範圍。可以通過實現提供者的 OnAuthenticated 方法來獲取檢索到的附加資訊,如下所示:

var facebookOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions()
{
   Provider = new FacebookAuthenticationProvider()
   {
       OnAuthenticated = (context) =&gt;
           {
               // All data from facebook in this object. 
               var rawUserObjectFromFacebookAsJson = context.User;

               // Only some of the basic details from facebook 
               // like id, username, email etc are added as claims.
               // But you can retrieve any other details from this
               // raw Json object from facebook and add it as claims here.
               // Subsequently adding a claim here will also send this claim
               // as part of the cookie set on the browser so you can retrieve
               // on every successive request. 
               context.Identity.AddClaim(...);

               return Task.FromResult(0);
           }
   }
};

//Way to specify additional scopes
facebookOptions.Scope.Add("...");

app.UseFacebookAuthentication(facebookOptions);

根據此處的程式碼,如果 facebook 已發送,我看到電子郵件已被檢索並在此處添加為聲明。你看不出來嗎?

在 Startup.ConfigureAuth (StartupAuth.cs) 中創建一個新的 Microsoft.Owin.Security.Facebook.AuthenticationOptions 對象,將 FacebookAppId、FacebookAppSecret 和一個新的 AuthenticationProvider 傳遞給它。您將使用 lambda 表達式向 OnAuthenticated 方法傳遞一些程式碼,以將聲明添加到包含您從 context.Identity 中提取的值的標識中。預設情況下,這將包括access_token。您必須將電子郵件添加到範圍。其他使用者屬性可從 context.User 獲得(例如,請參見底部的連結)。

啟動.Auth.cs

// Facebook : Create New App
// https://dev.twitter.com/apps
if (ConfigurationManager.AppSettings.Get("FacebookAppId").Length &gt; 0)
{
   var facebookOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions()
   {
       AppId = ConfigurationManager.AppSettings.Get("FacebookAppId"),
       AppSecret = ConfigurationManager.AppSettings.Get("FacebookAppSecret"),
       Provider = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationProvider()
       {
           OnAuthenticated = (context) =&gt;
               {
                   context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:access_token", context.AccessToken, XmlSchemaString, "Facebook"));
                   context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:email", context.Email, XmlSchemaString, "Facebook"));
                   return Task.FromResult(0);
               }
       }

   };
   facebookOptions.Scope.Add("email");
   app.UseFacebookAuthentication(facebookOptions);
}

在 AccountController 中,我使用外部 cookie 從 AuthenticationManager 中提取 ClaimsIdentity。然後我將它添加到使用應用程序 cookie 創建的身份中。我忽略了任何以“…schemas.xmlsoap.org/ws/2005/05/identity/claims”開頭的聲明,因為它似乎破壞了登錄。

AccountController.cs

private async Task SignInAsync(CustomUser user, bool isPersistent)
{
   AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
   var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);

// Extracted the part that has been changed in SignInAsync for clarity.
   await SetExternalProperties(identity);

   AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}

private async Task SetExternalProperties(ClaimsIdentity identity)
{
   // get external claims captured in Startup.ConfigureAuth
   ClaimsIdentity ext = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);

   if (ext != null)
   {
       var ignoreClaim = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims";
       // add external claims to identity
       foreach (var c in ext.Claims)
       {
           if (!c.Type.StartsWith(ignoreClaim))
               if (!identity.HasClaim(c.Type, c.Value))
                   identity.AddClaim(c);
       } 
   }
}

最後,我想顯示任何不是來自地方當局的值。我創建了顯示在/Account/Manage 頁面上的部分視圖 _ExternalUserPropertiesListPartial 。我從 AuthenticationManager.User.Claims 中獲取了之前儲存的聲明,然後將其傳遞給視圖。

AccountController.cs

[ChildActionOnly]
public ActionResult ExternalUserPropertiesList()
{
   var extList = GetExternalProperties();
   return (ActionResult)PartialView("_ExternalUserPropertiesListPartial", extList);
}

private List&lt;ExtPropertyViewModel&gt; GetExternalProperties()
{
   var claimlist = from claims in AuthenticationManager.User.Claims
                   where claims.Issuer != "LOCAL AUTHORITY"
                   select new ExtPropertyViewModel
                   {
                       Issuer = claims.Issuer,
                       Type = claims.Type,
                       Value = claims.Value
                   };

   return claimlist.ToList&lt;ExtPropertyViewModel&gt;();
}

只是為了徹底,觀點:

_ExternalUserPropertiesListPartial.cshtml

@model IEnumerable&lt;MySample.Models.ExtPropertyViewModel&gt;

@if (Model != null)
{
   &lt;legend&gt;External User Properties&lt;/legend&gt;
   &lt;table class="table"&gt;
       &lt;tbody&gt;
           @foreach (var claim in Model)
           {
               &lt;tr&gt;
                   &lt;td&gt;@claim.Issuer&lt;/td&gt;
                   &lt;td&gt;@claim.Type&lt;/td&gt;
                   &lt;td&gt;@claim.Value&lt;/td&gt;
               &lt;/tr&gt;
           }
       &lt;/tbody&gt;
   &lt;/table&gt;
}

工作範例和完整程式碼在 GitHub 上: https ://github.com/johndpalm/IdentityUserPropertiesSample

我們將不勝感激任何回饋、更正或改進。

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