首先,我们定义一个登录的页面以及登录成功后身体令牌的发放:
app.Map("/Account/Login", builder => builder.Run(async context => { if (context.Request.Method == "GET") { await context.Response.WriteHtmlAsync(async res => { await res.WriteAsync($"<form method=\"post\">"); await res.WriteAsync($"<input type=\"hidden\" name=\"returnUrl\" value=\"{HttpResponseExtensions.HtmlEncode(context.Request.Query["ReturnUrl"])}\"/>"); await res.WriteAsync($"<div class=\"form-group\"><label>用户名:<input type=\"text\" name=\"userName\" class=\"form-control\"></label></div>"); await res.WriteAsync($"<div class=\"form-group\"><label>密码:<input type=\"password\" name=\"password\" class=\"form-control\"></label></div>"); await res.WriteAsync($"<button type=\"submit\" class=\"btn btn-default\">登录</button>"); await res.WriteAsync($"</form>"); }); } else { var userStore = context.RequestServices.GetService<UserStore>(); var user = userStore.FindUser(context.Request.Form["userName"], context.Request.Form["password"]); if (user == null) { await context.Response.WriteHtmlAsync(async res => { await res.WriteAsync($"<h1>用户名或密码错误。</h1>"); await res.WriteAsync("<a class=\"btn btn-default\" href=\"/Account/Login\">返回</a>"); }); } else { var claimIdentity = new ClaimsIdentity("Cookie"); claimIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString())); claimIdentity.AddClaim(new Claim(ClaimTypes.Name, user.Name)); claimIdentity.AddClaim(new Claim(ClaimTypes.Email, user.Email)); claimIdentity.AddClaim(new Claim(ClaimTypes.MobilePhone, user.PhoneNumber)); claimIdentity.AddClaim(new Claim(ClaimTypes.DateOfBirth, user.Birthday.ToString())); var claimsPrincipal = new ClaimsPrincipal(claimIdentity); // 在上面注册AddAuthentication时,指定了默认的Scheme,在这里便可以不再指定Scheme。 await context.SignInAsync(claimsPrincipal); if (string.IsNullOrEmpty(context.Request.Form["ReturnUrl"])) context.Response.Redirect("/"); else context.Response.Redirect(context.Request.Form["ReturnUrl"]); } } }));如上,我们在Get请求中返回登录页面,在Post请求中验证用户名密码,匹配成功后,创建用户Claim, ClaimsIdentity, ClaimsPrincipal 最终通过SignInAsync方法将用户身份写入到响应Cookie中,完成身份令牌的发放。
授权我们在登录中间件后面添加一个自定义的授权中间件,用来禁用匿名用户的访问:
app.UseAuthorize();UseAuthorize的实现很简单,就是判断用户是否已通过认证,并跳过对首页的验证:
public static IApplicationBuilder UseAuthorize(this IApplicationBuilder app) { return app.Use(async (context, next) => { if (context.Request.Path == "/") { await next(); } else { var user = context.User; if (user?.Identity?.IsAuthenticated ?? false) { await next(); } else { await context.ChallengeAsync(); } } }); }其实上面的实现和我们在MVC5中常用的[Authorize]特性非常相似。
个人信息再定义一个认证后才能访问的页面,并把当前登录用户的信息展示出来:
app.Map("/profile", builder => builder.Run(async context => { await context.Response.WriteHtmlAsync(async res => { await res.WriteAsync($"<h1>你好,当前登录用户: {HttpResponseExtensions.HtmlEncode(context.User.Identity.Name)}</h1>"); await res.WriteAsync("<a class=\"btn btn-default\" href=\"/Account/Logout\">退出</a>"); await res.WriteAsync($"<h2>AuthenticationType:{context.User.Identity.AuthenticationType}</h2>"); await res.WriteAsync("<h2>Claims:</h2>"); await res.WriteTableHeader(new string[] { "Claim Type", "Value" }, context.User.Claims.Select(c => new string[] { c.Type, c.Value })); }); })); 退出