aspnet-core-系列15-自定义Identity

3次阅读

共计 7708 个字符,预计需要花费 20 分钟才能阅读完成。

0. 前言

在之前的文章中简略介绍了一下 asp.net core 中的 Identity,这篇文章将持续针对 Identity 进行进一步的开展。

1. 给 Identity 增加额定的信息

在《【asp.net core 系列】13 Identity 身份验证入门》一文中,咱们大略理解了如何应用 Identity,以及如何保留一些信息以便后续的验证。这里咱们将深刻讨论一下如何给 Identity 增加更多的信息。

咱们晓得在给 Identity 增加数据的时候,须要增加一个 Claim 对象。咱们先回顾一下 Claim 的信息,Claim 的属性大多只提供了公开的 get 拜访器,所以这个类的重点在于构造方法:

public class Claim
{
    // 根底的
    public Claim(string type, string value);
    public Claim(string type, string value, string valueType);
    public Claim(string type, string value, string valueType, string issuer);
    public Claim(string type, string value, string valueType, string issuer, string originalIssuer);
    //
    public Claim(BinaryReader reader);
    public Claim(BinaryReader reader, ClaimsIdentity subject);
}

暂且看一下几个应用字符类型的结构函数参数:

  1. type Claim 的类型,反对自定义,但 asp.net core 提供了一个根底的类型定义:
public static class ClaimTypes
{
    // 暗藏其余属性
    public const string Name = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name";
    public const string Role = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role";
}

​ 这个类里定义了大多数状况下会用到的 Claims 的类型。

  1. value 寄存 Claim 的值,通常状况下不对这个值进行束缚
  2. valueType 示意 value 的类型,取值范畴参考类:

    public static class ClaimValueTypes
    {
        public const string Base64Binary = "http://www.w3.org/2001/XMLSchema#base64Binary";
        public const string UpnName = "http://schemas.xmlsoap.org/claims/UPN";
        public const string UpnName = "http://schemas.xmlsoap.org/claims/UPN";
         public const string UInteger32 = "http://www.w3.org/2001/XMLSchema#uinteger32";
        public const string Time = "http://www.w3.org/2001/XMLSchema#time";
        public const string String = "http://www.w3.org/2001/XMLSchema#string";
        public const string Sid = "http://www.w3.org/2001/XMLSchema#sid";
        public const string RsaKeyValue = "http://www.w3.org/2000/09/xmldsig#RSAKeyValue";
        public const string Rsa = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/rsa";
        public const string Rfc822Name = "urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name";
        public const string KeyInfo = "http://www.w3.org/2000/09/xmldsig#KeyInfo";
        public const string Integer64 = "http://www.w3.org/2001/XMLSchema#integer64";
        public const string X500Name = "urn:oasis:names:tc:xacml:1.0:data-type:x500Name";
        public const string Integer32 = "http://www.w3.org/2001/XMLSchema#integer32";
        public const string HexBinary = "http://www.w3.org/2001/XMLSchema#hexBinary";
        public const string Fqbn = "http://www.w3.org/2001/XMLSchema#fqbn";
        public const string Email = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress";
        public const string DsaKeyValue = "http://www.w3.org/2000/09/xmldsig#DSAKeyValue";
        public const string Double = "http://www.w3.org/2001/XMLSchema#double";
        public const string DnsName = "http://schemas.xmlsoap.org/claims/dns";
        public const string DaytimeDuration = "http://www.w3.org/TR/2002/WD-xquery-operators-20020816#dayTimeDuration";
        public const string DateTime = "http://www.w3.org/2001/XMLSchema#dateTime";
        public const string Date = "http://www.w3.org/2001/XMLSchema#date";
        public const string Boolean = "http://www.w3.org/2001/XMLSchema#boolean";
        public const string Base64Octet = "http://www.w3.org/2001/XMLSchema#base64Octet";
        public const string Integer = "http://www.w3.org/2001/XMLSchema#integer";
        public const string YearMonthDuration = "http://www.w3.org/TR/2002/WD-xquery-operators-20020816#yearMonthDuration";
    }
  3. issuer 用来寄存 Claim 的发布者,默认值是:ClaimsIdentity.DefaultIssuer 该值容许在构造函数是传 NULL,一旦传 NULL,则主动认为是 ClaimsIdentity.DefaultIssuer
  4. originalIssuer Claim 的原公布人,如果不给值,则默认与 issuer 统一。

这是从构造函数以及相干文档中获取到的。

对于 ClaimTypes 里我只贴了两个,起因是这两个值在 Claim 中是两个必不可少的值。依据属性名就能看进去,一个是设置用户的名称,一个是设置用户的角色。

那么,持续摸索 Claim 里的属性和办法:

public class Claim
{public string Type { get;}
    public ClaimsIdentity Subject {get;}
    public IDictionary<string, string> Properties {get;}
    public string OriginalIssuer {get;}
    public string Issuer {get;}
    public string ValueType {get;}
    public string Value {get;}
    public virtual Claim Clone();
    public virtual Claim Clone(ClaimsIdentity identity);
    public virtual void WriteTo(BinaryWriter writer);
}

几个根本属性都是从构造函数中获取的,这里就不做过多的介绍了。不过值得注意的一点是,Properties 这个属性的值获取是须要应用

public Claim(BinaryReader reader, ClaimsIdentity? subject)

这个构造方法才能够无效的对其进行赋值,所以这个属性并没有太多值得关注的中央。

介绍完了 Claim 类之后,咱们持续看一下 Identity 相干的罕用类:

public class ClaimsIdentity : IIdentity;

通过这个类的申明,咱们能够看出它实现了接口:

public interface IIdentity
{string? AuthenticationType { get;}
    bool IsAuthenticated {get;}
    string? Name {get;}
}

其中

  • AuthenticationType 示意验证类型
  • IsAuthenticated 示意是否验证通过
  • Name 寄存的用户名

这是 Identity 里最要害的三个属性,贯通着整个 Identity 体系。咱们持续看一下 ClaimsIdentity 的几个关键点:

public class ClaimsIdentity : IIdentity
{public ClaimsIdentity(string authenticationType);
    public ClaimsIdentity(IIdentity identity);
    public ClaimsIdentity(IEnumerable<Claim> claims);
    public ClaimsIdentity(IEnumerable<Claim> claims, string authenticationType);
    public ClaimsIdentity(IIdentity identity, IEnumerable<Claim> claims);
    public virtual void AddClaim(Claim claim);
    public virtual void AddClaims(IEnumerable<Claim> claims);
}

对于 ClaimsIdentity 而言,其核心内容是 Claim 实例。咱们通常须要结构 Claim 对象,在 Claim 对象中增加咱们想增加的值,而后装入 ClaimIdentity 中。这里有一个值须要额定留神一下:AuthenticationType 示意验证类型,值并没有额定要求,不过对于应用 Cookie 作为信息保留的话,须要设置值为:

CookieAuthenticationDefaults.AuthenticationScheme

这时候,咱们曾经取得了一个 Identity 对象,在 asp.net core 中 Identity 体系还有最初一个要害类:

public class ClaimsPrincipal : IPrincipal
{public ClaimsPrincipal();
    public ClaimsPrincipal(IIdentity identity);
    public ClaimsPrincipal(IPrincipal principal);
    public virtual void AddIdentities(IEnumerable<ClaimsIdentity> identities);
    public virtual void AddIdentity(ClaimsIdentity identity);
}

这个类提供了几个办法用来存储 Identity,这个类在 IPrincipal 根底上以 Identity 为根底数据。这一点能够通过构造函数和它提供的一些办法能够确认。

2. 读取 Identity 的信息

在第一大节中,我简略介绍了一下如何利用 Claim 和 ClaimsIdentity 以及 ClaimsPrincipal 这三个类来存储用户信息以及咱们想要的数据。这里咱们看一下如何通过 Principal 读取信息,以及简略分析一下背地的逻辑。

咱们应用 HttpContext 的扩大办法:

public static Task SignInAsync(this HttpContext context, ClaimsPrincipal principal);

将咱们设置的 principal 数据保留,所保留的中央取决于咱们在 Startup.cs 中的设置。在该系列中,咱们启用了 Cookie,所以这个信息会以 Cookie 的模式保留。

在控制器外部时,Controller 类为咱们提供了一个属性:

public ClaimsPrincipal User {get;}

通过这个属性能够反向获取到咱们保留的 Principal 实例。

接下来,让咱们反向解析出 Principal 外面的数据:

public interface IPrincipal
{IIdentity? Identity { get;}
    bool IsInRole(string role);
}

IPrincipal 提供了两个根底数据和办法,一个是获取一个 Identity 对象,一个是判断是否是某个角色。

2.1 Identity

在 ClaimPrincipal 中,Identity 属性的默认取值逻辑是:

if (identities == null)
{throw new ArgumentNullException(nameof(identities));
}

foreach (ClaimsIdentity identity in identities)
{if (identity != null)
    {return identity;}
}

return null;

也就是获取 Principal 中第一个不为 Null 的 Identity 对象,这个取值逻辑能够通过上面的属性进行批改:

public static Func<IEnumerable<ClaimsIdentity>, ClaimsIdentity?> PrimaryIdentitySelector {get; set;}

2.2 IsInRole

在 Principal 中,通常会寄存一至多个 Identity 对象,每个 Identity 对象有一至多个 Claim 对象。当有 Claim 对象的 Type 值与 Identity 对象的:

public string RoleClaimType {get;}

值统一时,就会被认为该 Claim 外面寄存着角色信息,这时候会通过传入的 role 值与 Claim 的 Value 进行比拟。

比拟的办法是 Identity 的实例办法 HasClaim:

public virtual bool HasClaim(string type, string value);

如果初始化 Identity 时,没有手动设置 roleType 参数,那么这个参数取值就是:

public const string DefaultRoleClaimType = ClaimTypes.Role;

通常状况下,不会独自设置 roleType。

2.3 IsAuthenticated 判断是否登录

这个属性并不是 ClaimPrincipal 的,而是 ClaimIdentity 的。通常在 asp.net core 中会应用这个属性判断访问者是否实现了身份校验。这个属性的判断逻辑也很简略:

public virtual bool IsAuthenticated
{get { return !string.IsNullOrEmpty(AuthenticationType); }
}

也就是说,在 Identity 中指定了 AuthenticationType 就会认为实现了身份校验。

通常的应用形式:

User.Identity.IsAuthenticated

通过以上调用链进行数据调用。

2.4 Name

与 IsAuthenticatedy 一样,这个属性也是 ClaimIdentity 的。与 IsInRole 的判断根据相似,这个属性会获取 Identity 中寄存的 Claim 汇合中第一个 RoleType 为 ClaimType.Name 的 Claim,而后取值。

所以,在实现登录的时候,如果想要可能通过:

User.Identity.Name

获取一个用户名信息或者其余名称信息的话,则须要设置一个 Type 等于:

public const string DefaultNameClaimType = ClaimTypes.Name;

的 Claim 实例对象。

2.5 获取 Claim

在 Principal 体系中,最重要也是最根底的数据就是 Claim 对象。对于 ClaimPrincipal 对象来说,外面必然会寄存多个 Claim 对象。那么,咱们就须要有操作 Claim 对象的办法:

public virtual IEnumerable<Claim> Claims {get;}

通过这个办法能够取得 ClaimPrincipal 里所有的 Claim 对象,这是一个迭代器对象。

public virtual IEnumerable<Claim> FindAll(Predicate<Claim> match);

通过一个选择器筛选出符合条件的 Claim 汇合。

public virtual IEnumerable<Claim> FindAll(string type);

查问所有合乎类型的 Claim 对象。

public virtual Claim FindFirst(string type);

查找第一个 Type 值与指定值雷同的 Claim 对象。

public virtual bool HasClaim(Predicate<Claim> match);

查问是否存在符合条件的 Claim 对象。

public virtual bool HasClaim(string type, string value);

查问是否有 Type 和 Value 属性均等于指定值的 Claim 对象。

这些办法都是 ClaimPrincipal 里的,绝对应的 ClaimIdentity 里也提供了相似的办法这里就不做介绍了。

3. 总结

这一章介绍了如何利用 Claim 进行用户信息保留,以及惯例的一些应用逻辑。下一章,咱们将持续摸索如何利用咱们本人设置的 Identity 以达到咱们的目标。

更多内容烦请关注我的博客《高学生小屋》

正文完
 0