diff --git a/Falcon.SugarApi.Test/JwtTokenBuilderTest.cs b/Falcon.SugarApi.Test/JwtTokenBuilderTest.cs deleted file mode 100644 index 6a69a56..0000000 --- a/Falcon.SugarApi.Test/JwtTokenBuilderTest.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Falcon.SugarApi.JWT; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Falcon.SugarApi.Test -{ - /// - /// JwtTokenBuilderTest - /// - [TestClass] - public class JwtTokenBuilderTest - { - /// - /// Token获取测试 - /// - [TestMethod] - public void GetTokenTest() { - var loginTime = DateTime.Now; - var playload = new LoginUserInfo { - UserName = "abdc", - LoginTime = loginTime, - Roles = new List { "admin", "user" }, - }; - if (new JwtTokenBuilder().TryGetToken(playload, out var token, out var exception)) { - Console.WriteLine("token:{0}", token); - } - else { - Console.WriteLine(exception.ToString()); - Assert.Fail("获取token失败"); - } - Assert.IsNotNull(token); - if (new JwtTokenBuilder().TryGetPlayload(token, out var pl, out var exception1)) { - - } - else { - Console.WriteLine(exception1.ToString()); - Assert.Fail("获取Playload失败"); - } - Assert.IsNotNull(pl); - Assert.AreEqual(playload.UserName, pl.UserName); - Assert.IsTrue(pl.Roles != null); - Assert.IsTrue(pl.Roles.Count == 2); - Assert.IsTrue(pl.Roles.Any(m => m == "admin")); - Assert.IsTrue(pl.Roles.Any(m => m == "user")); - } - } -} diff --git a/Falcon.SugarApi/FalconClaim/AddFalconClaimHeaderFilter.cs b/Falcon.SugarApi/FalconClaim/AddFalconClaimHeaderFilter.cs new file mode 100644 index 0000000..4fafaa3 --- /dev/null +++ b/Falcon.SugarApi/FalconClaim/AddFalconClaimHeaderFilter.cs @@ -0,0 +1,44 @@ +using Microsoft.AspNetCore.Mvc.Authorization; +using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; +using System.Collections.Generic; +using System.Linq; + +namespace Falcon.SugarApi.FalconClaim +{ + /// + /// 为swagger openapi接口增加验证选项 + /// + public class AddFalconClaimHeaderFilter:IOperationFilter + { + /// + public void Apply(OpenApiOperation operation,OperationFilterContext context) { + var filterPipeline = context.ApiDescription.ActionDescriptor.FilterDescriptors; + //var isAuthorized = filterPipeline.Select(filterInfo => filterInfo.Filter) + // .Any(filter => filter is FalconClaimAuthorizeAttribute); + + + var metedata = context.ApiDescription.ActionDescriptor.EndpointMetadata; + var isAuthorized = metedata.Any(m => m is FalconClaimAuthorizeAttribute); + var allowAnonymous = filterPipeline.Select(filterInfo => filterInfo.Filter) + .Any(filter => filter is IAllowAnonymousFilter); + + if(isAuthorized && !allowAnonymous) { + operation.Parameters = operation.Parameters ?? new List(); + + operation.Parameters.Add(new OpenApiParameter { + Name = FalconClaimOption.FalconAuthenticationKey, + In = ParameterLocation.Header, + Description = FalconClaimOption.Description, + Required = true, + Schema = new OpenApiSchema { + Type = "string", + Default = new OpenApiString(FalconClaimOption.TokenPrefix), + }, + + }); + } + } + } +} diff --git a/Falcon.SugarApi/FalconClaim/AesTokenBuilder.cs b/Falcon.SugarApi/FalconClaim/AesTokenBuilder.cs new file mode 100644 index 0000000..f0a2c1a --- /dev/null +++ b/Falcon.SugarApi/FalconClaim/AesTokenBuilder.cs @@ -0,0 +1,56 @@ +using Falcon.SugarApi.Encryption; +using Falcon.SugarApi.JsonSerialize; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; + +namespace Falcon.SugarApi.FalconClaim +{ + /// + /// 利用AES生成token + /// + public class AesTokenBuilder:ITokenBuilter + { + /// + /// 构造基于AES算法的token生成器 + /// + /// aes算法 + /// json工厂 + public AesTokenBuilder(IAESEncryption aes,JsonSerializeFactory factory) { + Aes = aes; + this.Json = factory.CreateJsonSerialize(); + } + + public IAESEncryption Aes { get; } + + public IJsonSerialize Json { get; set; } + + /// + public List? GetClaims(string token) { + var str = this.Aes.Decrypt(FalconClaimOption.SecKey,token); + if(str.IsNullOrEmpty()) { + return new List(); + } + return this.Json.Deserialize>(str) + .Select(m => new Claim(m.Type,m.Value)).ToList(); + } + + /// + public string? GetToken(List claims) { + var obj = claims.Select(m => new ClaimSerModel(m.Type,m.Value)); + return this.Aes.Encrypt(FalconClaimOption.SecKey,this.Json.Serialize(obj)); + } + class ClaimSerModel + { + public ClaimSerModel(string type,string value) { + Type = type; + Value = value; + } + + public string Type { get; set; } + public string Value { get; set; } + } + + } + +} diff --git a/Falcon.SugarApi/FalconClaim/ClaimsIdentityExtend.cs b/Falcon.SugarApi/FalconClaim/ClaimsIdentityExtend.cs new file mode 100644 index 0000000..e2c9b77 --- /dev/null +++ b/Falcon.SugarApi/FalconClaim/ClaimsIdentityExtend.cs @@ -0,0 +1,23 @@ +using System.Security.Claims; + +namespace Falcon.SugarApi.FalconClaim +{ + /// + /// 身份扩展 + /// + public static class ClaimsIdentityExtend + { + + /// + /// 象身份中增加声明 + /// + /// 身份 + /// 声明类型 + /// 声明值 + /// 身份 + public static ClaimsIdentity AddClaim(this ClaimsIdentity cid,string ClaimTypes,string value) { + cid.AddClaim(new Claim(ClaimTypes,value)); + return cid; + } + } +} diff --git a/Falcon.SugarApi/FalconClaim/FalconAuthenticationHandler.cs b/Falcon.SugarApi/FalconClaim/FalconAuthenticationHandler.cs new file mode 100644 index 0000000..3de4595 --- /dev/null +++ b/Falcon.SugarApi/FalconClaim/FalconAuthenticationHandler.cs @@ -0,0 +1,108 @@ +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Net; +using System.Security.Claims; +using System.Threading.Tasks; + +namespace Falcon.SugarApi.FalconClaim +{ + /// + /// 自定义验证方式 + /// + public class FalconAuthenticationHandler:IAuthenticationHandler + { + /// + /// 构造自定义身份验证方式 + /// + /// token工具 + public FalconAuthenticationHandler(ITokenBuilter tokenBuilter) { + this.Scheme = null; + this.Context = null; + TokenBuilter = tokenBuilter; + } + + /// + /// 验证计划,模式 + /// + public AuthenticationScheme? Scheme { get; set; } + + /// + /// HttpContext 上下文 + /// + public HttpContext? Context { get; set; } + + /// + public Task AuthenticateAsync() { + if(!this.Context.Request.Headers.TryGetValue(FalconClaimOption.FalconAuthenticationKey,out var val)) { + return UnLoginResultTask; + } + var token = val.ToString(); + if(token.IsNullOrEmpty()) { + return UnLoginResultTask; + } + if(FalconClaimOption.TokenPrefix.IsNotNullOrEmpty() && !token.StartsWith(FalconClaimOption.TokenPrefix)) { + return UnLoginResultTask; + } + try { + var ticket = GetTicket(token); + if(ticket == null) { + return UnLoginResultTask; + } + return Task.FromResult(AuthenticateResult.Success(ticket)); + } catch(Exception) { + return UnLoginResultTask; + } + } + + /// + public Task ChallengeAsync(AuthenticationProperties? properties) { + this.Context.Response.StatusCode = (int)HttpStatusCode.Unauthorized; + return Task.CompletedTask; + } + + /// + public Task ForbidAsync(AuthenticationProperties? properties) { + this.Context.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return Task.CompletedTask; + } + + /// + public Task InitializeAsync(AuthenticationScheme scheme,HttpContext context) { + this.Scheme = scheme; this.Context = context; + return Task.CompletedTask; + } + + /// + /// 根据登录token获取票据 + /// + private AuthenticationTicket? GetTicket(string token) { + token.ThrowNullExceptionWhenNull(); + List? claims = null; + try { + claims = this.TokenBuilter.GetClaims(token); + } catch(Exception) { + return null; + } + if(claims == null || claims.Count == 0) { + return null; + } + var cid = new ClaimsIdentity(FalconClaimOption.SchemeName); + cid.AddClaims(claims); + var principal = new ClaimsPrincipal(cid); + return new AuthenticationTicket(principal,this.Scheme.Name); + } + + /// + /// 验证失败任务 + /// + //public static Task UnLoginResultTask => throw new ApiDefinistions.ApiException("未登录"); + public static Task UnLoginResultTask => Task.FromResult(AuthenticateResult.Fail("未登录")); + + /// + /// Token工具 + /// + public ITokenBuilter TokenBuilter { get; } + } +} diff --git a/Falcon.SugarApi/FalconClaim/FalconClaimAuthorizeAttribute.cs b/Falcon.SugarApi/FalconClaim/FalconClaimAuthorizeAttribute.cs new file mode 100644 index 0000000..16c9e2e --- /dev/null +++ b/Falcon.SugarApi/FalconClaim/FalconClaimAuthorizeAttribute.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Authorization; + +namespace Falcon.SugarApi.FalconClaim +{ + /// + /// 根据角色验证 + /// + public class FalconClaimAuthorizeAttribute:AuthorizeAttribute + { + /// + /// 通过提供的角色进行验证 + /// + public FalconClaimAuthorizeAttribute() { + base.AuthenticationSchemes = FalconClaimOption.SchemeName; + } + /// + /// 通过提供的角色进行验证 + /// + /// ,号分割的角色列表 + public FalconClaimAuthorizeAttribute(string roles) { + base.AuthenticationSchemes = FalconClaimOption.SchemeName; + base.Roles = roles; + } + + } + +} diff --git a/Falcon.SugarApi/FalconClaim/FalconClaimOption.cs b/Falcon.SugarApi/FalconClaim/FalconClaimOption.cs new file mode 100644 index 0000000..ec3af52 --- /dev/null +++ b/Falcon.SugarApi/FalconClaim/FalconClaimOption.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; + +namespace Falcon.SugarApi.FalconClaim +{ + /// + /// FalconClaim验证选项 + /// + public class FalconClaimOption + { + /// + /// 自定义验证方式名 + /// + public static string SchemeName { get; set; } = "FalconClaimSchemeName"; + + /// + /// 用于提供验证token的键 + /// + public static string FalconAuthenticationKey { get; set; } = "Falcon_WWW_Authenticate"; + + /// + /// 用于加密的key + /// + public static string SecKey { get; set; } = "E9319792CB7249AD8E432000E9F2FE7A"; + + /// + /// 验证头说明 + /// + public static string Description { get; set; } = "FalconClaim验证的Token。"; + + /// + /// 请求Token前缀 + /// + public static string TokenPrefix { get; set; } = ""; + + /// + /// 二次认证方法 + /// + public List UserValidates { get; set; } = new List(); + } +} diff --git a/Falcon.SugarApi/FalconClaim/IApplicationBuilderExtend.cs b/Falcon.SugarApi/FalconClaim/IApplicationBuilderExtend.cs new file mode 100644 index 0000000..57e2ac8 --- /dev/null +++ b/Falcon.SugarApi/FalconClaim/IApplicationBuilderExtend.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Builder; + +namespace Falcon.SugarApi.FalconClaim +{ + /// + /// 扩展IApplicationBuilder + /// + public static class IApplicationBuilderExtend + { + /// + /// 使用认证UseAuthentication和授权UseAuthorization。需要加在在UseRouting后UseEndpoints前 + /// + public static IApplicationBuilder UseFalconClaim(this IApplicationBuilder app) { + app.UseAuthentication().UseAuthorization(); + return app; + } + } +} diff --git a/Falcon.SugarApi/FalconClaim/IServiceCollectionExtend.cs b/Falcon.SugarApi/FalconClaim/IServiceCollectionExtend.cs new file mode 100644 index 0000000..12472c0 --- /dev/null +++ b/Falcon.SugarApi/FalconClaim/IServiceCollectionExtend.cs @@ -0,0 +1,33 @@ +using Falcon.SugarApi.Encryption; +using Falcon.SugarApi.JsonSerialize; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using System; +using System.Text.Json; + +namespace Falcon.SugarApi.FalconClaim +{ + /// + /// 扩展IServiceCollection + /// + public static class IServiceCollectionExtend + { + /// + /// 增加FalconCalom相关服务 + /// + public static IServiceCollection AddFalconClaim(this IServiceCollection services,Action? optionBuilder = null) { + optionBuilder?.Invoke(new FalconClaimOption()); + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(); + services.AddAuthentication(b => { + b.DefaultAuthenticateScheme = FalconClaimOption.SchemeName; + b.DefaultChallengeScheme = FalconClaimOption.SchemeName; + b.DefaultForbidScheme = FalconClaimOption.SchemeName; + b.AddScheme(FalconClaimOption.SchemeName,FalconClaimOption.SchemeName); + }); + return services; + } + } +} diff --git a/Falcon.SugarApi/FalconClaim/ITokenBuilter.cs b/Falcon.SugarApi/FalconClaim/ITokenBuilter.cs new file mode 100644 index 0000000..5c60568 --- /dev/null +++ b/Falcon.SugarApi/FalconClaim/ITokenBuilter.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using System.Security.Claims; + +namespace Falcon.SugarApi.FalconClaim +{ + /// + /// 通过声明生成token + /// + public interface ITokenBuilter + { + /// + /// 根据声称组生成token + /// + /// 一组声明 + /// token + string? GetToken(List claims); + /// + /// 通过token获取声明组 + /// + /// token + /// 声明组 + List? GetClaims(string token); + } +} diff --git a/Falcon.SugarApi/FalconClaim/IUserValidate.cs b/Falcon.SugarApi/FalconClaim/IUserValidate.cs new file mode 100644 index 0000000..657b167 --- /dev/null +++ b/Falcon.SugarApi/FalconClaim/IUserValidate.cs @@ -0,0 +1,16 @@ +using System.Security.Claims; + +namespace Falcon.SugarApi.FalconClaim +{ + /// + /// 认证时候提供二次验证方法 + /// + public interface IUserValidate + { + /// + /// 在认证时候提供二次认证的方法 + /// + /// 身份 + void UserLogin(ClaimsIdentity identity); + } +} diff --git a/Falcon.SugarApi/FalconClaim/NameClaim.cs b/Falcon.SugarApi/FalconClaim/NameClaim.cs new file mode 100644 index 0000000..2cf0107 --- /dev/null +++ b/Falcon.SugarApi/FalconClaim/NameClaim.cs @@ -0,0 +1,16 @@ +using System.Security.Claims; + +namespace Falcon.SugarApi.FalconClaim +{ + /// + /// 名字声明 + /// + public class NameClaim:Claim + { + /// + /// 提供名字实现名字声明 + /// + /// 名字 + public NameClaim(string name) : base(ClaimTypes.Name,name) { } + } +} diff --git a/Falcon.SugarApi/FalconClaim/Readme.md b/Falcon.SugarApi/FalconClaim/Readme.md new file mode 100644 index 0000000..5f44ba9 --- /dev/null +++ b/Falcon.SugarApi/FalconClaim/Readme.md @@ -0,0 +1,7 @@ +FalconClaim 使用说明: + + +1. 用户登录:模块提供了UserLoginModel和UserLoginResult类,分别负责提供登录凭据和登录结果,可以扩展使用,当然也可以使用自己的模型类。 +> 1.通过UserLoginModel提供的凭据验证用户合法性。 +> 2.通过ITokenBuilter.GetToken方法获取登录token。该方法需要一个Claim列表,该列表至少应包含一个name和role声明,表示登录的用户名和角色,也可以根据需要增加其他声明。 +> 3.构造UserLoginResult对象返回token。 \ No newline at end of file diff --git a/Falcon.SugarApi/FalconClaim/SidClaim.cs b/Falcon.SugarApi/FalconClaim/SidClaim.cs new file mode 100644 index 0000000..7cdf25a --- /dev/null +++ b/Falcon.SugarApi/FalconClaim/SidClaim.cs @@ -0,0 +1,18 @@ +using System.Security.Claims; + +namespace Falcon.SugarApi.FalconClaim +{ + /// + /// 安全标识声明 + /// + public class SidClaim:Claim + { + + /// + /// 提供名字实现名字声明 + /// + /// 安全标识 + public SidClaim(string sid) : base(ClaimTypes.Sid,sid) { } + + } +} diff --git a/Falcon.SugarApi/FalconClaim/SwaggerGenOptionsExtend.cs b/Falcon.SugarApi/FalconClaim/SwaggerGenOptionsExtend.cs new file mode 100644 index 0000000..8b8b2c5 --- /dev/null +++ b/Falcon.SugarApi/FalconClaim/SwaggerGenOptionsExtend.cs @@ -0,0 +1,51 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; +using System.Collections.Generic; + +namespace Falcon.SugarApi.FalconClaim +{ + /// + /// SwaggerGenOptions扩展 + /// + public static class SwaggerGenOptionsExtend + { + /// + /// 在swaggerUI中为有FalconClaimAuthorizeAttribute特性的Action增加token头 + /// + /// SwaggerGenOptions + /// SwaggerGenOptions + public static SwaggerGenOptions AddHeaderForFalconClaim(this SwaggerGenOptions options) { + options.OperationFilter(); + return options; + } + + /// + /// 在swaggerUI中为所有api请求增加token头 + /// + /// SwaggerGenOptions + /// SwaggerGenOptions + public static SwaggerGenOptions AddHeaderForAllApi(this SwaggerGenOptions options) { + options.AddSecurityDefinition(FalconClaimOption.SchemeName,new OpenApiSecurityScheme { + Description = FalconClaimOption.Description, + Name = FalconClaimOption.FalconAuthenticationKey, + In = ParameterLocation.Header, + Type = SecuritySchemeType.ApiKey, + Scheme = FalconClaimOption.SchemeName, + }); + options.AddSecurityRequirement(new OpenApiSecurityRequirement { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference { + Type = ReferenceType.SecurityScheme, + Id =FalconClaimOption.SchemeName, + } + }, + new List() + } + }); + return options; + } + } +} diff --git a/Falcon.SugarApi/FalconClaim/UserLoginModel.cs b/Falcon.SugarApi/FalconClaim/UserLoginModel.cs new file mode 100644 index 0000000..70cf7b5 --- /dev/null +++ b/Falcon.SugarApi/FalconClaim/UserLoginModel.cs @@ -0,0 +1,18 @@ +namespace Falcon.SugarApi.FalconClaim +{ + /// + /// 用户登录凭据模板 + /// 用于验证用户登录,可以实现自己的类进行验证 + /// + public class UserLoginModel + { + /// + /// 用户名 + /// + public string? UserName { get; set; } + /// + /// 密码 + /// + public string? Password { get; set; } + } +} diff --git a/Falcon.SugarApi/FalconClaim/UserLoginResult.cs b/Falcon.SugarApi/FalconClaim/UserLoginResult.cs new file mode 100644 index 0000000..5270f1e --- /dev/null +++ b/Falcon.SugarApi/FalconClaim/UserLoginResult.cs @@ -0,0 +1,44 @@ +using System; + +namespace Falcon.SugarApi.FalconClaim +{ + /// + /// 用户登录凭据模板 + /// 登录结果,Token作为票据返回。 + /// + public class UserLoginResult + { + /// + /// 登录结果。成功返回True,失败返回False + /// + public bool Success { get; set; } = false; + /// + /// 登录结果信息 + /// + public string? Msg { get; set; } + /// + /// 登录票据Token + /// + public string? Token { get; set; } + /// + /// 登录时间。默认当前系统时间 + /// + public DateTime? LoginTime { get; set; } = DateTime.Now; + + /// + /// 获取一条成功的登录信息 + /// + /// 成功登录Token + /// 成功登录结果 + public static UserLoginResult LoginSuccess(string token) + => new UserLoginResult { Success = true,Token = token,Msg = "ok" }; + + /// + /// 登录失败。 + /// + /// 失败原因 + /// 失败的登录结果 + public static UserLoginResult LoginFail(string? msg) + => new UserLoginResult { Success = false,Msg = msg }; + } +} diff --git a/Falcon.SugarApi/JWT/AESTokenbuilder.cs b/Falcon.SugarApi/JWT/AESTokenbuilder.cs deleted file mode 100644 index 141f44b..0000000 --- a/Falcon.SugarApi/JWT/AESTokenbuilder.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Falcon.SugarApi.Encryption; - -namespace Falcon.SugarApi.JWT -{ - /// - /// 使用AES算法生成Token - /// - public class AESTokenbuilder : IJwtTokenBuilder - { - /// - /// AES加密算法 - /// - public IAESEncryption AES { get; set; } - /// - /// jwt生成参数 - /// - public JwtContext Jwt { get; } - - /// - /// 构造AES的Token - /// - /// AES参数 - /// jwt生成参数 - public AESTokenbuilder(AESConfig config, JwtContext jwt) { - Jwt = jwt; - AES = new AESProvider(config); - } - - /// / - public LoginUserInfo GetPlayload(string token) { - token.ThrowNullExceptionWhenNull(); - return this.AES.Decrypt(Jwt.SecKey, token); - } - - /// / - public string GetToken(LoginUserInfo playload) { - playload.ThrowNullExceptionWhenNull(); - return this.AES.Encrypt(Jwt.SecKey, playload); - } - } - -} diff --git a/Falcon.SugarApi/JWT/ApiAuthorizationAttribute.cs b/Falcon.SugarApi/JWT/ApiAuthorizationAttribute.cs deleted file mode 100644 index 9a908ea..0000000 --- a/Falcon.SugarApi/JWT/ApiAuthorizationAttribute.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Microsoft.AspNetCore.Mvc.Authorization; -using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; - -namespace Falcon.SugarApi.JWT -{ - /// - /// 验证 - /// - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] - public class ApiAuthorizationAttribute : Attribute, IAuthorizationFilter - { - /// - /// 用户需要具有的角色 - /// - public string[] Roles { get; set; } - - /// - /// 只需要登录即可通过验证 - /// - public ApiAuthorizationAttribute() { - this.Roles = new string[] { }; - } - /// - /// 需要登录并且具有一定的角色 - /// - /// 角色组 - public ApiAuthorizationAttribute(params string[] roles) { - this.Roles = roles; - } - - /// - public void OnAuthorization(AuthorizationFilterContext context) { - if (context.Filters.Any(f => f is IAllowAnonymousFilter)) { - return; - } - var option = context.HttpContext.RequestServices.GetRequiredService(); - var key = option?.AuthHeaderKey; - key.ThrowNullExceptionWhenNull(); - var token = context.HttpContext.Request.Headers[key].ToString(); - if (token.IsNullOrEmpty()) { - Unauthorized(context); - return; - } - var jwt = option?.JwtTokenBuilder; - jwt.ThrowNullExceptionWhenNull(); - var user = jwt.GetPlayload(token); - var userLogin = option?.UserLogin; - if (userLogin != null && !userLogin.CheckUserLogin(user)) { - Unauthorized(context); - return; - } - if (this.Roles != null && this.Roles.Length > 0 && !userLogin.UserInRoles(user, this.Roles)) { - Unauthorized(context); - return; - } - return; - } - - /// - /// 返回授权失败 - /// - /// 上下文 - private static void Unauthorized(AuthorizationFilterContext context) { - context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized; - } - } -} diff --git a/Falcon.SugarApi/JWT/IJwtTokenBuilder.cs b/Falcon.SugarApi/JWT/IJwtTokenBuilder.cs deleted file mode 100644 index 19ba5e5..0000000 --- a/Falcon.SugarApi/JWT/IJwtTokenBuilder.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Falcon.SugarApi.JWT -{ - - /// - /// jwt token 生成器 - /// - public interface IJwtTokenBuilder - { - /// - /// 获取Token负载 - /// - /// 登录Token - /// 负载信息 - LoginUserInfo GetPlayload(string token); - /// - /// 获取Token - /// - /// 负载 - /// Token对象 - string GetToken(LoginUserInfo playload); - } -} \ No newline at end of file diff --git a/Falcon.SugarApi/JWT/IServiceCollectionExtend.cs b/Falcon.SugarApi/JWT/IServiceCollectionExtend.cs deleted file mode 100644 index a598a30..0000000 --- a/Falcon.SugarApi/JWT/IServiceCollectionExtend.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Falcon.SugarApi.Encryption; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using System; - -namespace Falcon.SugarApi.JWT -{ - /// - /// 服务扩展 - /// - public static class IServiceCollectionExtend - { - /// - /// 注册Falcon.SqlSugar.JWT - /// - /// 服务集合 - /// 服务集合 - public static IServiceCollection AddFalconJWT(this IServiceCollection services) - => services.AddFalconJWT(null); - - /// - /// 注册Falcon.SqlSugar.JWT.JwtContext,并配置相关参数 - /// 消费端通过JwtContext注入 - /// - /// 服务集合 - /// 参数创建器 - /// 服务集合 - public static IServiceCollection AddFalconJWT(this IServiceCollection services, Action? OptionBuilder) { - services.AddSingleton(sp => { - var option = new JwtContext(); - var jtb = sp.GetService(); - if (jtb == null) { - var aesc = sp.GetService() ?? new AESConfig(); - jtb = new AESTokenbuilder(aesc, option); - } - option.JwtTokenBuilder = jtb; - - var ulj = sp.GetService(); - if (ulj != null) { - option.UserLogin = ulj; - } - - OptionBuilder?.Invoke(option); - - if (option.UserLogin == null) { - throw new Exception("必须为JwtOptions提供UserLogin属性!"); - } - if (option.JwtTokenBuilder == null) { - throw new Exception("必须为JwtOptions提供JwtTokenBuilder属性!"); - } - return option; - }); - return services; - } - } -} diff --git a/Falcon.SugarApi/JWT/IUserLogin.cs b/Falcon.SugarApi/JWT/IUserLogin.cs deleted file mode 100644 index a8118db..0000000 --- a/Falcon.SugarApi/JWT/IUserLogin.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Collections.Generic; - -namespace Falcon.SugarApi.JWT -{ - /// - /// 用户登录验证接口 - /// - public interface IUserLogin - { - /// - /// 登录是否成功 - /// - /// 登录凭据 - /// 成功返回用户信息,否则返回null - LoginUserInfo? Login(LoginDto login); - - /// - /// 用户登出 - /// - /// 用户名 - /// True成功,False失败 - bool LogOut(LoginUserInfo userInfo); - - /// - /// 登录用户验证。检查客户端提供的已登录用户是否仍然处于登录中。 - /// - /// 登录凭据 - /// 登录中返回True,否则返回False - bool CheckUserLogin(LoginUserInfo userInfo); - - /// - /// 用户是否具有某个角色 - /// - /// 用户信息 - /// 需要具有的角色组 - /// True具有,False不具有 - bool UserInRoles(LoginUserInfo userInfo, params string[] roles); - } -} diff --git a/Falcon.SugarApi/JWT/JwtContext.cs b/Falcon.SugarApi/JWT/JwtContext.cs deleted file mode 100644 index 1e8a1c0..0000000 --- a/Falcon.SugarApi/JWT/JwtContext.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace Falcon.SugarApi.JWT -{ - /// - /// JWT认证上下文 - /// - public class JwtContext - { - /// - /// 验证头的键值 - /// - public string AuthHeaderKey { get; set; } = "auth"; - - /// - /// 用户Token加密的秘钥 - /// - public string SecKey { get; set; } = "fefafwefwf464664f64e64f63"; - - /// - /// jwtToken生成器 - /// - public IJwtTokenBuilder? JwtTokenBuilder { get; set; } - - /// - /// 用户登录管理 - /// - public IUserLogin? UserLogin { get; set; } - - } -} diff --git a/Falcon.SugarApi/JWT/JwtTokenBuilder.cs b/Falcon.SugarApi/JWT/JwtTokenBuilder.cs deleted file mode 100644 index 8016c48..0000000 --- a/Falcon.SugarApi/JWT/JwtTokenBuilder.cs +++ /dev/null @@ -1,64 +0,0 @@ -using JWT; -using JWT.Algorithms; -using JWT.Serializers; -using Microsoft.AspNetCore.Server.IIS.Core; -using System; -using System.Text; - -namespace Falcon.SugarApi.JWT -{ - /// - /// jwt token 生成器 - /// - public class JwtTokenBuilder : IJwtTokenBuilder - { - /// - /// 使用默认配置实例化 - /// - public JwtTokenBuilder() : this(new JwtContext()) { } - - /// - /// 实例化 - /// - /// JWT认证配置 - public JwtTokenBuilder(JwtContext options) { - Options = options; - } - - /// - /// JWT认证配置 - /// - public JwtContext Options { get; } - - /// - /// 获取Token - /// - /// 负载 - /// Token对象 - public string GetToken(LoginUserInfo playload) { - playload = playload ?? throw new ArgumentNullException(nameof(playload)); - var key = Encoding.UTF8.GetBytes(this.Options.SecKey); - var algorithm = new HMACSHA256Algorithm(); - var serializer = new JsonNetSerializer(); - var urlEncoder = new JwtBase64UrlEncoder(); - var encoder = new JwtEncoder(algorithm, serializer, urlEncoder); - return encoder.Encode(playload, key); - } - - /// - /// 获取Token负载 - /// - /// 登录Token - /// 负载信息 - public LoginUserInfo GetPlayload(string token) { - var key = Encoding.UTF8.GetBytes(this.Options.SecKey); - var serializer = new JsonNetSerializer(); - var dtProvider = new UtcDateTimeProvider(); - var validator = new JwtValidator(serializer, dtProvider); - var urlEncoder = new JwtBase64UrlEncoder(); - var algorithm = new HMACSHA256Algorithm(); - var decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm); - return decoder.DecodeToObject(token, key, true); - } - } -} diff --git a/Falcon.SugarApi/JWT/JwtTokenBuilderExtend.cs b/Falcon.SugarApi/JWT/JwtTokenBuilderExtend.cs deleted file mode 100644 index b16b5da..0000000 --- a/Falcon.SugarApi/JWT/JwtTokenBuilderExtend.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; - -namespace Falcon.SugarApi.JWT -{ - /// - /// JwtTokenBuilder扩展 - /// - public static class JwtTokenBuilderExtend - { - /// - /// 尝试获取Token - /// - /// 生成器 - /// 用户信息 - /// 生成的token - /// 失败异常 - /// 成功True,失败False - public static bool TryGetToken(this JwtTokenBuilder builder, LoginUserInfo userInfo, out string? token, out Exception? exception) { - try { - token = builder.GetToken(userInfo); - exception = null; - return true; - } - catch (Exception ex) { - token = null; - exception = ex; - return false; - } - } - - /// - /// 尝试获取用户信息 - /// - /// jwt创建器 - /// token - /// 用户信息 - /// 异常 - /// True成功,False失败 - public static bool TryGetPlayload(this JwtTokenBuilder builder, string token, out LoginUserInfo? userInfo, out Exception? exception) { - try { - userInfo = builder.GetPlayload(token); - exception = null; - return true; - } - catch (Exception ex) { - userInfo = null; - exception = ex; - return false; - } - } - } -} diff --git a/Falcon.SugarApi/JWT/LoginDto.cs b/Falcon.SugarApi/JWT/LoginDto.cs deleted file mode 100644 index 4a7d67e..0000000 --- a/Falcon.SugarApi/JWT/LoginDto.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Falcon.SugarApi.JWT -{ - /// - /// 登录信息 - /// - public class LoginDto - { - /// - /// 用户名 - /// - public string UserName { get; set; } - /// - /// 密码 - /// - public string Password { get; set; } - } -} diff --git a/Falcon.SugarApi/JWT/LoginUserInfo.cs b/Falcon.SugarApi/JWT/LoginUserInfo.cs deleted file mode 100644 index 9ea2c65..0000000 --- a/Falcon.SugarApi/JWT/LoginUserInfo.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Falcon.SugarApi.JWT -{ - /// - /// JWT载荷信息 - /// - public class LoginUserInfo - - { - /// - /// 登录用户名 - /// - public string? UserName { get; set; } - /// - /// 用户角色 - /// - public List Roles { get; set; } = new List(); - /// - /// 其他扩展用户信息 - /// - public Dictionary UserInfoExtend { get; set; } = new Dictionary(); - /// - /// 登录时间 - /// - public DateTime? LoginTime { get; set; } - } -} diff --git a/Falcon.SugarApi/JWT/TokenDto.cs b/Falcon.SugarApi/JWT/TokenDto.cs deleted file mode 100644 index 0871d21..0000000 --- a/Falcon.SugarApi/JWT/TokenDto.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Falcon.SugarApi.JWT -{ - /// - /// 登录凭据 - /// - public class TokenDto - { - /// - /// 登录结果 - /// - public bool Success { get; set; } - /// - /// 信息 - /// - public string Message { get; set; } - /// - /// 凭据 - /// - public string Token { get; set; } - } -} diff --git a/Falcon.SugarApi/JWT/readme.md b/Falcon.SugarApi/JWT/readme.md deleted file mode 100644 index ecc3437..0000000 --- a/Falcon.SugarApi/JWT/readme.md +++ /dev/null @@ -1,7 +0,0 @@ -初始化过程: -1. 初始化相关表: -2. 初始化用户系统:检查是否存在用户,如果没有用户插入默认管理员用户,后期可以删除。 -2. 初始化角色系统: -> 1. 检查系统所有控制器,查询是否标注ApiExplorerSettings特性,如果标注查询是否定义GroupName,不为空则列为角色之一。 -> 2. 检查角色表,如果发现缺少某角色则插入。检查是否存在超管角色,如果不存在则插入 -