认证
认证是安全体系的第一道屏障。当访问者的请求进入的时候,认证体系通过验证对方提供的凭证来确定它的真实身份。认证体系只有在证实了访问者的真实身份之后才允许它进入。.NET Core提供了多种认证方式。但是它们的实现都是一样的。都是基于同一个认证模型的。
ASP.NET Core的认证功能是通过内置的一个认证组件来提供的。这个组件在处理分发给它的请求时会按照指定的认证方案从请求中提取能够验证用户真实身份的数据。我们一般把这种数据称为安全令牌。在ASP.NET Core应用下的安全令牌也叫做认证票据。
认证组件实现的整个流程涉及上图所示的三种针对认证票据的操作。也就是认证票据的颁发、验证、撤销。我们将这三种操作对应的角色称为认证票据的颁发者、验证者、撤销者。在大部分场景下这三种角色其实是由同一个主体来扮演的。
颁发认证票据的过程其实就是登录的操作。一般来说,用户试图通过登录应用以获取认证票据的时候需要提供可用来证明自身身份的用户凭证。最常见的用户凭证的就是用户名加密码。认证方在确定了对方真实身份之后就会颁发一个认证票据。这个票据携带的该用户有关的身份权限,以及其它相关的信息。一旦客户端拥有了由认证方颁发的认证票据。我们就可以按照双方协商的方式在请求种携带这个认证票据。并以此票据声明的身份执行目标操作, 或则访问目标资源。
一般来说,这个认证票据是有时效性的。一旦过期就会无效。我们有的时候会希望在过期之前就让认证票据无效。这就是所谓的注销操作。由撤销者来完成。
ASP.NET Core认证系统目的就在于构建一个标准的模型,用来完成针对请求的认证以及相关登录和注销操作。
示例:
public class demo21
{
private static readonly Dictionary<string, string> Account = new Dictionary<string, string>
{
{ "Admin","123"},
{ "UserA","123"},
{ "UserB","123"}
};
public static void Run()
{
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(
builder => builder
.ConfigureServices(
collection => collection
.AddRouting()
.AddAuthentication(
options => options
.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme
)
.AddCookie()
)
.Configure(app => app
.UseAuthentication()
.UseRouting()
.UseEndpoints(endpoints => {
endpoints.Map("/",RenderHomePageAsync);
endpoints.Map("Account/Login",SignInAsync);
endpoints.Map("Account/Logout",SignOutAsync);
})
)
)
.Build()
.Run();
}
public static async Task RenderHomePageAsync(HttpContext context)
{
if (context?.User?.Identity?.IsAuthenticated == true)
{
await context.Response.WriteAsync(
@"<html>
<head><title>Index</title></head>
<body>" +
$"<h3>Welcome {context.User.Identity.Name}</h3>" +
@"<a href='/Account/Logout'>Sign out</a>
</body>
</html>"
);
}
else
{
await context.ChallengeAsync();
}
}
public static async Task SignInAsync(HttpContext context)
{
if (string.CompareOrdinal(context.Request.Method, "GET") == 0)
{
await RenderLoginPageAsync(context, null, null, null);
}
else
{
var userName = context.Request.Form["username"];
var password = context.Request.Form["password"];
if (Account.TryGetValue(userName, out var pwd) && pwd == password)
{
var identity = new GenericIdentity(userName, "Passord");
var principal = new ClaimsPrincipal(identity);
await context.SignInAsync(principal);
}
else
{
await RenderLoginPageAsync(context, userName, password, "Invalid user name or password");
}
}
}
private static Task RenderLoginPageAsync(HttpContext context, string userName, string password,string errorMessage)
{
context.Response.ContentType = "text/html";
return context.Response.WriteAsync(
@"<html>
<head><title>Login</t