AuthenticationMiddleware.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. using ERP.Framework.Cache;
  2. using ERP.Framework.Config;
  3. using ERP.Framework.Constants;
  4. using ERP.Framework.Exceptions;
  5. using ERP.Framework.Resource;
  6. using ERP.Framework.Security;
  7. using ERP.Framework.Utils;
  8. using ERP.Framework.WebApi;
  9. using Microsoft.AspNetCore.Builder;
  10. using Microsoft.AspNetCore.Http;
  11. using Microsoft.Extensions.Configuration;
  12. using Newtonsoft.Json;
  13. using System.IdentityModel.Tokens.Jwt;
  14. using System.Net;
  15. using System.Security.Claims;
  16. namespace ERP.Framework.Middleware
  17. {
  18. /// <summary>
  19. /// 验证 (解签 header附带用户id) useJwt
  20. /// </summary>
  21. public class AuthenticationMiddleware : IMiddleware
  22. {
  23. private readonly IConfiguration _configuration;
  24. public AuthenticationMiddleware(IConfiguration configuration)
  25. {
  26. this._configuration = configuration;
  27. }
  28. public async Task InvokeAsync(HttpContext context, RequestDelegate next)
  29. {
  30. var path = context.Request.Path.ToString();
  31. var securityConfig = _configuration.GetSection(FrameworkConstant.SECURITY_CONFIG).Get<SecurityConfig>() ?? new SecurityConfig();
  32. if (securityConfig.WhiteList != null && UrlUtil.Match(path, securityConfig.WhiteList))
  33. {
  34. await next(context);
  35. return;
  36. }
  37. var token = context.Request.Headers[AuthConstant.HEADER].ToString().Replace(FrameworkConstant.TOKEN_PREFIX, "").TrimStart();
  38. var isValid = TokenHelper.ValidateToken(token, securityConfig.JwtSecurityKey);
  39. if (!isValid)
  40. {
  41. // 返回401状态码和自定义错误信息
  42. context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
  43. context.Response.ContentType = "application/json";
  44. var errorJson = JsonConvert.SerializeObject(new Result()
  45. {
  46. Code = ErrorCode.TOKEN_VALIDATE,
  47. Message = FrameworkI18N.TokenValidate!
  48. });
  49. await context.Response.WriteAsync(errorJson);
  50. return;
  51. }
  52. var claims = TokenHelper.GetClaims(token);
  53. var tokenId = claims.FirstOrDefault(t => t.Type == JwtRegisteredClaimNames.UniqueName)!.Value;
  54. var userId = claims.FirstOrDefault(t => t.Type == JwtRegisteredClaimNames.NameId)!.Value;
  55. var userName = claims.FirstOrDefault(t => t.Type == ClaimTypes.Name)!.Value;
  56. var checkLastActivityResult = CheckLastActivity(tokenId, securityConfig.ActivityTimeOut);
  57. if (checkLastActivityResult != null)
  58. {
  59. context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
  60. context.Response.ContentType = "application/json";
  61. await context.Response.WriteAsync(JsonConvert.SerializeObject(checkLastActivityResult));
  62. return;
  63. }
  64. context.Items["TokenId"] = tokenId;
  65. context.Items["UserId"] = userId;
  66. context.Items["UserName"] = userName;
  67. await next(context);
  68. return;
  69. }
  70. private static Result? CheckLastActivity(string tokenId, int activityTimeOut)
  71. {
  72. DateTime date;
  73. var result = new Result();
  74. var key = AuthConstant.LAST_ACTIVITY + tokenId;
  75. var lastActivity = RedisHelper.GetWithExpire(key);
  76. var value = lastActivity.Value.ToString();
  77. var expireTime = lastActivity.Expiry;
  78. if (value.IsNullOrEmpty())
  79. {
  80. result.Code = ErrorCode.IDLE_TIME_OUT;
  81. result.Message = FrameworkI18N.IdleTimeOut!;
  82. return result;
  83. }
  84. if (value == "-1")
  85. {
  86. result.Code = ErrorCode.KICKED_OUT;
  87. result.Message = FrameworkI18N.KickedOut!;
  88. return result;
  89. }
  90. if (value == "-2")
  91. {
  92. result.Code = ErrorCode.CONCURRENT_LOGIN;
  93. result.Message = FrameworkI18N.ConcurrentLogin!;
  94. return result;
  95. }
  96. if (DateTime.TryParse(value, out date))
  97. {
  98. var isOnline = DateTime.Now <= date;
  99. if (isOnline)
  100. {
  101. SetLastActivityCache(tokenId, activityTimeOut, expireTime);
  102. }
  103. else
  104. {
  105. result.Code = ErrorCode.IDLE_TIME_OUT;
  106. result.Message = FrameworkI18N.IdleTimeOut!;
  107. return result;
  108. }
  109. }
  110. return null;
  111. }
  112. /// <summary>
  113. /// 刷新last Activity
  114. /// </summary>
  115. /// <param name="tokenId"></param>
  116. /// <param name="activityTimeOut"></param>
  117. private static void SetLastActivityCache(
  118. string tokenId
  119. , int activityTimeOut
  120. , TimeSpan? expireTime)
  121. {
  122. var key = AuthConstant.LAST_ACTIVITY + tokenId;
  123. var val = DateTime.Now.AddMinutes(activityTimeOut).ToDateLongString();
  124. RedisHelper.SaveExpire(key, val, expireTime);
  125. }
  126. }
  127. public static class AuthenticationMiddlewareExtensions
  128. {
  129. public static IApplicationBuilder UseAuthenticationMiddleware(this IApplicationBuilder builder)
  130. {
  131. return builder.UseMiddleware<AuthenticationMiddleware>();
  132. }
  133. }
  134. }