身份标识是 .NET 安全体系中最最基础的概念,称为 Identity。在任何一个系统中,每一次对系统的访问应该都需要对其身份进行标识,例如游客。
身份标识好比一个人的身份证,有一个唯一的标识号码,例如你的身份证号,网站的邮箱、用户名等,能表明这个用户的身份信息。
在命名空间 System.Security.Principal
中,定义了一个接口 IIdentity
//
// 摘要:
// 定义标识对象的基本功能。
public interface IIdentity
{
//
// 摘要:
// 获取当前用户的名称。
//
// 返回结果:
// 以其名义运行代码的用户的名称。
string Name { get; }
//
// 摘要:
// 获取使用的身份验证的类型。
//
// 返回结果:
// 用于标识用户的身份验证的类型。
string AuthenticationType { get; }
//
// 摘要:
// 获取一个值,该值指示是否已验证用户。
//
// 返回结果:
// 如果用户已经过验证,则为 true;否则为 false。
bool IsAuthenticated { get; }
}
Name
:表示身份标识的唯一名称,例如用户名AuthenticationType
:作为认证的一种类型,比如 Windows 认证,数字证书认证等等IsAuthenticated
:用于判断该用户是否通过了认证,通俗而言就是是否登录这是最主要的一个接口,表示了身份标识的基本信息,你可以通过这个接口来扩展自己的身份标识。
可以容纳一个或多个身份标识的主体,一个系统只能有一个主体。
只能使用主体来将身份标识进行包裹,一个系统只能会有一个主体,且是线程隔离的。
//
// 摘要:
// Defines the basic functionality of a principal object.
public interface IPrincipal
{
//
// 摘要:
// Gets the identity of the current principal.
//
// 返回结果:
// The System.Security.Principal.IIdentity object associated with the current principal.
IIdentity Identity { get; }
//
// 摘要:
// Determines whether the current principal belongs to the specified role.
//
// 参数:
// role:
// The name of the role for which to check membership.
//
// 返回结果:
// true if the current principal is a member of the specified role; otherwise, false.
bool IsInRole(string role);
}
IPrincipal
接口只有一个 IIdentity
的接口,说明主体包含了一个标识;IsInRole
这个方法用于判断当前标识的角色;顾名思义就是 Windows 的主体和标识。
可以通过这两个对象直接拿到当前登录到 Windows 的账号信息。
以下是示例代码:
static void Main(string[] args)
{
var user = WindowsIdentity.GetCurrent();
Console.WriteLine("计算机名称:{0}",user.Name);
Console.WriteLine("系统账户:{0}", user.IsSystem);
Console.WriteLine("游客账户:{0}", user.IsGuest);
Console.WriteLine("----声明----");
foreach (var item in user.Claims)
{
Console.WriteLine("{0}:{1}", item.Type, item.Value);
}
}
表示很广泛的主体和标识,可以自由进行应用。
var identity = new GenericIdentity("张三");
Console.WriteLine(identity.Name); //输出张三
//添加其他字段
identity.AddClaim(new Claim("email", "[email protected]"));
identity.AddClaim(new Claim("mobile", "1861943821"));
identity.AddClaim(new Claim("nationality", "中国"));
基于声明的主体和标识。这是目前最广泛的使用,以上两种类型都是从这个实例派生。
你可以把声明理解成一个字典,不同字典的是Key可以重复。
基于声明的技术可以用于可以动态的创建字段。
var claimIdentity = new ClaimsIdentity();
claimIdentity.AddClaim(new Claim("username", "张三"));
claimIdentity.AddClaim(new Claim("email", "[email protected]"));
claimIdentity.AddClaim(new Claim("mobile", "1861943821"));
claimIdentity.AddClaim(new Claim("nationality", "中国"));
claimIdentity.AddClaim(new Claim("role", "管理员"));
claimIdentity.AddClaim(new Claim("role", "普通用户"));
var claimPricipal = new ClaimsPrincipal(claimIdentity);
Console.WriteLine(claimPricipal.FindFirst("username"));
Console.WriteLine(claimPricipal.FindFirst("email"));
foreach (var item in claimPricipal.FindAll("role"))
{
Console.WriteLine("{0}:{1}", item.Type, item.Value);
}
通过 FindFirst
或 FindAll
方法查找类型(Key)的声明。
你可以根据自己的需要自定义适合自己的主体和标识。
IIdentity
接口以实现自己的标识类。IPrincipal
接口以实现自己的主体类。以下是示例代码:
public class MyIdentity : IIdentity
{
public MyIdentity(string name,string role)
{
Name = name;
Role = role;
}
public string AuthenticationType => "自定义";
public bool IsAuthenticated => !string.IsNullOrEmpty(Name);
public string Name { get; }
public string Role { get; }
}
public class MyPrincipal : IPrincipal
{
private readonly MyIdentity _identity;
public MyPrincipal(MyIdentity identity)
{
_identity = identity;
}
public IIdentity Identity => _identity;
public bool IsInRole(string role)
{
return _identity.Role == role;
}
}
使用方式:
var myIdentity = new MyIdentity("张三", "管理员");
var myPrincipal = new MyPrincipal(myIdentity);
Console.WriteLine("姓名:{0}",myPrincipal.Identity.Name);
Console.WriteLine("是管理员吗:{0}", myPrincipal.IsInRole("管理员"));
在整个 .NET 框架中会,当你需要用到内置的用户标识时,你会看到已经被定义好了的 IPrincipal
接口或 IIdentity
接口,例如 MVC 中的 User
对象:
通过 User.Identity.IsAuthenticated
判断是否登录,通过 User.Identity.Name
获取用户名。
我看到很多同学都是自己定义 UserInfo
类似的对象来保存当前登录用户,比如存在 Session 或 Cookie 中。如果你能很好的理解底层原理,你可以很轻松的利用本来就设计好的用户体系,包括微软的 Identity 框架。
下一章,将手把手教你前后端分离所使用的 JWT 和 Identity 的配合。