mirror of
https://github.com/ThingsGateway/ThingsGateway.git
synced 2026-10-29 04:16:49 +08:00
refactor: 添加Cors
This commit is contained in:
+49
@@ -0,0 +1,49 @@
|
||||
// 版权归百小僧及百签科技(广东)有限公司所有。
|
||||
|
||||
using Furion.CorsAccessor;
|
||||
using Microsoft.AspNetCore.Cors.Infrastructure;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder;
|
||||
|
||||
/// <summary>
|
||||
/// 跨域中间件拓展
|
||||
/// </summary>
|
||||
public static class CorsAccessorApplicationBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加跨域中间件
|
||||
/// </summary>
|
||||
/// <param name="app"></param>
|
||||
/// <param name="corsPolicyBuilderHandler"></param>
|
||||
/// <returns></returns>
|
||||
public static IApplicationBuilder UseCorsAccessor(this IApplicationBuilder app, Action<CorsPolicyBuilder> corsPolicyBuilderHandler = default)
|
||||
{
|
||||
// 获取选项
|
||||
var corsAccessorSettings = app.ApplicationServices.GetService<IOptions<CorsAccessorSettingsOptions>>().Value;
|
||||
|
||||
// 判断是否启用 SignalR 跨域支持
|
||||
if (corsAccessorSettings.SignalRSupport == false)
|
||||
{
|
||||
// 配置跨域中间件
|
||||
_ = corsPolicyBuilderHandler == null
|
||||
? app.UseCors(corsAccessorSettings.PolicyName)
|
||||
: app.UseCors(corsPolicyBuilderHandler);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 配置跨域中间件
|
||||
app.UseCors(builder =>
|
||||
{
|
||||
// 设置跨域策略
|
||||
Penetrates.SetCorsPolicy(builder, corsAccessorSettings, true);
|
||||
|
||||
// 添加自定义配置
|
||||
corsPolicyBuilderHandler?.Invoke(builder);
|
||||
});
|
||||
}
|
||||
|
||||
return app;
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
// 版权归百小僧及百签科技(广东)有限公司所有。
|
||||
|
||||
using Furion;
|
||||
using Furion.CorsAccessor;
|
||||
using Microsoft.AspNetCore.Cors.Infrastructure;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using ThingsGateway;
|
||||
using ThingsGateway.Core;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
/// <summary>
|
||||
/// 跨域访问服务拓展类
|
||||
/// </summary>
|
||||
public static class CorsAccessorServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 配置跨域
|
||||
/// </summary>
|
||||
/// <param name="services">服务集合</param>
|
||||
/// <param name="corsOptionsHandler"></param>
|
||||
/// <param name="corsPolicyBuilderHandler"></param>
|
||||
/// <returns>服务集合</returns>
|
||||
public static IServiceCollection AddCorsAccessor(this IServiceCollection services, Action<CorsOptions> corsOptionsHandler = default, Action<CorsPolicyBuilder> corsPolicyBuilderHandler = default)
|
||||
{
|
||||
// 解决服务重复注册问题
|
||||
if (services.Any(u => u.ServiceType == typeof(IConfigureOptions<CorsAccessorSettingsOptions>)))
|
||||
{
|
||||
return services;
|
||||
}
|
||||
|
||||
// 添加跨域配置选项
|
||||
services.TryAddSingleton<IConfigureOptions<CorsAccessorSettingsOptions>, Microsoft.Extensions.DependencyInjection.ConfigureOptions<CorsAccessorSettingsOptions>>();
|
||||
|
||||
// 获取选项
|
||||
var corsAccessorSettings = App.Configuration.GetSection("CorsAccessorSettings").Get<CorsAccessorSettingsOptions>();
|
||||
|
||||
// 添加跨域服务
|
||||
services.AddCors(options =>
|
||||
{
|
||||
// 添加策略跨域
|
||||
options.AddPolicy(corsAccessorSettings.PolicyName, builder =>
|
||||
{
|
||||
// 设置跨域策略
|
||||
Penetrates.SetCorsPolicy(builder, corsAccessorSettings);
|
||||
|
||||
// 添加自定义配置
|
||||
corsPolicyBuilderHandler?.Invoke(builder);
|
||||
});
|
||||
|
||||
// 添加自定义配置
|
||||
corsOptionsHandler?.Invoke(options);
|
||||
});
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
// 版权归百小僧及百签科技(广东)有限公司所有。
|
||||
|
||||
using Microsoft.AspNetCore.Cors.Infrastructure;
|
||||
|
||||
namespace Furion.CorsAccessor;
|
||||
|
||||
/// <summary>
|
||||
/// 常量、公共方法配置类
|
||||
/// </summary>
|
||||
internal static class Penetrates
|
||||
{
|
||||
/// <summary>
|
||||
/// 默认跨域导出响应头 Key
|
||||
/// </summary>
|
||||
/// <remarks>解决 ajax,XMLHttpRequest,axios 不能获取请求头问题</remarks>
|
||||
private static readonly string[] _defaultExposedHeaders = new[]
|
||||
{
|
||||
"access-token",
|
||||
"x-access-token",
|
||||
"Content-Disposition"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 设置跨域策略
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
/// <param name="corsAccessorSettings"></param>
|
||||
/// <param name="isMiddleware"></param>
|
||||
internal static void SetCorsPolicy(CorsPolicyBuilder builder, CorsAccessorSettingsOptions corsAccessorSettings, bool isMiddleware = false)
|
||||
{
|
||||
// 判断是否设置了来源,因为 AllowAnyOrigin 不能和 AllowCredentials一起公用
|
||||
var isNotSetOrigins = corsAccessorSettings.WithOrigins == null || corsAccessorSettings.WithOrigins.Length == 0;
|
||||
|
||||
// https://docs.microsoft.com/zh-cn/aspnet/core/signalr/security?view=aspnetcore-6.0
|
||||
var isSupportSignarlR = isMiddleware && corsAccessorSettings.SignalRSupport == true;
|
||||
|
||||
// 设置总是允许跨域源配置
|
||||
builder.SetIsOriginAllowed(_ => true);
|
||||
|
||||
// 如果没有配置来源,则允许所有来源
|
||||
if (isNotSetOrigins)
|
||||
{
|
||||
// 解决 SignarlR 不能配置允许所有源问题
|
||||
if (!isSupportSignarlR) builder.AllowAnyOrigin();
|
||||
}
|
||||
else builder.WithOrigins(corsAccessorSettings.WithOrigins)
|
||||
.SetIsOriginAllowedToAllowWildcardSubdomains();
|
||||
|
||||
// 如果没有配置请求标头,则允许所有表头,包含处理 SignarlR 情况
|
||||
if ((corsAccessorSettings.WithHeaders == null || corsAccessorSettings.WithHeaders.Length == 0) || isSupportSignarlR) builder.AllowAnyHeader();
|
||||
else builder.WithHeaders(corsAccessorSettings.WithHeaders);
|
||||
|
||||
// 如果没有配置任何请求谓词,则允许所有请求谓词
|
||||
if (corsAccessorSettings.WithMethods == null || corsAccessorSettings.WithMethods.Length == 0) builder.AllowAnyMethod();
|
||||
else
|
||||
{
|
||||
// 解决 SignarlR 必须允许 GET POST 问题
|
||||
if (isSupportSignarlR)
|
||||
{
|
||||
builder.WithMethods(corsAccessorSettings.WithMethods.Concat(new[] { "GET", "POST" }).Distinct(StringComparer.OrdinalIgnoreCase).ToArray());
|
||||
}
|
||||
else builder.WithMethods(corsAccessorSettings.WithMethods);
|
||||
}
|
||||
|
||||
// 配置跨域凭据,包含处理 SignarlR 情况
|
||||
if ((corsAccessorSettings.AllowCredentials == true && !isNotSetOrigins) || isSupportSignarlR) builder.AllowCredentials();
|
||||
|
||||
// 配置响应头,如果前端不能获取自定义的 header 信息,必须配置该项,默认配置了 access-token 和 x-access-token,可取消默认行为
|
||||
IEnumerable<string> exposedHeaders = corsAccessorSettings.FixedClientToken == true
|
||||
? _defaultExposedHeaders
|
||||
: Array.Empty<string>();
|
||||
if (corsAccessorSettings.WithExposedHeaders != null && corsAccessorSettings.WithExposedHeaders.Length > 0)
|
||||
{
|
||||
exposedHeaders = exposedHeaders.Concat(corsAccessorSettings.WithExposedHeaders).Distinct(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
if (exposedHeaders.Any()) builder.WithExposedHeaders(exposedHeaders.ToArray());
|
||||
|
||||
// 设置预检过期时间,如果不设置默认为 24小时
|
||||
builder.SetPreflightMaxAge(TimeSpan.FromSeconds(corsAccessorSettings.SetPreflightMaxAge ?? 24 * 60 * 60));
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
// 版权归百小僧及百签科技(广东)有限公司所有。
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Furion.CorsAccessor;
|
||||
|
||||
/// <summary>
|
||||
/// 跨域配置选项
|
||||
/// </summary>
|
||||
public sealed class CorsAccessorSettingsOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// 策略名称
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string PolicyName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 允许来源域名,没有配置则允许所有来源
|
||||
/// </summary>
|
||||
public string[] WithOrigins { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求表头,没有配置则允许所有表头
|
||||
/// </summary>
|
||||
public string[] WithHeaders { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设置客户端可获取的响应标头
|
||||
/// </summary>
|
||||
public string[] WithExposedHeaders { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设置跨域允许请求谓词,没有配置则允许所有
|
||||
/// </summary>
|
||||
public string[] WithMethods { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否允许跨域请求中的凭据
|
||||
/// </summary>
|
||||
public bool? AllowCredentials { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设置预检过期时间
|
||||
/// </summary>
|
||||
public int? SetPreflightMaxAge { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 修正前端无法获取 Token 问题
|
||||
/// </summary>
|
||||
public bool? FixedClientToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 启用 SignalR 跨域支持
|
||||
/// </summary>
|
||||
public bool? SignalRSupport { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 后期配置
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="configuration"></param>
|
||||
public void PostConfigure(CorsAccessorSettingsOptions options, IConfiguration configuration)
|
||||
{
|
||||
PolicyName ??= "App.Cors.Policy";
|
||||
WithOrigins ??= Array.Empty<string>();
|
||||
AllowCredentials ??= true;
|
||||
FixedClientToken ??= true;
|
||||
SignalRSupport ??= false;
|
||||
}
|
||||
}
|
||||
@@ -82,7 +82,7 @@ public class Program
|
||||
});
|
||||
}
|
||||
|
||||
builder.Services.AddCors();
|
||||
builder.Services.AddCorsAccessor();
|
||||
|
||||
builder.WebHost.UseWebRoot("wwwroot");
|
||||
//builder.WebHost.UseStaticWebAssets();
|
||||
@@ -193,15 +193,7 @@ public class Program
|
||||
|
||||
app.UseStaticFiles(new StaticFileOptions { ContentTypeProvider = provider });
|
||||
|
||||
app.UseStaticFiles();
|
||||
var cors = app.Configuration["AllowOrigins"]?.Split(',', StringSplitOptions.RemoveEmptyEntries);
|
||||
if (cors?.Length > 0)
|
||||
{
|
||||
app.UseCors(builder => builder.WithOrigins()
|
||||
.AllowAnyHeader()
|
||||
.AllowAnyMethod()
|
||||
.AllowCredentials());
|
||||
}
|
||||
app.UseCorsAccessor();
|
||||
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
@@ -26,7 +26,6 @@ public class SingleFilePublish : ISingleFilePublish
|
||||
/// <returns></returns>
|
||||
public Assembly[] IncludeAssemblies()
|
||||
{
|
||||
// 需要 Furion 框架扫描哪些程序集就写上去即可
|
||||
return Array.Empty<Assembly>();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
"urls": "http://*:5000",
|
||||
|
||||
"ConfigurationScanDirectories": [ "" ],
|
||||
"IgnoreConfigurationFiles": [ "" ],
|
||||
"CorsAccessorSettings": {
|
||||
"WithExposedHeaders": [ "access-token", "x-access-token", "environment" ],
|
||||
"SignalRSupport": true
|
||||
},
|
||||
|
||||
|
||||
//冗余配置
|
||||
"ManagementOptions": {
|
||||
"PrimaryUri": "127.0.0.1:7101", //主(备)站IP
|
||||
|
||||
Reference in New Issue
Block a user