BasicAuthenticationHandler.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. using Microsoft.AspNetCore.Authentication;
  2. using Microsoft.AspNetCore.Authorization;
  3. using Microsoft.AspNetCore.Builder;
  4. using Microsoft.AspNetCore.Http;
  5. using Microsoft.AspNetCore.Http.Features;
  6. using Microsoft.Extensions.DependencyInjection;
  7. using Microsoft.Extensions.Logging;
  8. using Microsoft.Extensions.Options;
  9. using System;
  10. using System.Net.Http.Headers;
  11. using System.Security.Claims;
  12. using System.Text.Encodings.Web;
  13. using System.Threading.Tasks;
  14. using XYY.Common.Standard;
  15. using XYY.Core.Standard.Data.Infrastructure;
  16. using XYY.Model.Standard;
  17. using XYY.Service.Standard.UserService;
  18. namespace XYY.Authentication.Standard
  19. {
  20. public static class BasicAuthenticationScheme
  21. {
  22. public const string DefaultScheme = "Basic";
  23. }
  24. public class BasicAuthenticationOption : AuthenticationSchemeOptions
  25. {
  26. }
  27. /// <summary>
  28. /// API服务中间证
  29. /// 认证token
  30. /// </summary>
  31. public class BasicAuthenticationHandler : AuthenticationHandler<BasicAuthenticationOption>
  32. {
  33. private readonly BasicAuthenticationOption authOptions;
  34. private readonly IUserService userService;
  35. private readonly IUnitOfWork unitOfWork;
  36. public BasicAuthenticationHandler(
  37. IOptionsMonitor<BasicAuthenticationOption> options,
  38. ILoggerFactory logger,
  39. UrlEncoder encoder,
  40. ISystemClock clock,
  41. IUserService userService,
  42. IUnitOfWork unitOfWork)
  43. : base(options, logger, encoder, clock)
  44. {
  45. authOptions = options.CurrentValue;
  46. this.userService = userService;
  47. this.unitOfWork = unitOfWork;
  48. }
  49. public Endpoint GetEndpoint(HttpContext context)
  50. {
  51. if (context == null)
  52. {
  53. return null;
  54. }
  55. return context.Features.Get<IEndpointFeature>()?.Endpoint;
  56. }
  57. /// <summary>
  58. /// 认证 Token
  59. /// </summary>
  60. /// <returns></returns>
  61. protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
  62. {
  63. bool isAllow = false;
  64. var endpoint = GetEndpoint(this.Context);
  65. if (endpoint != null)
  66. {
  67. var allow = endpoint.Metadata.GetMetadata<IAllowAnonymous>();
  68. if (allow != null)
  69. {
  70. isAllow = true;
  71. }
  72. }
  73. else
  74. {
  75. var claims = new[]
  76. {
  77. new Claim(ClaimTypes.StreetAddress,""),
  78. };
  79. var identity = new ClaimsIdentity(claims, Scheme.Name);
  80. var principal = new ClaimsPrincipal(identity);
  81. var ticket = new AuthenticationTicket(principal, Scheme.Name);
  82. unitOfWork.CurrentName = "";
  83. return await Task.FromResult(AuthenticateResult.Success(ticket));
  84. }
  85. if (isAllow || Request.Path.Value.Contains("dingtalk") || Request.Path.Value.Contains("SendNowCustomerQuotaion", StringComparison.InvariantCultureIgnoreCase))
  86. {
  87. var claims = new[]
  88. {
  89. new Claim(ClaimTypes.StreetAddress,""),
  90. };
  91. var identity = new ClaimsIdentity(claims, Scheme.Name);
  92. var principal = new ClaimsPrincipal(identity);
  93. var ticket = new AuthenticationTicket(principal, Scheme.Name);
  94. unitOfWork.CurrentName = "";
  95. return await Task.FromResult(AuthenticateResult.Success(ticket));
  96. }
  97. if (!Request.Headers.ContainsKey("Authorization"))
  98. {
  99. if (string.IsNullOrEmpty(Request.Query["access_token"]))
  100. {
  101. return AuthenticateResult.Fail("Missing Authorization ");
  102. }
  103. }
  104. try
  105. {
  106. string token = "";
  107. //var uservice = Context.RequestServices.GetService<IUserService>();
  108. if (Request.Headers.ContainsKey("Authorization"))
  109. {
  110. var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
  111. //var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
  112. if (!authHeader.Scheme.Equals("token", StringComparison.InvariantCultureIgnoreCase)
  113. && !authHeader.Scheme.Equals("bearer", StringComparison.InvariantCultureIgnoreCase))
  114. {
  115. return AuthenticateResult.Fail("Invalid Token");
  116. }
  117. else
  118. {
  119. token = authHeader.Parameter;
  120. }
  121. }
  122. else
  123. {
  124. token = Request.Query["access_token"];
  125. }
  126. var user = await Authorized(token);
  127. if (user != null)
  128. {
  129. ///当前用户的身份信息
  130. var claims = new[]
  131. {
  132. new Claim(ClaimTypes.StreetAddress,token),
  133. new Claim(ClaimTypes.NameIdentifier,user.Id.ToString()),
  134. new Claim(ClaimTypes.Name,user.NiceName),
  135. new Claim(ClaimTypes.GroupSid,user.CustomerId.ToString()),
  136. new Claim(ClaimTypes.Role,string.Join(",",user.Roles)),
  137. new Claim(ClaimTypes.AuthorizationDecision,string.Join(",",user.PrivilegeUrl))
  138. };
  139. var identity = new ClaimsIdentity(claims, Scheme.Name);
  140. var principal = new ClaimsPrincipal(identity);
  141. var ticket = new AuthenticationTicket(principal, Scheme.Name);
  142. unitOfWork.CurrentName = user.NiceName;
  143. return await Task.FromResult(AuthenticateResult.Success(ticket));
  144. }
  145. else
  146. {
  147. return AuthenticateResult.Fail("token无效");
  148. }
  149. }
  150. catch
  151. {
  152. return AuthenticateResult.Fail("Invalid Authorization Header");
  153. }
  154. }
  155. /// <summary>
  156. /// 质询
  157. /// </summary>
  158. /// <param name="properties"></param>
  159. /// <returns></returns>
  160. protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
  161. {
  162. //Response.Headers["WWW-Authenticate"] = $"Basic realm=our site";
  163. await base.HandleChallengeAsync(properties);
  164. }
  165. /// <summary>
  166. /// 认证失败
  167. /// </summary>
  168. /// <param name="properties"></param>
  169. /// <returns></returns>
  170. protected override async Task HandleForbiddenAsync(AuthenticationProperties properties)
  171. {
  172. await base.HandleForbiddenAsync(properties);
  173. }
  174. private async Task<UserContent> Authorized(string token)
  175. {
  176. var ui = await userService.GetUserContentAtApi(token);
  177. return ui;
  178. }
  179. }
  180. public static class BasicAuthentication
  181. {
  182. public static void UseBasicAuthentication(this IApplicationBuilder app)
  183. {
  184. app.UseMiddleware<BasicAuthenticationMiddleware>();
  185. }
  186. }
  187. public class BasicAuthenticationMiddleware
  188. {
  189. private readonly RequestDelegate _next;
  190. private readonly ILogger _logger;
  191. public BasicAuthenticationMiddleware(RequestDelegate next, ILoggerFactory LoggerFactory)
  192. {
  193. _next = next;
  194. _logger = LoggerFactory.CreateLogger<BasicAuthenticationMiddleware>();
  195. }
  196. public async Task Invoke(HttpContext httpContext, IAuthenticationService authenticationService)
  197. {
  198. var authenticated = await authenticationService.AuthenticateAsync(httpContext, BasicAuthenticationScheme.DefaultScheme);
  199. //authenticated.Principal.Claims.
  200. //_logger.LogInformation("Access Status:" + authenticated.Succeeded);
  201. if (!authenticated.Succeeded)
  202. {
  203. await authenticationService.ForbidAsync(httpContext, BasicAuthenticationScheme.DefaultScheme, new AuthenticationProperties { });
  204. return;
  205. }
  206. await _next(httpContext);
  207. }
  208. }
  209. }