123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- using Bowin.Common.Cache;
- using Bowin.Common.JSON;
- using Bowin.Common.Utility;
- using Microsoft.AspNetCore.Authentication.JwtBearer;
- using Microsoft.AspNetCore.Hosting;
- using Microsoft.AspNetCore.Http;
- using Microsoft.AspNetCore.SignalR;
- using Microsoft.Extensions.Configuration;
- using Microsoft.Extensions.DependencyInjection;
- using Microsoft.Extensions.Logging;
- using Microsoft.IdentityModel.Tokens;
- using System;
- using System.Collections.Generic;
- using System.IdentityModel.Tokens.Jwt;
- using System.IO;
- using System.Linq;
- using System.Linq.Expressions;
- using System.Runtime.CompilerServices;
- using System.Security.Claims;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- namespace Bowin.Common.ServiceToken
- {
- public static class JwtHelper
- {
- private static JwtSettings Settings { get; set; }
- private const string AUTH_SECURITY_KEY = "6bb452e82b0f6ab0253d6db9f384996552dd3afcb9113d760a00a154cabc6cbd56c5f33c246a05090005a1e8dfc148388aa6593fdbb3b5a18a73153c07a5cdd3";
- private const string AUTH_REFRESH_KEY = "4e64a7b3614c2710fef2fee37fe1b660302b65ca485fd57c9271e96bc36413e7c9c509a28190154b901d54abd4a45fc9b92f06fc3d798ea4b827f151f1e7c322";
- public static Func<Guid, List<string>> GetFunctionCodeMethod { get; set; }
- internal static Delegate GetRefreshUserFunc { get; set; }
- static JwtHelper()
- {
- var configuration = new ConfigurationBuilder()
- .SetBasePath(Directory.GetCurrentDirectory())
- .AddJsonFile("appsettings.json")
- .Build();
- Settings = configuration.GetSection("JwtSettings").Get<JwtSettings>();
- }
- public static void AddBowinAuthentication<T>(this IServiceCollection service, Func<Guid, T> refreshUserFunc, Func<Guid, List<string>> getFunctionGodeFunc = null)
- {
- GetRefreshUserFunc = refreshUserFunc;
- GetFunctionCodeMethod = getFunctionGodeFunc;
- service.AddAuthentication(options =>
- {
- options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
- options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
- })
- .AddJwtBearer(options => {
- options.RequireHttpsMetadata = false;
- options.SaveToken = true;
- options.TokenValidationParameters = new TokenValidationParameters
- {
- ValidateIssuer = true,
- ValidateAudience = true,
- ValidateIssuerSigningKey = true,
- ValidateLifetime = false,
- ValidAudience = Settings.Audience,
- ValidIssuer = Settings.Issuer,
- //AudienceValidator = (audiences, securityToken, validationParameters) => {
- // //var userID = CacheHelper.Get(securityToken.Id);
- // //if (userID == null)
- // //{
- // // return false;
- // //}
- // return audiences != null && audiences.FirstOrDefault().Equals(Settings.Audience);
- //},
- AudienceValidator = AudianValidator,
- IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(AUTH_SECURITY_KEY))
- };
- //options.Events = new JwtBearerEvents
- //{
- // OnTokenValidated = (context => {
- // //var logger = HttpHelper.GetService<ILogger<TokenSender>>();
- // var claims = context.Principal.Claims;
- // claims = claims.Where(x => x.Type != JwtRegisteredClaimNames.Aud && x.Type != JwtRegisteredClaimNames.Nbf && x.Type != JwtRegisteredClaimNames.Jti).ToArray();
- // var userID = claims.FirstOrDefault(x => x.Type == ClaimTypes.Name).Value;
- // var nowTime = DateTime.Now;
- // nowTime.AddMilliseconds(0 - nowTime.Millisecond);
- // var jti = GetJTI(userID);
- // claims = claims//.Append(new Claim(JwtRegisteredClaimNames.Nbf, $"{ new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds() }"))
- // .Append(new Claim(JwtRegisteredClaimNames.Jti, jti));
- // var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(AUTH_SECURITY_KEY));
- // var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
- // var token = new JwtSecurityToken(
- // issuer: Settings.Issuer,
- // audience: Settings.Audience,
- // claims: claims,
- // signingCredentials: creds
- // );
- // var newToken = new JwtSecurityTokenHandler().WriteToken(token);
- // if (jti != context.SecurityToken.Id)
- // {
- // CacheHelper.Add(jti, userID, DateTime.Now.AddDays(1));
- // CacheHelper.Set(context.SecurityToken.Id, userID, DateTime.Now.AddSeconds(2));
- // }
- // //context.HttpContext.Response.Headers.Add("ServiceToken", newToken);
- // return System.Threading.Tasks.Task.CompletedTask;
- // })
- //};
- });
- //service.AddSignalR(options => {
- // options.ClientTimeoutInterval = TimeSpan.FromHours(2);
- // options.KeepAliveInterval = TimeSpan.FromMinutes(2);
- //});
- service.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
- var serviceProvider = service.BuildServiceProvider();
- HttpHelper.Accessor = serviceProvider.GetService<IHttpContextAccessor>();
- HttpHelper.ServiceCollection = service;
- HttpHelper.WebHostEnvironment = serviceProvider.GetService<IWebHostEnvironment>();
- }
- public static bool AudianValidator(IEnumerable<string> audiences, SecurityToken securityToken, TokenValidationParameters validationParameters)
- {
- var curJTI = securityToken.Id;
- var userID = ((JwtSecurityToken)securityToken).Claims.Where(x => x.Type == ClaimTypes.Name).Select(x => x.Value).FirstOrDefault();
- if (string.IsNullOrEmpty(userID) || GetJTI(userID) != curJTI)
- {
- return false;
- }
- var nowId = ((JwtSecurityToken)securityToken).Claims.Where(x => x.Type == ClaimTypes.NameIdentifier).Select(x => x.Value).FirstOrDefault();
- if (string.IsNullOrEmpty(nowId))
- {
- return false;
- }
- if (CacheHelper.Get(nowId) == null)
- {
- return false;
- }
- return audiences != null && audiences.FirstOrDefault().Equals(Settings.Audience);
- }
- private static string GetTimeStamp()
- {
- var nowTime = DateTime.Now;
- nowTime.AddMilliseconds(0 - nowTime.Millisecond);
- var timeStamp = new DateTimeOffset(nowTime).ToUnixTimeSeconds();
- return timeStamp.ToString();
- }
- private static string GetJTI(string userID)
- {
- var ip = "";//HttpHelper.GetUserIp();
- return (userID + ip + HttpHelper.Current.Request.Host.ToString() + ip).MD5();
- }
- public static BowinToken<T> GetToken<T>(Func<T> getUserFunc, Expression<Func<T, Guid>> keyExp)
- {
- var userInfo = getUserFunc.Invoke();
- if (userInfo == null)
- {
- throw new TokenLoginFailureException("帐号或密码错误。");
- }
- var userID = keyExp.Compile().Invoke(userInfo);
- var jti = GetJTI(userID.ToString());
-
- return GenerateToken(userInfo, jti, userID);
- }
- private static BowinToken<T> GenerateToken<T>(T userInfo, string jti, Guid userID)
- {
- var nowId = HttpHelper.Current.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier)?.Value;
- var newId = Guid.NewGuid().ToString();
- CacheHelper.Add("uinfo_" + userID.ToString(), userInfo.ToJson());
- var claims = new[] {
- new Claim(JwtRegisteredClaimNames.Jti, jti),
- new Claim(JwtRegisteredClaimNames.Nbf, $"{ new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds() }"),
- new Claim(ClaimTypes.NameIdentifier, newId),
- new Claim(ClaimTypes.Name, userID.ToString())
- };
- if (GetFunctionCodeMethod != null)
- {
- CacheHelper.Add("rinfo_" + userID.ToString(), GetFunctionCodeMethod.Invoke(userID).ToJson());
- }
- var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(AUTH_SECURITY_KEY));
- var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
- var token = new JwtSecurityToken(
- issuer: Settings.Issuer,
- audience: Settings.Audience,
- expires: DateTime.Now.AddMinutes(20),
- claims: claims,
- signingCredentials: creds
- );
- if (nowId != null)
- {
- CacheHelper.Set(nowId, userID, DateTime.Now.AddSeconds(30));
- }
- CacheHelper.Add(newId, userID, DateTime.Now.AddDays(1));
- var endToken = new BowinToken<T> { Token = new JwtSecurityTokenHandler().WriteToken(token), UserObj = userInfo };
- return endToken;
- }
- public static BowinToken<T> RefreshToken<T>()
- {
- var claims = HttpHelper.Current.User.Claims;
- var userID = claims.Where(x => x.Type == ClaimTypes.Name).Select(x => x.Value).FirstOrDefault();
- if (string.IsNullOrEmpty(userID))
- {
- throw new Exception("无法获取用户信息,请检查访问令牌是否错误。");
- }
- var jti = GetJTI(userID);
- var userInfo = JwtUser<T>.Current;
- if (userInfo == null)
- {
- throw new Exception("无法获取用户信息,请检查访问令牌是否错误。");
- }
- return GenerateToken(userInfo, jti, new Guid(userID));
- }
- }
- public class TokenSender : Hub
- {
- public override async Task OnConnectedAsync()
- {
- await Groups.AddToGroupAsync(Context.ConnectionId, this.Context.GetHttpContext().Request.Query["UserID"]);
- }
- }
- public class TokenLoginFailureException : Exception
- {
- public TokenLoginFailureException(string message) : base(message)
- {
- }
- }
- public class JwtRereshTokenInvalidException : Exception
- {
- public JwtRereshTokenInvalidException(string message) : base(message)
- {
- }
- }
- }
|