2014-07-17 7 views
6

Ich entwickle eine Webanwendung mit Asp.Net 5 MVC, Owin und Oauth2-Bearer-Token als Auth-Typ.Komplexe Anspruchswerte in .NET Framework mit System.Security.Claims

this guide Nach, die einen benutzerdefinierten komplexen Anspruch Json serialisiert zu einer Instanz von Microsoft.IdentityModel.Claims.ClaimsIdentity mit Erfolg fügt hinzu, habe ich versucht, das gleiche Beispiel mit dem ClaimsIdentity auf dem System.Security.Claims Namespace zu replizieren.

Unglücklicherweise scheint es, dass durch das Hinzufügen einer complexClaim zu der ClaimsIdentity Instanz die Information des abgeleiteten Klassentyps verloren geht und der Anspruch als gespeichert wird.

var complexClaim = new ComplexClaim<UKPassport>(@"http://it.test/currentpassport", passport); 
var claims = new List<Claim>() { complexClaim }; 
identity.AddClaims(claims); 

Wenn ich versuche, die Behauptung von Identität zurück zu bekommen, es zu einem ComplexClaim<UKPassport> Typ führt zu einem Nullwert zu werfen.

var passportClaim = identity.Claims.FirstOrDefault<Claim>(c=>c.Type == @"http://it.test/currentpassport") as ComplexClaim<UKPassport>; 

Das gleiche Beispiel funktioniert perfekt mit Microsoft.IdentityModel.Claims.

Irgendwelche Hinweise? Hier

ist die komplette portierten Code:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using Newtonsoft.Json; 
using System.Security.Claims; 

namespace ConsoleApplication1 
{ 
    class Program { 
    private static ClaimsIdentity identity = new ClaimsIdentity(); 

    static void Main(string[] args) 
    { 
     var oldPassport = CreatePassport(); 
     identity.AddPassport(oldPassport); 

     var britishCitizen = identity.IsBritishCitizen(); 
     var hasExpired = identity.IsCurrentPassportExpired(); 
     Console.WriteLine(hasExpired); 
     Console.ReadLine(); 
    } 

    private static UKPassport CreatePassport() 
    { 
     var passport = new UKPassport(
      code: PassportCode.GBR, 
      number: 123456789, 
      expiryDate: DateTime.Now); 

     return passport; 
    } 
} 

    public static class ClaimsIdentityExtensions { 
    public static void AddPassport(this ClaimsIdentity identity, UKPassport passport) 
    { 
     var complexClaim = new ComplexClaim<UKPassport>(@"http://it.test/currentpassport", passport); 

     var claims = new List<Claim>() { complexClaim }; 
     identity.AddClaims(claims); 
    } 

    public static bool IsCurrentPassportExpired(this ClaimsIdentity identity) 
    { 
     var passport = GetPassport(identity, @"http://it.test/currentpassport"); 
     return DateTime.Now > passport.ExpiryDate; 
    } 

    public static bool IsBritishCitizen(this ClaimsIdentity identity) 
    { 
     var passport = GetPassport(identity, @"http://it.test/currentpassport"); 
     return passport.Code == PassportCode.GBR; 
    } 

    private static UKPassport GetPassport(this ClaimsIdentity identity, string passportType) 
    { 
     var passportClaim = identity.Claims.FirstOrDefault<Claim>(c=>c.Type == @"http://it.test/currentpassport") as ComplexClaim<UKPassport>; 
     return passportClaim.Value; 
    } 
} 

    public enum PassportCode 
    { 
     GBR, 

     GBD, 

     GBO, 

     GBS, 

     GBP, 

     GBN 
    } 


    public class ComplexClaim<T> : Claim where T : ClaimValue 
    { 
     public ComplexClaim(string claimType, T claimValue) 
      : this(claimType, claimValue, string.Empty) 
     { 
     } 

     public ComplexClaim(string claimType, T claimValue, string issuer) 
      : this(claimType, claimValue, issuer, string.Empty) 
     { 
     } 

     public ComplexClaim(string claimType, T claimValue, string issuer, string originalIssuer) 
      : base(claimType, claimValue.ToString(), claimValue.ValueType(), issuer, originalIssuer) 
     { 
     } 

     public new T Value 
     { 
      get 
      { 
       return JsonConvert.DeserializeObject<T>(base.Value); 
      } 
     } 
    } 

    public class UKPassport : ClaimValue 
    { 
     public const string Name = "UKPassport"; 

     private readonly PassportCode code; 
     private readonly int number; 
     private readonly DateTime expiryDate; 

     public UKPassport(PassportCode code, int number, DateTime expiryDate) 
     { 
      this.code = code; 
      this.number = number; 
      this.expiryDate = expiryDate; 
     } 

     public PassportCode Code { get { return this.code; } } 
     public int Number { get { return this.number; } } 
     public DateTime ExpiryDate { get { return this.expiryDate; } } 

     public override string ValueType() 
     { 
      return @"http://it.test/currentpassport"; 
     } 
    }  

public abstract class ClaimValue { 
    public abstract string ValueType(); 

    public override string ToString() 
    { 
     return JsonConvert.SerializeObject(this); 
    } 
} 
} 

Antwort

7

Dies wird nicht unterstützt noch empfohlen - Ansprüche sind der Schlüssel/Wert-Paare - halten sie so einfach wie möglich.

Es gibt eine Reihe von Klassen in .NET unterstützt, die nicht verarbeiten kann, was Sie (die SAM, CookieMiddleware usw.) ..

siehe auch hier http://leastprivilege.com/2012/10/08/custom-claims-principals-in-net-4-5/

+0

ich einige Ihrer Antworten und einen Blog gelesen haben, aber ich bin immer noch nicht sicher über ein hier beschriebenes Szenario http://stackoverflow.com/questions/39380623/complex-claims-in-jwt wo wir als Teil der Benutzeridentität seine Rollen für verschiedene Unternehmen haben wollen. Das scheint mir ein Teil der Information über "wer ein Benutzer ist" zu sein, aber es würde eine komplexe JWT erfordern, die dir nicht sehr gefällt. – iberodev

1

Die Besetzung zu erreichen versuchen in GetPassport versucht, vom Basistyp Claim in den abgeleiteten Typ ComplexClaim<UKPassport> zu konvertieren, was zu null führt. Sie benötigen einen Cast-Operator schreiben Claim-UKPassport

public static explicit operator UKPassport(Claim c) 
{ 
    return (c == null ? null:JsonConvert.DeserializeObject<UKPassport> (c.Value)); 
}  

und GetPassport zu konvertieren wird

private static UKPassport GetPassport(this ClaimsIdentity identity, string passportType) 
{ 
    return (UKPassport)identity.Claims.FirstOrDefault<Claim>(c => c.Type == @"http://it.test/currentpassport"); 
}