!3 新增授权认证

Merge pull request !3 from 刘小吉/master
This commit is contained in:
Token
2024-01-25 10:52:11 +00:00
committed by Gitee
6 changed files with 2083 additions and 1937 deletions
+16 -1
View File
@@ -19,7 +19,22 @@ public sealed class RouteEntity : Entity
/// 绑定集群Id可空
/// </summary>
public string? ClusterId { get; set; }
/// <summary>
/// 授权策略
/// </summary>
public string? AuthorizationPolicy { get; set; }
/// <summary>
/// 认证中心否需要https
/// </summary>
public bool? RequireHttpsMetadata { get; set; }
/// <summary>
/// 授权认证中心地址
/// </summary>
public string? AuthorizationPolicyAddress { get; set; }
/// <summary>
/// 请求Body最大长度
/// </summary>
@@ -12,15 +12,17 @@ public static class JwtServiceCollectionExtension
/// </summary>
/// <param name="services"></param>
/// <param name="options">JWT授权的配置项</param>
public static IServiceCollection AddJwtBearerAuthentication(this IServiceCollection services)
/// <param name="policies">路由信息</param>
public static IServiceCollection AddJwtBearerAuthentication(this IServiceCollection services, List<RouteEntity>? policies = null)
{
//使用应用密钥得到一个加密密钥字节数组
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddCookie(cfg => cfg.SlidingExpiration = true)
var authenticationBuilder = services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
});
authenticationBuilder.AddCookie(cfg => cfg.SlidingExpiration = true)
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = true;
@@ -34,6 +36,31 @@ public static class JwtServiceCollectionExtension
};
});
// 添加认证信息
if (policies != null)
{
foreach (var policy in policies)
{
authenticationBuilder.AddJwtBearer(policy.AuthorizationPolicy!, options =>
{
options.Authority = policy.AuthorizationPolicyAddress;
options.RequireHttpsMetadata = policy.RequireHttpsMetadata ?? true;
options.Audience = policy.AuthorizationPolicy!;
});
}
}
return services;
}
/// <summary>
/// 使用自定义授权中间件
/// </summary>
/// <param name="app">应用程序生成器接口</param>
/// <returns>应用程序生成器接口</returns>
public static IApplicationBuilder UseCustomAuthentication(this IApplicationBuilder app)
{
ArgumentNullException.ThrowIfNull(app);
return app.UseMiddleware<CustomAuthenticationMiddleware>();
}
}
@@ -0,0 +1,72 @@
using Microsoft.AspNetCore.Authentication;
using Yarp.ReverseProxy.Model;
namespace Gateway.Middlewares
{
/// <summary>
/// 自定义授权中间件
/// </summary>
public class CustomAuthenticationMiddleware
{
/// <summary>
/// 请求委托
/// </summary>
private readonly RequestDelegate _next;
/// <summary>
/// Initializes a new instance of <see cref="AuthenticationMiddleware"/>.
/// </summary>
/// <param name="next">The next item in the middleware pipeline.</param>
/// <param name="schemes">The <see cref="IAuthenticationSchemeProvider"/>.</param>
public CustomAuthenticationMiddleware(RequestDelegate next, IAuthenticationSchemeProvider schemes)
{
ArgumentNullException.ThrowIfNull(next);
ArgumentNullException.ThrowIfNull(schemes);
_next = next;
Schemes = schemes;
}
/// <summary>
/// Gets or sets the <see cref="IAuthenticationSchemeProvider"/>.
/// </summary>
public IAuthenticationSchemeProvider Schemes { get; set; }
/// <summary>
/// Invokes the middleware performing authentication.
/// </summary>
/// <param name="context">The <see cref="HttpContext"/>.</param>
public async Task Invoke(HttpContext context)
{
var endpoint = context.GetEndpoint()
?? throw new InvalidOperationException($"Routing Endpoint wasn't set for the current request.");
var route = endpoint.Metadata.GetMetadata<RouteModel>();
if (route == null)
{
await _next(context);
return;
}
var scheme = await GetSchemeAsync(route);
if (scheme != null)
{
var result = await context.AuthenticateAsync(scheme);
if (result?.Principal != null)
{
context.User = result.Principal;
}
}
await _next(context);
}
private async Task<string?> GetSchemeAsync(RouteModel route)
{
var scheme = route.Config.AuthorizationPolicy;
if (scheme == null)
{
var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync();
return defaultAuthenticate?.Name;
}
return scheme;
}
}
}
+32 -18
View File
@@ -1,5 +1,6 @@
#region FreeSql类型转换
using Microsoft.Extensions.DependencyInjection;
using Gateway.BackgroundServices;
Utils.TypeHandlers.TryAdd(typeof(Dictionary<string, string>), new StringJsonHandler<Dictionary<string, string>>());
@@ -11,6 +12,19 @@ Utils.TypeHandlers.TryAdd(typeof(string[]), new StringJsonHandler<string[]>());
var builder = WebApplication.CreateBuilder(args);
var directory = new DirectoryInfo("/data");
if (!directory.Exists)
{
directory.Create();
}
var freeSql = new FreeSqlBuilder()
.UseConnectionString(DataType.Sqlite, builder.Configuration.GetConnectionString("DefaultConnection"))
.UseMonitorCommand(cmd => Console.WriteLine($"Sql:{cmd.CommandText}")) //监听SQL语句
.UseAutoSyncStructure(true) //自动同步实体结构到数据库,FreeSql不会扫描程序集,只有CRUD时才会生成表。
.Build();
builder.Configuration.GetSection(nameof(JwtOptions))
.Get<JwtOptions>();
@@ -40,7 +54,7 @@ builder.WebHost.UseKestrel(options =>
builder.WebHost.ConfigureKestrel(kestrel =>
{
kestrel.Limits.MaxRequestBodySize = null;
kestrel.ListenAnyIP(8081, portOptions =>
{
portOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
@@ -55,15 +69,25 @@ builder.WebHost.ConfigureKestrel(kestrel =>
#region Jwt
var policies = freeSql.Select<RouteEntity>().Where(a => a.AuthorizationPolicy != null).Distinct().ToList();
builder.Services
.AddAuthorization()
.AddJwtBearerAuthentication();
.AddAuthorization(options =>
{
// 添加授权策略
foreach (var policy in policies)
{
options.AddPolicy(policy.AuthorizationPolicy!, policy => policy.RequireAuthenticatedUser());
}
})
.AddJwtBearerAuthentication(policies);
#endregion
builder.Services.Configure<KestrelServerOptions>(options =>
{
options.Limits.MaxRequestBodySize = int.MaxValue;
options.Limits.MaxRequestBodySize = int.MaxValue;
});
builder.Services.Configure<FormOptions>(x =>
@@ -110,20 +134,7 @@ builder.Services.AddSingleton<NetWorkService>();
builder.Services.AddSingleton<IContentTypeProvider, FileExtensionContentTypeProvider>();
builder.Services.AddSingleton<IFreeSql>(_ =>
{
var directory = new DirectoryInfo("/data");
if (!directory.Exists)
{
directory.Create();
}
return new FreeSqlBuilder()
.UseConnectionString(DataType.Sqlite, builder.Configuration.GetConnectionString("DefaultConnection"))
.UseMonitorCommand(cmd => Console.WriteLine($"Sql:{cmd.CommandText}")) //监听SQL语句
.UseAutoSyncStructure(true) //自动同步实体结构到数据库,FreeSql不会扫描程序集,只有CRUD时才会生成表。
.Build();
});
builder.Services.AddSingleton<IFreeSql>(freeSql);
// 使用内存加载配置
builder.Services.AddReverseProxy()
@@ -147,6 +158,9 @@ app.MapCertificate();
app.MapSetting();
app.MapNetWork();
// 添加自定义授权
app.UseCustomAuthentication();
app.UseAuthentication();
app.UseAuthorization();
+1
View File
@@ -26,6 +26,7 @@ public class GatewayService(
RouteId = route.RouteId,
ClusterId = route.ClusterId,
MaxRequestBodySize = route.MaxRequestBodySize,
AuthorizationPolicy = route.AuthorizationPolicy,
Match = new RouteMatch()
{
Path = route.MatchEntities.Path,
+1928 -1911
View File
File diff suppressed because it is too large Load Diff