You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

155 lines
5.8 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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
{
/// <summary>
/// 浏览器认证 处理器
/// 可实现子接口 IAuthenticationRequestHandler, 以控制后续中间件是否执行.
/// </summary>
public class BrowserAuthenticationHandler<TOptions> :
IAuthenticationHandler, IAuthenticationRequestHandler, IAuthenticationSignInHandler, IAuthenticationSignOutHandler
where TOptions : AuthenticationSchemeOptions, new()
{
public const string DefaultAuthenticationScheme = BrowserAuthenticationDefault.AuthenticationSchemeName;
public HttpContext? CurrentHttpContext;
public List<string> supportedBrowsers = new() { "Chrome", "Edge" };
/// <summary>
/// 认证
/// </summary>
public Task<AuthenticateResult> 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<Claim>();
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);
}
/// <summary>
/// 无认证:服务端向客户端(浏览器)发质询(要求提供一个新票据),质询体现为 htpp请求的响应。
/// </summary>
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;
}
/// <summary>
/// 无权限:服务端向客户端(浏览器)发质询(要求提供一个新票据),质询体现为 htpp请求的响应。
/// </summary>
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;
}
/// <summary>
/// IAuthenticationRequestHandler
/// 返回true,立即反回,不执行后续中间件
/// </summary>
/// <returns></returns>
public Task<bool> HandleRequestAsync()
{
return Task.FromResult(false);
}
/// <summary>
/// 初始化
/// </summary>
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;
}
/// <summary>
/// 登陆方法
/// 写入Cookie和Session认证信息持久化等
/// </summary>
public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties? properties)
{
//导航到登陆页
CurrentHttpContext?.Response.Redirect("https://www.baidu.com");
return Task.CompletedTask;
}
/// <summary>
/// 退出方法: 反操作登陆方法
/// 清除Cookie和Session删除认证信息的持久化作废票据等
/// </summary>
public Task SignOutAsync(AuthenticationProperties? properties)
{
//导航到登陆页
CurrentHttpContext?.Response.Redirect("/api/auth/login");
return Task.CompletedTask;
}
}
}