使用System.Security.Claims实现.net框架中的复杂索赔值

本文关键字:复杂 框架 Security System Claims 实现 net 使用 | 更新日期: 2023-09-27 18:13:20

我正在开发一个web应用程序与Asp。. Net 5 MVC, Owin和Oauth2承载令牌作为验证类型。

按照这个成功地将自定义复杂索赔Json序列化到Microsoft.IdentityModel.Claims.ClaimsIdentity实例的指南,我尝试在System.Security.Claims名称空间上使用ClaimsIdentity复制相同的示例。

不幸的是,将complexClaim添加到ClaimsIdentity实例中,派生的类类型信息丢失,而声明被存储为System.Security.Claims.Claim

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

当我试图从身份中获取声明时,将其转换为ComplexClaim<UKPassport>类型会导致null值。

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

同样的例子使用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<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);
    }
}
}

使用System.Security.Claims实现.net框架中的复杂索赔值

这是不支持也不推荐的-声明是键/值对-保持它们尽可能简单。

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

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

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

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

GetPassport将是

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