using System.Security.Claims; using System.Text.Encodings.Web; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; namespace NPin.Framework.AspNetCore.Authentication.OAuth; public abstract class OAuthAuthenticationHandler : AuthenticationHandler where TOptions : AuthenticationSchemeOptions, new() { public abstract string AuthenticationSchemeName { get; } // private AuthenticationScheme _scheme; protected IHttpClientFactory HttpClientFactory { get; } protected HttpClient HttpClient { get; } public OAuthAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, IHttpClientFactory httpClientFactory) : base(options, logger, encoder) { HttpClientFactory = httpClientFactory; HttpClient = httpClientFactory.CreateClient(); } /// /// Claims 转换为 票据 /// /// /// private AuthenticationTicket ConvertTicket(List claims) { var claimsIdentity = new ClaimsIdentity(claims.ToArray(), AuthenticationSchemeName); var principal = new ClaimsPrincipal(claimsIdentity); return new AuthenticationTicket(principal, AuthenticationSchemeName); } protected async Task SendHttpRequestAsync(string url, IEnumerable> query, HttpMethod? httpMethod = null) { httpMethod ??= HttpMethod.Get; var queryUrl = QueryHelpers.AddQueryString(url, query); HttpResponseMessage response = null; if (httpMethod == HttpMethod.Get) { response = await HttpClient.GetAsync(queryUrl); } else if (httpMethod == HttpMethod.Post) { response = await HttpClient.PostAsync(queryUrl, null); } if (response == null) { throw new NotSupportedException($"不支持的请求方式: {httpMethod}"); } var content = await response.Content.ReadAsStringAsync(); if (!response.IsSuccessStatusCode) { throw new Exception($"授权服务器请求错误,请求地址[{queryUrl}] 错误信息[{content}]"); } VerifyErrResponse(content); var model = JsonConvert.DeserializeObject(content); return model!; } protected virtual void VerifyErrResponse(string content) { AuthenticationErrCodeModel.VerifyErrResponse(content); } /// /// 获取登录票据 /// /// /// protected abstract Task> GetAuthTicketAsync(string code); protected override async Task HandleAuthenticateAsync() { if (!Context.Request.Query.ContainsKey("code")) { return AuthenticateResult.Fail("回调中未包含code参数"); } var code = Context.Request.Query["code"].ToString(); List authTicket; try { authTicket = await GetAuthTicketAsync(code); } catch (Exception ex) { return AuthenticateResult.Fail(ex.Message ?? "未知错误"); } // 获取登录票据成功 return AuthenticateResult.Success(ConvertTicket(authTicket)); } }