using System.Security; using System.Security.Claims; using System.Security.Policy; using System.Security.Principal; using System.Text; using System.Text.Unicode; using System.Threading.Tasks.Sources; using Microsoft.AspNetCore; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; using UAParser; namespace AuthStudy.Authentication.Browser { /// /// 浏览器认证 处理器 /// 可实现子接口 IAuthenticationRequestHandler, 以控制后续中间件是否执行. /// public class BrowserAuthenticationHandler : IAuthenticationHandler, IAuthenticationRequestHandler, IAuthenticationSignInHandler, IAuthenticationSignOutHandler where TOptions : AuthenticationSchemeOptions, new() { public const string DefaultAuthenticationScheme = BrowserAuthenticationDefault.AuthenticationSchemeName; public HttpContext? CurrentHttpContext; public List supportedBrowsers = new() { "Chrome", "Edge" }; /// /// 认证 /// public Task AuthenticateAsync() { var properties = new AuthenticationProperties(); properties.Items.Add("x-test", "测试"); //获取浏览器信息 CurrentHttpContext?.Request.Headers.TryGetValue("User-Agentx", out StringValues browserInfo); ClientInfo clientInfo = Parser.GetDefault().Parse(CurrentHttpContext?.Request.Headers["User-Agent"]); if (!supportedBrowsers.Contains(clientInfo.UA.Family)) { var success = AuthenticateResult.Fail($"不支持的浏览器:{clientInfo.UA.Family}", properties); return Task.FromResult(success); } //声明(身份项) var role = new Claim(ClaimTypes.Role, "Admin"); var email = new Claim(ClaimTypes.Email, "bicijinlian@168.com"); //声明集合 var Claims = new List(); Claims.Add(role); Claims.Add(email); //身份:包含声明集合,是声明集合的包装类,一个身份对应多个声明 var claimsIdentity = new ClaimsIdentity(Claims, DefaultAuthenticationScheme); //当事人/主角:是身份Identity的包装,对应多个身份 var claimsPrincipal = new ClaimsPrincipal(claimsIdentity); //票据:对Principal的包装,一对一 var ticket = new AuthenticationTicket(claimsPrincipal, DefaultAuthenticationScheme); //认证结果:认证信息会写入 当前请求的 User属性中,供下一个授权中间件使用 var result = AuthenticateResult.Success(ticket); //调用登陆 //CurrentHttpContext?.SignInAsync(BrowserAuthentication.DefaultAuthenticationScheme, claimsPrincipal, properties); return Task.FromResult(result); } /// /// 无认证:服务端向客户端(浏览器)发质询(要求提供一个新票据),质询体现为 htpp请求的响应。 /// public Task ChallengeAsync(AuthenticationProperties? properties) { properties?.Parameters.Add("x-itme", "无效的认证"); CurrentHttpContext!.Response.StatusCode = 401; if (CurrentHttpContext?.Response.Body.CanWrite ?? false) { var msg = UTF8Encoding.UTF8.GetBytes("认证无效"); CurrentHttpContext!.Response.Body.WriteAsync(msg); } CurrentHttpContext?.Items.Add("认证结束时间", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); return Task.CompletedTask; } /// /// 无权限:服务端向客户端(浏览器)发质询(要求提供一个新票据),质询体现为 htpp请求的响应。 /// public Task ForbidAsync(AuthenticationProperties? properties) { CurrentHttpContext!.Response.StatusCode = 403; if (CurrentHttpContext?.Response.Body.CanWrite ?? false) { var msg = UTF8Encoding.UTF8.GetBytes("无权访问"); CurrentHttpContext!.Response.Body.WriteAsync(msg); } return Task.CompletedTask; } /// /// IAuthenticationRequestHandler /// 返回true,立即反回,不执行后续中间件 /// /// public Task HandleRequestAsync() { return Task.FromResult(false); } /// /// 初始化 /// public async Task InitializeAsync(AuthenticationScheme scheme, Microsoft.AspNetCore.Http.HttpContext context) { //初始化工作,传递给认证方法和授权中间件 CurrentHttpContext = context; context.Items.Add("认证初始时间", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); await Task.CompletedTask; } /// /// 登陆方法 /// 写入Cookie和Session,认证信息持久化等 /// public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties? properties) { //导航到登陆页 CurrentHttpContext?.Response.Redirect("https://www.baidu.com"); return Task.CompletedTask; } /// /// 退出方法: 反操作登陆方法 /// 清除Cookie和Session,删除认证信息的持久化,作废票据等 /// public Task SignOutAsync(AuthenticationProperties? properties) { //导航到登陆页 CurrentHttpContext?.Response.Redirect("/api/auth/login"); return Task.CompletedTask; } } }