Asp.net

如何訪問 Microsoft.Owin.Security.xyz OnAuthenticated 上下文 AddClaims 值?

  • July 24, 2015

我正在嘗試檢索作為 OnAuthenticated 上下文返回的使用者屬性,並在此範例之後添加為聲明: 如何使用 ASP.NET 身份 (OWIN) 訪問 Facebook 私人資訊?

我可以看到我期望的數據在登錄時被返回,並被添加為 Starup.Auth.cs 中的聲明。但是,當我在 Account Controller 中時,出現在 UserManager 或 UserStore 中的唯一聲明是由 LOCAL AUTHORITY 發布的。找不到 Facebook(或其他外部提供商)的聲明。添加到上下文中的聲明在哪裡結束?(我正在使用 VS2013 RTM。)

Azure 上的完整原始碼和實時站點連結在這裡:https ://github.com/johndpalm/IdentityUserPropertiesSample/tree/VS2013rtm

這是我在 Startup.Auth.cs 中的內容:

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) =>
           {
               const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string";
               foreach (var x in context.User)
               {
                   var claimType = string.Format("urn:facebook:{0}", x.Key);
                   string claimValue = x.Value.ToString();
                   if (!context.Identity.HasClaim(claimType, claimValue))
                       context.Identity.AddClaim(new System.Security.Claims.Claim(claimType, claimValue, XmlSchemaString, "Facebook"));

               }
               context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:access_token", context.AccessToken, XmlSchemaString, "Facebook"));
               return Task.FromResult(0);
           }
   }

};

facebookOptions.Scope.Add("email");

app.UseFacebookAuthentication(facebookOptions);

擷取外部登錄屬性的另一種方法是為訪問令牌添加一個聲明並使用屬性填充它:

const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string";
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) =>
       {
           var claim = new System.Security.Claims.Claim("urn:facebook:access_token", context.AccessToken, XmlSchemaString, "Facebook");
           foreach (var x in context.User)
           {
               string key = string.Format("urn:facebook:{0}", x.Key);
               string value = x.Value.ToString();
               claim.Properties.Add(key, value);
           }

           context.Identity.AddClaim(claim);

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

注意 - 此範例不起作用:儘管傳遞帶有屬性的單個聲明會很好。外部 cookie 似乎注意到了聲明屬性。稍後從身份中檢索屬性時,這些屬性為空。

我能夠使用 MVC 5 RTM 模板、OWIN 和 ASP.NET 標識位創建一個工作範例。您可以在此處找到完整的原始碼和指向實時工作範例的連結: https ://github.com/johndpalm/IdentityUserPropertiesSample

這對我有用:

在 Startup.ConfigureAuth (StartupAuth.cs) 中創建一個新的(在此處插入提供程序名稱)AuthenticationOptions 對象,將客戶端 ID、客戶端密碼和新的 AuthenticationProvider 傳遞給它。您將使用 lambda 表達式向 OnAuthenticated 方法傳遞一些程式碼,以將聲明添加到包含您從 context.Identity 中提取的值的標識中。

啟動.Auth.cs

// Facebook : Create New App
// https://dev.twitter.com/apps
if (ConfigurationManager.AppSettings.Get("FacebookAppId").Length > 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) =>
               {
                   context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:access_token", context.AccessToken, XmlSchemaString, "Facebook"));
                   foreach (var x in context.User)
                   {
                       var claimType = string.Format("urn:facebook:{0}", x.Key);
                       string claimValue = x.Value.ToString();
                       if (!context.Identity.HasClaim(claimType, claimValue))
                           context.Identity.AddClaim(new System.Security.Claims.Claim(claimType, claimValue, XmlSchemaString, "Facebook"));

                   }
                   return Task.FromResult(0);
               }
       }

   };
   app.UseFacebookAuthentication(facebookOptions);
}

注意:Facebook 身份驗證提供程序使用此處使用的程式碼。如果您將相同的程式碼與 Microsoft 帳戶提供程序(或我使用 MS 帳戶程式碼作為模型創建的Foursquare 提供程序)一起使用,它將無法登錄。如果您只選擇 access_token 參數,它可以正常工作。似乎某些參數會破壞登錄過程。(如果您對此進展感興趣,已在 katanaproject.codeplex.com 上打開了一個問題。)如果我找到原因,我會更新。除了驗證我是否可以獲得 access_token 之外,我沒有對 Twitter 或 Google 做太多事情。

var msaccountOptions = new Microsoft.Owin.Security.MicrosoftAccount.MicrosoftAccountAuthenticationOptions() 
{
   ClientId = ConfigurationManager.AppSettings.Get("MicrosoftClientId"),
   ClientSecret = ConfigurationManager.AppSettings.Get("MicrosoftClientSecret"),
   Provider = new Microsoft.Owin.Security.MicrosoftAccount.MicrosoftAccountAuthenticationProvider()
   {
       OnAuthenticated = (context) =>
           {
               context.Identity.AddClaim(new System.Security.Claims.Claim("urn:microsoftaccount:access_token", context.AccessToken, XmlSchemaString, "Microsoft"));
               return Task.FromResult(0);
           }
   }                   
};

app.UseMicrosoftAccountAuthentication(msaccountOptions);

在 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<ExtPropertyViewModel> 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<ExtPropertyViewModel>();
}

只是為了徹底,觀點:

_ExternalUserPropertiesListPartial.cshtml

@model IEnumerable<MySample.Models.ExtPropertyViewModel>

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

同樣,工作範例和完整程式碼位於 GitHub 上: https ://github.com/johndpalm/IdentityUserPropertiesSample

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

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