ASP.NET Core Identity 与基于声明的认证

在本文中,将探讨什么是基于声明的认证,ASP.NET Core Identity如何实现它,以及身份系统的整体工作原理。

ASP.NET Core Identity简介

ASP.NET Core Identity 是随 .NET Core 一起提供的新型会员系统。与之前的版本不同,它采用了基于声明的认证,这是与之前版本的 ASP.NET Identity 最大的不同之一。

在开始探索身份系统之前,需要先了解基于声明的认证

让考虑一个场景:Bob 是一名大学生,他去银行开户。银行经理想要看到一些能够证明 Bob 身份的文件。Bob 出示了他的驾照,上面有他的名字、出生日期和地址。

现在 Bob 还想申请银行只为学生提供的折扣。经理再次要求提供证明 Bob 是学生的文件。这次 Bob 出示了他的学生证,上面有他的名字、大学名称、系名称和学生编号。

这个现实生活中的场景可以用来类比基于声明的认证。在这里,Bob 是使用基于声明的认证的用户。他使用了两种身份(用户可以有多个身份)—— 驾照和学生证。如果身份附加了声明——比如名字、出生日期、学生编号等。

ASP.NET Core 的一个好处是它是开源的,如果需要,可以查看源代码以了解其工作原理。ASP.NET Core Identity的源代码可以在以下 GitHub 仓库中找到:

https://github.com/aspnet/Identity

在当前的 ASP.NET Core 实现中,用户是 ClaimsPrincipal 类型,它实现了 IPrincipal 接口。ClaimsPrincipal 类在 System.Security.Claims 命名空间下实现。

public class ClaimsPrincipal : IPrincipal { public virtual IIdentity Identity { get; } public virtual IEnumerable Identities { get; } public virtual IEnumerable Claims { get; } public virtual bool HasClaim(Predicate match); public virtual bool HasClaim(string type, string value); public virtual bool IsInRole(string role); }

从实现中可以看到,ClaimsPrincipal 类有一个 Identities 属性,它返回 ClaimsIdentity 的集合。这意味着用户可以有多个身份。

还有一个属性 Identity。不要被它迷惑,它返回与此 ClaimsPrincipal 关联的主要声明身份。另一个重要的属性是 Claims,它返回一个集合,包含与此 ClaimsPrincipal 关联的所有 ClaimsIdentity 的所有声明。

public class ClaimsIdentity : IIdentity { public virtual string AuthenticationType { get; } public virtual string Name { get; } public virtual bool IsAuthenticated { get; } public virtual IEnumerable Claims { get; } public virtual IEnumerable FindAll(Predicate match); public virtual Claim FindFirst(string type); public virtual bool HasClaim(string type, string value); }

AuthenticationType 返回类型,可能是 Basic、Windows、Cookie 等。Claims 属性返回与此身份关联的声明集合。

现在如果尝试将 Bob 的例子映射到这些类,它将看起来像这样:

ASP.NET Core Identity 实现了一些 API(如 SignInManager、UserManager、RoleManager 等),简化了与身份对象的交互。在 ASP.NET Core 项目中工作时,依赖注入将为这些类提供对象,以便可以使用它们。

例如,SignInManager 实现了以下公共方法来登录用户:

public virtual async Task SignInAsync(TUser user, AuthenticationProperties authenticationProperties, string authenticationMethod = null) { var userPrincipal = await CreateUserPrincipalAsync(user); if (authenticationMethod != null) { userPrincipal.Identities.First().AddClaim( new Claim(ClaimTypes.AuthenticationMethod, authenticationMethod)); } await Context.SignInAsync(IdentityConstants.ApplicationScheme, userPrincipal, authenticationProperties ?? new AuthenticationProperties()); }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485