diff --git a/aspnet-core/configuration/messages/LINGYUN.Abp.MessageService.HttpApi.Host/appsettings.Development.json b/aspnet-core/configuration/messages/LINGYUN.Abp.MessageService.HttpApi.Host/appsettings.Development.json
index 97b761933..2501d64b5 100644
--- a/aspnet-core/configuration/messages/LINGYUN.Abp.MessageService.HttpApi.Host/appsettings.Development.json
+++ b/aspnet-core/configuration/messages/LINGYUN.Abp.MessageService.HttpApi.Host/appsettings.Development.json
@@ -1,4 +1,7 @@
{
+ "App": {
+ "CorsOrigins": "http://localhost:9527,http://127.0.0.1:30000"
+ },
"ConnectionStrings": {
"Default": "Server=127.0.0.1;Database=Messages;User Id=root;Password=123456",
"MessageService": "Server=127.0.0.1;Database=Messages;User Id=root;Password=123456",
diff --git a/aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs b/aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs
index 289533348..b28fc772c 100644
--- a/aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs
+++ b/aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs
@@ -183,7 +183,10 @@ namespace AuthServer.Host
app.UseIdentityServer();
app.UseAuditing();
- SeedData(context);
+ if (context.GetEnvironment().IsDevelopment())
+ {
+ SeedData(context);
+ }
}
private void SeedData(ApplicationInitializationContext context)
diff --git a/aspnet-core/services/account/AuthServer.Host/AuthServer.Host.csproj b/aspnet-core/services/account/AuthServer.Host/AuthServer.Host.csproj
index 8b53e7a06..63fa249bc 100644
--- a/aspnet-core/services/account/AuthServer.Host/AuthServer.Host.csproj
+++ b/aspnet-core/services/account/AuthServer.Host/AuthServer.Host.csproj
@@ -40,7 +40,5 @@
-
-
-
+
diff --git a/aspnet-core/services/admin/LINGYUN.BackendAdminApp.Host/BackendAdminHostModule.cs b/aspnet-core/services/admin/LINGYUN.BackendAdminApp.Host/BackendAdminHostModule.cs
index c9d5d9108..613c0558c 100644
--- a/aspnet-core/services/admin/LINGYUN.BackendAdminApp.Host/BackendAdminHostModule.cs
+++ b/aspnet-core/services/admin/LINGYUN.BackendAdminApp.Host/BackendAdminHostModule.cs
@@ -306,7 +306,10 @@ namespace LINGYUN.BackendAdmin
// 路由
app.UseConfiguredEndpoints();
- SeedData(context);
+ if (context.GetEnvironment().IsDevelopment())
+ {
+ SeedData(context);
+ }
}
private void SeedData(ApplicationInitializationContext context)
diff --git a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/ApiGatewayHttpApiHostModule.cs b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/ApiGatewayHttpApiHostModule.cs
index e82316470..704648bf5 100644
--- a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/ApiGatewayHttpApiHostModule.cs
+++ b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/ApiGatewayHttpApiHostModule.cs
@@ -210,7 +210,10 @@ namespace LINGYUN.ApiGateway
// 路由
app.UseConfiguredEndpoints();
- SeedData(context);
+ if (context.GetEnvironment().IsDevelopment())
+ {
+ SeedData(context);
+ }
}
private void SeedData(ApplicationInitializationContext context)
diff --git a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/AbpMessageServiceHttpApiHostModule.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/AbpMessageServiceHttpApiHostModule.cs
index a0750fd17..d12a51e50 100644
--- a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/AbpMessageServiceHttpApiHostModule.cs
+++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/AbpMessageServiceHttpApiHostModule.cs
@@ -16,15 +16,18 @@ using LINGYUN.Abp.MultiTenancy.DbFinder;
using LINGYUN.Abp.Notifications.SignalR;
using LINGYUN.Abp.Notifications.WeChat.WeApp;
using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Caching.StackExchangeRedis;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using StackExchange.Redis;
using System;
+using System.Linq;
using System.Text;
using Volo.Abp;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
@@ -68,6 +71,8 @@ namespace LINGYUN.Abp.MessageService
)]
public class AbpMessageServiceHttpApiHostModule : AbpModule
{
+ private const string DefaultCorsPolicyName = "Default";
+
public override void PreConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
@@ -190,6 +195,35 @@ namespace LINGYUN.Abp.MessageService
});
});
+ context.Services.AddCors(options =>
+ {
+ options.AddPolicy(DefaultCorsPolicyName, builder =>
+ {
+ builder
+ .WithOrigins(
+ configuration["App:CorsOrigins"]
+ .Split(",", StringSplitOptions.RemoveEmptyEntries)
+ .Select(o => o.RemovePostFix("/"))
+ .ToArray()
+ )
+ .WithAbpExposedHeaders()
+ .SetIsOriginAllowedToAllowWildcardSubdomains()
+ .AllowAnyHeader()
+ .AllowAnyMethod()
+ .AllowCredentials();
+ });
+ });
+
+ Configure(options =>
+ {
+ options.WithOrigins(
+ configuration["App:CorsOrigins"]
+ .Split(",", StringSplitOptions.RemoveEmptyEntries)
+ .Select(o => o.RemovePostFix("/"))
+ .ToArray()
+ );
+ });
+
// 支持本地化语言类型
Configure(options =>
{
@@ -241,8 +275,12 @@ namespace LINGYUN.Abp.MessageService
app.UseAbpRequestLocalization();
//路由
app.UseRouting();
+ // 跨域
+ app.UseCors(DefaultCorsPolicyName);
// 加入自定义中间件
app.UseSignalRJwtToken();
+ // TODO: 还有没有其他方法在iframe中传递身份令牌?
+ app.UseHangfireJwtToken();
// 认证
app.UseAuthentication();
// jwt
@@ -263,6 +301,7 @@ namespace LINGYUN.Abp.MessageService
app.UseHangfireServer();
app.UseHangfireDashboard(options =>
{
+ options.IgnoreAntiforgeryToken = true;
options.UseAuthorization(new HangfireDashboardAuthorizationFilter());
});
// 路由
diff --git a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Authorization/HangfireDashboardAuthorizationFilter.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Authorization/HangfireDashboardAuthorizationFilter.cs
index 298b561d2..29862f433 100644
--- a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Authorization/HangfireDashboardAuthorizationFilter.cs
+++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Authorization/HangfireDashboardAuthorizationFilter.cs
@@ -1,7 +1,10 @@
-using Hangfire.Annotations;
+using Hangfire;
+using Hangfire.Annotations;
using Hangfire.Dashboard;
-using LINGYUN.Abp.MessageService.Permissions;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using NUglify.Helpers;
+using System.Linq;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Threading;
@@ -9,18 +12,42 @@ namespace LINGYUN.Abp.MessageService.Authorization
{
public class HangfireDashboardAuthorizationFilter : IDashboardAuthorizationFilter
{
+ protected string[] AllowGrantPath { get; }
+ public HangfireDashboardAuthorizationFilter()
+ {
+ AllowGrantPath = new string[] { "/css", "/js", "/fonts", "/stats" };
+ }
+
public bool Authorize([NotNull] DashboardContext context)
{
+ // 本地请求
+ if (LocalRequestOnlyAuthorize(context))
+ {
+ return true;
+ }
+
+ // 放行路径
+ if (AllowGrantPath.Contains(context.Request.Path))
+ {
+ return true;
+ }
var httpContext = context.GetHttpContext();
- var permissionChecker = httpContext.RequestServices.GetService();
+ var options = httpContext.RequestServices.GetService>()?.Value;
- if (permissionChecker != null)
+ if (options != null)
{
- // 可以详细到每个页面授权,这里就免了
- return AsyncHelper.RunSync(async () => await permissionChecker.IsGrantedAsync(AbpMessageServicePermissions.Hangfire.ManageQueue));
+ // 请求路径对应的权限检查
+ // TODO: 怎么来传递用户身份令牌?
+ var permission = options.GetPermission(context.Request.Path);
+ if (!permission.IsNullOrWhiteSpace())
+ {
+ var permissionChecker = httpContext.RequestServices.GetRequiredService();
+ return AsyncHelper.RunSync(async () => await permissionChecker.IsGrantedAsync(permission));
+ }
}
- return new LocalRequestsOnlyAuthorizationFilter().Authorize(context);
+
+ return false;
}
public override int GetHashCode()
@@ -42,5 +69,25 @@ namespace LINGYUN.Abp.MessageService.Authorization
}
return base.Equals(obj);
}
+
+ protected virtual bool LocalRequestOnlyAuthorize(DashboardContext context)
+ {
+ if (string.IsNullOrEmpty(context.Request.RemoteIpAddress))
+ {
+ return false;
+ }
+
+ if (context.Request.RemoteIpAddress == "127.0.0.1" || context.Request.RemoteIpAddress == "::1")
+ {
+ return true;
+ }
+
+ if (context.Request.RemoteIpAddress == context.Request.LocalIpAddress)
+ {
+ return true;
+ }
+
+ return false;
+ }
}
}
diff --git a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Hangfire/HangfireApplicationBuilderExtensions.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Hangfire/HangfireApplicationBuilderExtensions.cs
index 9b20af009..dedf71955 100644
--- a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Hangfire/HangfireApplicationBuilderExtensions.cs
+++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Hangfire/HangfireApplicationBuilderExtensions.cs
@@ -7,6 +7,12 @@ namespace Hangfire
{
public static class HangfireApplicationBuilderExtensions
{
+ public static IApplicationBuilder UseHangfireJwtToken(
+ [NotNull] this IApplicationBuilder app)
+ {
+ return app.UseMiddleware();
+ }
+
public static IApplicationBuilder UseHangfireDashboard(
[NotNull] this IApplicationBuilder app,
[CanBeNull] Action setup = null)
diff --git a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Hangfire/HangfireDashboardRouteOptions.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Hangfire/HangfireDashboardRouteOptions.cs
new file mode 100644
index 000000000..ee9ea7213
--- /dev/null
+++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Hangfire/HangfireDashboardRouteOptions.cs
@@ -0,0 +1,55 @@
+using LINGYUN.Abp.MessageService.Permissions;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Hangfire
+{
+ public class HangfireDashboardRouteOptions
+ {
+ public IList AllowFrameOrigins { get; }
+ public IDictionary RoutePermissions { get; }
+ public HangfireDashboardRouteOptions()
+ {
+ AllowFrameOrigins = new List();
+ RoutePermissions = new Dictionary();
+ InitDefaultRoutes();
+ }
+
+ public void WithOrigins(params string[] origins)
+ {
+ AllowFrameOrigins.AddIfNotContains(origins);
+ }
+
+ public void WithPermission(string route, string permission)
+ {
+ RoutePermissions.Add(route, permission);
+ }
+
+ public string GetPermission(string route)
+ {
+ var permission = RoutePermissions
+ .Where(x => x.Key.StartsWith(route))
+ .Select(x => x.Value)
+ .FirstOrDefault();
+
+ return permission;
+ }
+
+ private void InitDefaultRoutes()
+ {
+ WithPermission("/hangfire", AbpMessageServicePermissions.Hangfire.Default);
+ WithPermission("/stats", AbpMessageServicePermissions.Hangfire.Default);
+ WithPermission("/servers", AbpMessageServicePermissions.Hangfire.Default);
+ WithPermission("/retries", AbpMessageServicePermissions.Hangfire.Default);
+ WithPermission("/recurring", AbpMessageServicePermissions.Hangfire.Default);
+ WithPermission("/jobs/enqueued", AbpMessageServicePermissions.Hangfire.ManageQueue);
+ WithPermission("/jobs/processing", AbpMessageServicePermissions.Hangfire.ManageQueue);
+ WithPermission("/jobs/scheduled", AbpMessageServicePermissions.Hangfire.ManageQueue);
+ WithPermission("/jobs/failed", AbpMessageServicePermissions.Hangfire.ManageQueue);
+ WithPermission("/jobs/deleted", AbpMessageServicePermissions.Hangfire.ManageQueue);
+ WithPermission("/jobs/awaiting", AbpMessageServicePermissions.Hangfire.ManageQueue);
+ WithPermission("/jobs/actions", AbpMessageServicePermissions.Hangfire.ManageQueue);
+ WithPermission("/jobs/details", AbpMessageServicePermissions.Hangfire.ManageQueue);
+ }
+ }
+}
diff --git a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Hangfire/HangfireJwtTokenMiddleware.cs b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Hangfire/HangfireJwtTokenMiddleware.cs
new file mode 100644
index 000000000..708fc1407
--- /dev/null
+++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/Hangfire/HangfireJwtTokenMiddleware.cs
@@ -0,0 +1,31 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+
+namespace Hangfire
+{
+ public class HangfireJwtTokenMiddleware : IMiddleware, ITransientDependency
+ {
+ public async Task InvokeAsync(HttpContext context, RequestDelegate next)
+ {
+ // 通过 iframe 加载页面的话,需要手动传递 access_token 到参数列表
+ if (context.Request.Path.StartsWithSegments("/hangfire") && context.User.Identity?.IsAuthenticated != true)
+ {
+ if (context.Request.Query.TryGetValue("access_token", out var accessTokens))
+ {
+ context.Request.Headers.Add("Authorization", accessTokens);
+ }
+ var options = context.RequestServices.GetService>()?.Value;
+ if (options != null && options.AllowFrameOrigins.Count > 0)
+ {
+ // 跨域 iframe
+ context.Response.Headers.TryAdd("X-Frame-Options", $"\"ALLOW-FROM {options.AllowFrameOrigins.JoinAsString(",")}\"");
+ }
+ }
+ await next(context);
+ }
+ }
+}
diff --git a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj
index 7f323bee6..f1cb3d2c4 100644
--- a/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj
+++ b/aspnet-core/services/messages/LINGYUN.Abp.MessageService.HttpApi.Host/LINGYUN.Abp.MessageService.HttpApi.Host.csproj
@@ -6,13 +6,13 @@
-
-
+
+
-
-
+
+
diff --git a/vueJs/src/components/HangfireDashboard/index.vue b/vueJs/src/components/HangfireDashboard/index.vue
new file mode 100644
index 000000000..d7e85a34f
--- /dev/null
+++ b/vueJs/src/components/HangfireDashboard/index.vue
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+