2013-10-18 11 views
13

Ich versuche Benutzereigenschaften abzurufen, die als OnAuthenticated Kontext und hinzugefügt als Ansprüche nach diesem Beispiel zurückgegeben werden: How to access Facebook private information by using ASP.NET Identity (OWIN)?Wie greife ich auf Microsoft.Owin.Security.xyz OnAuthenticated Kontext AddClaims Werte zu?

kann ich diese Daten sehen ich erwarte zurückgegeben wird bei der Anmeldung und als wird hinzugefügt Anspruch in Starup.Auth.cs. Aber wenn ich innerhalb des Account Controllers bin, werden die einzigen Ansprüche, die im UserManager oder UserStore erscheinen, von LOCAL AUTHORITY ausgegeben. Für Facebook (oder andere externe Anbieter) können keine Ansprüche erhoben werden. Woher kommen die zum Kontext hinzugefügten Ansprüche? (Ich verwende VS2013 RTM.)

Full Source und Live-Website auf Azure hier verlinkt: https://github.com/johndpalm/IdentityUserPropertiesSample/tree/VS2013rtm

Hier ist, was ich in Startup.Auth.cs haben:

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); 

Eine alternative Art und Weise die externen Login-Eigenschaften einen einzigen Anspruch für den Zugriffstoken zu erfassen und mit Eigenschaften zu füllen hinzuzufügen wäre:

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); 
     } 
    } 
}; 

HINWEIS - Dieses Beispiel funktioniert nicht: Du Es wäre schön, eine einzelne Forderung mit Eigenschaften zu übergeben. Der externe Cookie scheint zu beachten, die Ansprüche Eigenschaften. Die Eigenschaften sind leer, wenn sie später von der Identität abgerufen werden.

Antwort

16

Ich konnte ein funktionierendes Beispiel mit MVC 5 RTM-Vorlagen, OWIN und ASP.NET-Identitätsbits erstellen. Sie können die vollständige Quelle und einen Link zu einem Live-Arbeitsbeispiel finden Sie hier: https://github.com/johndpalm/IdentityUserPropertiesSample

Hier ist, was für mich gearbeitet:

Erstellen Sie einen neuen (insert Provider Name hier) AuthenticationOptions in Startup.ConfigureAuth Objekt (StartupAuth.cs), übergeben Sie ihm die Client-ID, das Client-Geheimnis und einen neuen AuthenticationProvider. Sie verwenden einen Lambda-Ausdruck, um der OnAuthenticated-Methode einen Code zum Hinzufügen von Ansprüchen an die Identität zu übergeben, die die Werte enthalten, die Sie aus context.Identity extrahieren.

StartUp.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); 
} 

HINWEIS: Der Anbieter Facebook Auth mit dem Code funktioniert hier verwendet.Wenn Sie denselben Code mit dem Microsoft-Kontoanbieter verwenden (oder Foursquare provider, den ich mit dem MS-Kontocode als ein Modell erstellte), kann er sich nicht anmelden. Wenn Sie nur den Parameter access_token auswählen, funktioniert es einwandfrei. Scheint, als ob einige Parameter den Login-Prozess unterbrechen. (An issue has been opened on katanaproject.codeplex.com if progress on this is of interest to you.) Ich werde aktualisieren, wenn ich die Ursache finde. Ich habe nicht viel mit Twitter oder Google gemacht, anstatt zu überprüfen, ob ich das access_token bekommen konnte.

In AccountController extrahiere ich die ClaimsIdentity aus dem AuthenticationManager mit dem externen Cookie. Ich füge es dann der Identität hinzu, die mit dem Anwendungscookie erstellt wurde. Ich ignorierte jegliche Behauptungen, die mit "... schemas.xmlsoap.org/ws/2005/05/identity/claims" beginnen, da es den Login zu brechen schien. nicht von der lokalen Behörde

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); 
     } 
    } 
} 

Und schließlich mag ich bin, was Wert anzuzeigen. Ich habe eine Teilansicht _ExternalUserPropertiesListPartial erstellt, die auf der /Account/Manage page erscheint. Ich bekomme die Ansprüche, die ich zuvor von AuthenticationManager.User.Claims gespeichert und dann an die Ansicht übergeben.

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

Und gründlich zu sein, wobei die Ansicht:

_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> 
} 

Auch hier ist das Arbeitsbeispiel und vollständiger Code auf GitHub: https://github.com/johndpalm/IdentityUserPropertiesSample

Und jede Rückmeldung, Korrekturen oder Verbesserungen würden geschätzt werden.

+0

Ich erhalte einen Google 404-Fehlercode bei der Verwendung Ihres Codes. Soweit ich das beurteilen kann, unterstützt Google dies nicht mehr, oauth2. –

1

Also dieser Artikel erklärt, wie das alles funktioniert ziemlich gut: Decoupling owin external auth

Aber die kurze Antwort ist, wenn Sie von facebook authentifizierten erhalten, dass Sie eine externe Identität gibt. Sie müssen dann diese externe Identität übernehmen und eine lokale App-Identität "anmelden". In diesem Schritt müssen Sie der ClaimsIdentity, die User.Identity wird, beliebige Ansprüche aus der externen Identität hinzufügen.

Edit: Zur weiteren Klärung, können Sie es innerhalb von ExternalLoginCallback tun:

// GET: /Account/ExternalLoginCallback 
    [AllowAnonymous] 
    public async Task<ActionResult> ExternalLoginCallback(string returnUrl) { 
     var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(); 
     if (loginInfo == null) { 
      return RedirectToAction("Login"); 
     } 

     // Sign in this external identity if its already linked 
     var user = await UserManager.FindAsync(loginInfo.Login); 
     if (user != null) { 
      await SignInAsync(user, isPersistent: false); 
      return RedirectToLocal(returnUrl); 
     } 

    private async Task SignInAsync(ApplicationUser user, bool isPersistent) { 
     AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie); 
     var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie); 
     AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity); 
    } 

So müssen Sie in zusätzliche Daten an die SignIn passieren, was in etwa so aussehen:

ClaimsIdentity id = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie); 

Diese ClaimsIdentity erhält Ihren zusätzlichen Anspruch, und Sie müssen diesen Anspruch der Identität hinzufügen, die in der SignInAsync-Methode erstellt wurde, damit sie angezeigt wird.

+0

Hao, das ist mein Verständnis ... Wenn ich in ExternalLoginCallback debuggen ich aber „örtliche Behörde“ in AuthenticationManager keine Ansprüche sehen (oder Usermanager). Wo soll ich die Ansprüche sehen, die ich im obigen Code hinzugefügt habe? –

+0

Ich habe genau das gleiche Problem. Ich füge die Ansprüche hinzu und ich kann sehen, dass sie hinzugefügt werden, aber wenn ich versuche, sie später aus dem Kontext zu lesen, sehe ich nur einen einzigen LOCAL AUTHORITY Anspruch:/ –

+0

Die einzige Möglichkeit, die ich geschafft habe, ein bisschen von Informationen zu bekommen Startup.Auth Klasse ist über ein Cookie, das ist einfach schrecklich und müsste verschlüsselt werden. Die Sitzung ist nicht verfügbar und die AddClaim-Methode ist leer. Das Hinzufügen eines verschlüsselten Cookies scheint jedes Mal einfach falsch zu sein. –

0

Kurz gesagt der Linie, die einst AddClaim erforderlich verwendet wird, ist wie folgt:

von johns Genommen oben beantworten.

ClaimsIdentity ext = await AuthenticationManager.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie); 
Verwandte Themen