.NET Framework中的复杂声明值与System.Security.Claims

我正在使用Asp.Net 5 MVC,Owin和Oauth2 bearer token作为auth类型开发一个Web应用程序。

按照本指南将Json序列化的自定义复杂声明成功添加到Microsoft.IdentityModel.Claims.ClaimsIdentity实例,我尝试使用System.Security.Claims命名空间上的ClaimsIdentity复制相同的示例。

不幸的是,似乎将一个complexClaim添加到ClaimsIdentity实例,派生的类类型信息将丢失,并且声明将存储为System.Security.Claims.Claim

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

当我尝试从身份中取回声明时,将其转换为ComplexClaim Type会产生空值。

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

相同的示例使用Microsoft.IdentityModel.Claims完美运行。

任何提示?

这是完整的移植代码:

 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(@"http://it.test/currentpassport", passport); var claims = new List() { 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(c=>c.Type == @"http://it.test/currentpassport") as ComplexClaim; return passportClaim.Value; } } public enum PassportCode { GBR, GBD, GBO, GBS, GBP, GBN } public class ComplexClaim : 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(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); } } } 

这不是支持也不是建议 – 声明是键/值对 – 保持它们尽可能简单。

.NET中有许多支持类无法处理您要实现的目标(SAM,CookieMiddleware等)。

另见http://leastprivilege.com/2012/10/08/custom-claims-principals-in-net-4-5/

GetPassport中的GetPassport转换尝试从基类型Claim转换为派生类型ComplexClaim ,这将导致null。 您需要编写一个UKPassport转换操作符来将Claim转换为UKPassport

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

GetPassport将是

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