Ver código fonte

😁代码优化及其他调整

zuohuaijun 3 anos atrás
pai
commit
3e77ecf51f
33 arquivos alterados com 515 adições e 215 exclusões
  1. 3 3
      Admin.NET/Admin.NET.Core/Entity/SysJobDetail.cs
  2. 2 2
      Admin.NET/Admin.NET.Core/Enum/ErrorCodeEnum.cs
  3. 26 0
      Admin.NET/Admin.NET.Core/Enum/JobCreateTypeEnum.cs
  4. 17 3
      Admin.NET/Admin.NET.Core/Service/Job/DbJobPersistence.cs
  5. 24 12
      Admin.NET/Admin.NET.Core/Service/Job/SysJobService.cs
  6. 1 1
      Admin.NET/Admin.NET.Core/Service/Message/SysMessageService.cs
  7. 8 1
      Admin.NET/Admin.NET.Web.Core/Startup.cs
  8. 4 3
      Web/src/api-services/models/add-job-detail-input.ts
  9. 1 0
      Web/src/api-services/models/index.ts
  10. 24 0
      Web/src/api-services/models/job-create-type-enum.ts
  11. 4 3
      Web/src/api-services/models/sys-job-detail.ts
  12. 4 3
      Web/src/api-services/models/update-job-detail-input.ts
  13. 3 1
      Web/src/layout/navBars/breadcrumb/breadcrumb.vue
  14. 7 0
      Web/src/types/views.d.ts
  15. 101 11
      Web/src/views/system/job/component/editJobDetail.vue
  16. 99 45
      Web/src/views/system/job/index.vue
  17. 3 1
      Web/src/views/system/region/index.vue
  18. 8 3
      docker/app/Configuration/App.json
  19. 2 0
      docker/app/Configuration/Database.json
  20. 2 2
      docker/nginx/conf/nginx.conf
  21. 23 0
      docker/nginx/key/abc.admin.com.crt
  22. 17 0
      docker/nginx/key/abc.admin.com.csr
  23. 28 0
      docker/nginx/key/abc.admin.com.key
  24. 20 0
      docker/nginx/key/abc.admin.com.pem
  25. 22 0
      docker/nginx/key/admin.com.crt
  26. 28 0
      docker/nginx/key/admin.com.key
  27. 22 0
      docker/nginx/key/admin.com.pem
  28. 0 28
      docker/nginx/key/rootCA.key
  29. 0 22
      docker/nginx/key/rootCA.pem
  30. 0 17
      docker/nginx/key/server.csr
  31. 0 28
      docker/nginx/key/server.key
  32. 0 21
      docker/nginx/key/server.pem
  33. 12 5
      docker/nginx/key/ssl.sh

+ 3 - 3
Admin.NET/Admin.NET.Core/Entity/SysJobDetail.cs

@@ -67,10 +67,10 @@ public class SysJobDetail : EntityBaseId
     public DateTime? UpdatedTime { get; set; }
 
     /// <summary>
-    /// 是否为脚本创建的作业
+    /// 作业创建类型
     /// </summary>
-    [SugarColumn(ColumnDescription = "是否为脚本创建的作业")]
-    public bool CreateFromScript { get; set; } = false;
+    [SugarColumn(ColumnDescription = "作业创建类型")]
+    public JobCreateTypeEnum CreateType { get; set; } = JobCreateTypeEnum.BuiltIn;
 
     /// <summary>
     /// 脚本代码

+ 2 - 2
Admin.NET/Admin.NET.Core/Enum/ErrorCodeEnum.cs

@@ -210,13 +210,13 @@ public enum ErrorCodeEnum
     /// </summary>
     [ErrorCodeItemMetadata("只能增加下级机构")]
     D2006,
-    
+
     /// <summary>
     /// 下级机构下有用户禁止删除
     /// </summary>
     [ErrorCodeItemMetadata("下级机构下有用户禁止删除")]
     D2007,
-    
+
     /// <summary>
     /// 租户默认机构禁止删除
     /// </summary>

+ 26 - 0
Admin.NET/Admin.NET.Core/Enum/JobCreateTypeEnum.cs

@@ -0,0 +1,26 @@
+namespace Admin.NET.Core;
+
+/// <summary>
+/// 作业创建类型枚举
+/// </summary>
+[Description("作业创建类型枚举")]
+public enum JobCreateTypeEnum
+{
+    /// <summary>
+    /// 内置
+    /// </summary>
+    [Description("内置")]
+    BuiltIn = 0,
+
+    /// <summary>
+    /// 脚本
+    /// </summary>
+    [Description("脚本")]
+    Script = 1,
+
+    /// <summary>
+    /// HTTP请求
+    /// </summary>
+    [Description("HTTP请求")]
+    Http = 2,
+}

+ 17 - 3
Admin.NET/Admin.NET.Core/Service/Job/DbJobPersistence.cs

@@ -65,11 +65,25 @@ public class DbJobPersistence : IJobPersistence
         }
 
         // 获取数据库所有通过脚本创建的作业
-        var allDbScriptJobs = jobRepository.GetList(u => u.CreateFromScript);
+        var allDbScriptJobs = jobRepository.GetList(u => u.CreateType != JobCreateTypeEnum.BuiltIn);
         foreach (var dbDetail in allDbScriptJobs)
         {
             // 动态创建作业
-            var jobType = dynamicJobCompiler.BuildJob(dbDetail.ScriptCode);
+            Type jobType;
+            switch (dbDetail.CreateType)
+            {
+                case JobCreateTypeEnum.Script:
+                    jobType = dynamicJobCompiler.BuildJob(dbDetail.ScriptCode);
+                    break;
+
+                case JobCreateTypeEnum.Http:
+                    jobType = typeof(HttpJob);
+                    break;
+
+                default:
+                    throw new NotSupportedException();
+            }
+
             var jobBuilder = JobBuilder.Create(jobType).LoadFrom(dbDetail);
 
             // 强行设置为不扫描 IJob 实现类 [Trigger] 特性触发器,否则 SchedulerBuilder.Create 会再次扫描,导致重复添加同名触发器
@@ -116,7 +130,7 @@ public class DbJobPersistence : IJobPersistence
                 break;
 
             case PersistenceBehavior.Updated:
-                jobRepository.AsUpdateable(jobDetail).WhereColumns(u => new { u.JobId }).IgnoreColumns(u => new { u.Id, u.CreateFromScript, u.ScriptCode }).ExecuteCommand();
+                jobRepository.AsUpdateable(jobDetail).WhereColumns(u => new { u.JobId }).IgnoreColumns(u => new { u.Id, u.CreateType, u.ScriptCode }).ExecuteCommand();
                 break;
 
             case PersistenceBehavior.Removed:

+ 24 - 12
Admin.NET/Admin.NET.Core/Service/Job/SysJobService.cs

@@ -67,17 +67,29 @@ public class SysJobService : IDynamicApiController, ITransient
         if (isExist)
             throw Oops.Oh(ErrorCodeEnum.D1006);
 
-        if (string.IsNullOrEmpty(input.ScriptCode))
-            throw Oops.Oh(ErrorCodeEnum.D1701);
-
-        input.CreateFromScript = true;//确保为true
         // 动态创建作业
-        var jobType = _dynamicJobCompiler.BuildJob(input.ScriptCode);
-
-        if (jobType.GetCustomAttributes(typeof(JobDetailAttribute)).FirstOrDefault() is not JobDetailAttribute jobDetailAttribute)
-            throw Oops.Oh(ErrorCodeEnum.D1702);
-        if (jobDetailAttribute.JobId != input.JobId)
-            throw Oops.Oh(ErrorCodeEnum.D1703);
+        Type jobType;
+        switch (input.CreateType)
+        {
+            case JobCreateTypeEnum.Script when string.IsNullOrEmpty(input.ScriptCode):
+                throw Oops.Oh(ErrorCodeEnum.D1701);
+            case JobCreateTypeEnum.Script:
+                {
+                    jobType = _dynamicJobCompiler.BuildJob(input.ScriptCode);
+
+                    if (jobType.GetCustomAttributes(typeof(JobDetailAttribute)).FirstOrDefault() is not JobDetailAttribute jobDetailAttribute)
+                        throw Oops.Oh(ErrorCodeEnum.D1702);
+                    if (jobDetailAttribute.JobId != input.JobId)
+                        throw Oops.Oh(ErrorCodeEnum.D1703);
+                    break;
+                }
+            case JobCreateTypeEnum.Http:
+                jobType = typeof(HttpJob);
+                break;
+
+            default:
+                throw new NotSupportedException();
+        }
 
         _schedulerFactory.AddJob(
             JobBuilder.Create(jobType)
@@ -86,7 +98,7 @@ public class SysJobService : IDynamicApiController, ITransient
         // 延迟一下等待持久化写入,再执行其他字段的更新
         await Task.Delay(500);
         await _sysJobDetailRep.AsUpdateable()
-            .SetColumns(u => new SysJobDetail { CreateFromScript = input.CreateFromScript, ScriptCode = input.ScriptCode })
+            .SetColumns(u => new SysJobDetail { CreateType = input.CreateType, ScriptCode = input.ScriptCode })
             .Where(u => u.JobId == input.JobId).ExecuteCommandAsync();
     }
 
@@ -110,7 +122,7 @@ public class SysJobService : IDynamicApiController, ITransient
         var oldScriptCode = sysJobDetail.ScriptCode;//旧脚本代码
         input.Adapt(sysJobDetail);
 
-        if (input.CreateFromScript)
+        if (input.CreateType == JobCreateTypeEnum.Script)
         {
             if (string.IsNullOrEmpty(input.ScriptCode))
                 throw Oops.Oh(ErrorCodeEnum.D1701);

+ 1 - 1
Admin.NET/Admin.NET.Core/Service/Message/SysMessageService.cs

@@ -76,7 +76,7 @@ public class SysMessageService : IDynamicApiController, ITransient
         foreach (var userid in input.UserIds)
         {
             var user = _sysCacheService.Get<SysOnlineUser>(CacheConst.KeyOnlineUser + userid);
-            if (user!=null) userlist.Add(user.ConnectionId);
+            if (user != null) userlist.Add(user.ConnectionId);
         }
         await _chatHubContext.Clients.Clients(userlist).ReceiveMessage(input);
     }

+ 8 - 1
Admin.NET/Admin.NET.Web.Core/Startup.cs

@@ -3,6 +3,7 @@ using Admin.NET.Core.Service;
 using AspNetCoreRateLimit;
 using Furion;
 using Furion.SpecificationDocument;
+using Furion.VirtualFileServer;
 using IGeekFan.AspNetCore.Knife4jUI;
 using Microsoft.AspNetCore.Builder;
 using Microsoft.AspNetCore.Hosting;
@@ -220,7 +221,13 @@ public class Startup : AppStartup
         //// 启用HTTPS
         //app.UseHttpsRedirection();
 
-        app.UseStaticFiles();
+        // 特定文件类型(文件后缀)处理
+        var contentTypeProvider = FS.GetFileExtensionContentTypeProvider();
+        // contentTypeProvider.Mappings[".文件后缀"] = "MIME 类型";
+        app.UseStaticFiles(new StaticFileOptions
+        {
+            ContentTypeProvider = contentTypeProvider
+        });
 
         app.UseRouting();
 

+ 4 - 3
Web/src/api-services/models/add-job-detail-input.ts

@@ -11,6 +11,7 @@
  * https://github.com/swagger-api/swagger-codegen.git
  * Do not edit the class manually.
  */
+import { JobCreateTypeEnum } from './job-create-type-enum';
 /**
  * 
  * @export
@@ -72,11 +73,11 @@ export interface AddJobDetailInput {
      */
     updatedTime?: Date | null;
     /**
-     * 是否为脚本创建的作业
-     * @type {boolean}
+     * 
+     * @type {JobCreateTypeEnum}
      * @memberof AddJobDetailInput
      */
-    createFromScript?: boolean;
+    createType?: JobCreateTypeEnum;
     /**
      * 脚本代码
      * @type {string}

+ 1 - 0
Web/src/api-services/models/index.ts

@@ -123,6 +123,7 @@ export * from './gen-auth-url-input';
 export * from './gender-enum';
 export * from './iaction-result';
 export * from './jtoken';
+export * from './job-create-type-enum';
 export * from './job-detail-input';
 export * from './job-output';
 export * from './job-trigger-input';

+ 24 - 0
Web/src/api-services/models/job-create-type-enum.ts

@@ -0,0 +1,24 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * 所有接口
+ * 让 .NET 开发更简单、更通用、更流行。前后端分离架构(.NET6/Vue3),开箱即用紧随前沿技术。<br/><a href='https://gitee.com/zuohuaijun/Admin.NET/'>https://gitee.com/zuohuaijun/Admin.NET</a>
+ *
+ * OpenAPI spec version: 1.0.0
+ * Contact: 515096995@qq.com
+ *
+ * NOTE: This class is auto generated by the swagger code generator program.
+ * https://github.com/swagger-api/swagger-codegen.git
+ * Do not edit the class manually.
+ */
+/**
+ * 作业创建类型枚举<br />&nbsp;内置 BuiltIn = 0<br />&nbsp;脚本 Script = 1<br />&nbsp;HTTP Http = 2<br />
+ * @export
+ * @enum {string}
+ */
+export enum JobCreateTypeEnum {
+    NUMBER_0 = 0,
+    NUMBER_1 = 1,
+    NUMBER_2 = 2
+}
+

+ 4 - 3
Web/src/api-services/models/sys-job-detail.ts

@@ -11,6 +11,7 @@
  * https://github.com/swagger-api/swagger-codegen.git
  * Do not edit the class manually.
  */
+import { JobCreateTypeEnum } from './job-create-type-enum';
 /**
  * 系统作业信息表
  * @export
@@ -78,11 +79,11 @@ export interface SysJobDetail {
      */
     updatedTime?: Date | null;
     /**
-     * 是否为脚本创建的作业
-     * @type {boolean}
+     * 
+     * @type {JobCreateTypeEnum}
      * @memberof SysJobDetail
      */
-    createFromScript?: boolean;
+    createType?: JobCreateTypeEnum;
     /**
      * 脚本代码
      * @type {string}

+ 4 - 3
Web/src/api-services/models/update-job-detail-input.ts

@@ -11,6 +11,7 @@
  * https://github.com/swagger-api/swagger-codegen.git
  * Do not edit the class manually.
  */
+import { JobCreateTypeEnum } from './job-create-type-enum';
 /**
  * 
  * @export
@@ -72,11 +73,11 @@ export interface UpdateJobDetailInput {
      */
     updatedTime?: Date | null;
     /**
-     * 是否为脚本创建的作业
-     * @type {boolean}
+     * 
+     * @type {JobCreateTypeEnum}
      * @memberof UpdateJobDetailInput
      */
-    createFromScript?: boolean;
+    createType?: JobCreateTypeEnum;
     /**
      * 脚本代码
      * @type {string}

+ 3 - 1
Web/src/layout/navBars/breadcrumb/breadcrumb.vue

@@ -55,9 +55,11 @@ const isShowBreadcrumb = computed(() => {
 });
 // 面包屑点击时
 const onBreadcrumbClick = (v: RouteItem) => {
+	// eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars
 	const { redirect, path } = v;
 	if (redirect) router.push(redirect);
-	else router.push(path);
+	// 如果没有指定重定向,则不跳转
+	// else if (path) router.push(path);
 };
 // 展开/收起左侧菜单点击
 const onThemeConfigChange = () => {

+ 7 - 0
Web/src/types/views.d.ts

@@ -342,3 +342,10 @@ declare type TableDemoState = {
 		defaultSort: EmptyObjectType;
 	};
 };
+
+// HTTP 作业消息(字段定义来源 Furion 的 HttpJobMessage)
+interface HttpJobMessage {
+	requestUri?: string | null;
+	httpMethod?: string | null;
+	body?: string | null;
+}

+ 101 - 11
Web/src/views/system/job/component/editJobDetail.vue

@@ -11,16 +11,25 @@
 				<el-tab-pane label="作业信息">
 					<el-form :model="state.ruleForm" ref="ruleFormRef" size="default" label-width="130px">
 						<el-row :gutter="35">
-							<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+							<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
 								<el-form-item label="作业编号" prop="jobId" :rules="[{ required: true, message: '作业编号不能为空', trigger: 'blur' }]">
 									<el-input v-model="state.ruleForm.jobId" placeholder="作业编号" :disabled="isEdit" clearable />
 								</el-form-item>
 							</el-col>
-							<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+							<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
 								<el-form-item label="组名称" prop="groupName" :rules="[{ required: true, message: '组名称不能为空', trigger: 'blur' }]">
 									<el-input v-model="state.ruleForm.groupName" placeholder="组名称" clearable />
 								</el-form-item>
 							</el-col>
+							<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+								<el-form-item label="创建类型" prop="createType">
+									<el-radio-group v-model="state.ruleForm.createType" :disabled="isEdit">
+										<el-radio :label="JobCreateTypeEnum.NUMBER_0" v-show="isEdit">内置</el-radio>
+										<el-radio :label="JobCreateTypeEnum.NUMBER_1">脚本</el-radio>
+										<el-radio :label="JobCreateTypeEnum.NUMBER_2">Http请求</el-radio>
+									</el-radio-group>
+								</el-form-item>
+							</el-col>
 							<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
 								<el-form-item label="执行方式" prop="concurrent">
 									<el-radio-group v-model="state.ruleForm.concurrent">
@@ -29,7 +38,7 @@
 									</el-radio-group>
 								</el-form-item>
 							</el-col>
-							<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20" v-show="!isEdit">
+							<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20" v-show="!isEdit && !isHttpCreateType">
 								<el-form-item prop="includeAnnotations">
 									<template v-slot:label>
 										<div>
@@ -46,19 +55,39 @@
 								</el-form-item>
 							</el-col>
 							<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
+								<el-form-item label="描述信息" prop="description">
+									<el-input v-model="state.ruleForm.description" placeholder="描述信息" clearable type="textarea" :autosize="{ minRows: 1, maxRows: 3 }" />
+								</el-form-item>
+							</el-col>
+							<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20" v-if="!isHttpCreateType">
 								<el-form-item label="额外数据" prop="properties">
-									<el-input v-model="state.ruleForm.properties" placeholder="额外数据" clearable type="textarea" />
+									<el-input v-model="state.ruleForm.properties" placeholder="额外数据" clearable type="textarea" :autosize="{ minRows: 3, maxRows: 6 }" />
 								</el-form-item>
 							</el-col>
-							<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
-								<el-form-item label="描述信息" prop="description">
-									<el-input v-model="state.ruleForm.description" placeholder="描述信息" clearable type="textarea" />
+							<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20" v-if="isHttpCreateType">
+								<el-form-item label="请求地址" prop="requestUri">
+									<el-input v-model="state.httpJobMessage.requestUri" placeholder="请求地址" clearable />
+								</el-form-item>
+							</el-col>
+							<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20" v-if="isHttpCreateType">
+								<el-form-item label="请求方法" prop="httpMethod">
+									<el-radio-group v-model="state.httpJobMessage.httpMethod">
+										<el-radio :label="httpMethodDef.get">Get</el-radio>
+										<el-radio :label="httpMethodDef.post">Post</el-radio>
+										<el-radio :label="httpMethodDef.put">Put</el-radio>
+										<el-radio :label="httpMethodDef.delete">Delete</el-radio>
+									</el-radio-group>
+								</el-form-item>
+							</el-col>
+							<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20" v-if="isHttpCreateType">
+								<el-form-item label="请求报文体" prop="body">
+									<el-input v-model="state.httpJobMessage.body" placeholder="请求报文体" clearable type="textarea" :autosize="{ minRows: 3, maxRows: 6 }" />
 								</el-form-item>
 							</el-col>
 						</el-row>
 					</el-form>
 				</el-tab-pane>
-				<el-tab-pane label="脚本代码" :disabled="!state.ruleForm.createFromScript">
+				<el-tab-pane label="脚本代码" :disabled="!isScriptCreateType">
 					<div ref="monacoEditorRef" style="width: 100%; height: 500px"></div>
 				</el-tab-pane>
 			</el-tabs>
@@ -80,7 +109,16 @@ import { JobScriptCode } from './JobScriptCode';
 
 import { getAPI } from '/@/utils/axios-utils';
 import { SysJobApi } from '/@/api-services/api';
-import { UpdateJobDetailInput } from '/@/api-services/models';
+import { JobCreateTypeEnum, UpdateJobDetailInput } from '/@/api-services/models';
+
+// HttpMethod 定义,来源后端 HttpMethod 对象的序列化
+// 下面定义内容【不要】加空格,否则 getHttpJobMessage 中 JSON.stringify(httpJobMessageNet.HttpMethod) 后无法匹配
+const httpMethodDef = {
+	get: '{"Method":"GET"}',
+	post: '{"Method":"POST"}',
+	put: '{"Method":"PUT"}',
+	delete: '{"Method":"DELETE"}',
+};
 
 const props = defineProps({
 	title: String,
@@ -93,6 +131,7 @@ const state = reactive({
 	selectedTabName: '0', // 选中的 tab 页
 	ruleForm: {} as UpdateJobDetailInput,
 	monacoEditor: null as any,
+	httpJobMessage: { requestUri: '', httpMethod: httpMethodDef.get, body: '' } as HttpJobMessage,
 });
 
 // 是否编辑状态
@@ -100,6 +139,16 @@ const isEdit = computed(() => {
 	return state.ruleForm.id != undefined && state.ruleForm.id > 0;
 });
 
+// 是否脚本创建类型
+const isScriptCreateType = computed(() => {
+	return state.ruleForm.createType === JobCreateTypeEnum.NUMBER_1;
+});
+
+// 是否Http请求创建类型
+const isHttpCreateType = computed(() => {
+	return state.ruleForm.createType === JobCreateTypeEnum.NUMBER_2;
+});
+
 // 初始化monacoEditor对象
 var monacoEditor: any = null;
 const initMonacoEditor = () => {
@@ -135,6 +184,11 @@ const openDialog = (row: any) => {
 	state.ruleForm = JSON.parse(JSON.stringify(row));
 	state.isShowDialog = true;
 
+	// Http请求
+	if (state.ruleForm.createType === JobCreateTypeEnum.NUMBER_2) {
+		state.httpJobMessage = getHttpJobMessage(state.ruleForm.properties);
+	}
+
 	// 延迟拿值防止取不到
 	setTimeout(() => {
 		if (monacoEditor == null) initMonacoEditor();
@@ -157,7 +211,29 @@ const cancel = () => {
 const submit = () => {
 	ruleFormRef.value.validate(async (valid: boolean) => {
 		if (!valid) return;
-		state.ruleForm.scriptCode = monacoEditor.getValue();
+
+		// 脚本创建类型
+		if (state.ruleForm.createType === JobCreateTypeEnum.NUMBER_1) {
+			state.ruleForm.scriptCode = monacoEditor.getValue();
+		} else {
+			state.ruleForm.scriptCode = '';
+		}
+
+		// Http请求创建类型
+		if (state.ruleForm.createType === JobCreateTypeEnum.NUMBER_2) {
+			// 将 httpJobMessage 重新封装,按后端 HttpJob 序列化要求,字段要大写开头
+			// HttpJob 约定读取属性为“HttpJob”的值
+			const httpJobPropValue = JSON.stringify({
+				RequestUri: state.httpJobMessage.requestUri,
+				HttpMethod: JSON.parse(state.httpJobMessage.httpMethod + ''),
+				Body: state.httpJobMessage.body,
+				ClientName: 'HttpJob',
+				EnsureSuccessStatusCode: true,
+			});
+			const prop = { HttpJob: httpJobPropValue };
+			state.ruleForm.properties = JSON.stringify(prop);
+		}
+
 		if (state.ruleForm.id != undefined && state.ruleForm.id > 0) {
 			await getAPI(SysJobApi).apiSysJobUpdateJobDetailPost(state.ruleForm);
 		} else {
@@ -167,6 +243,20 @@ const submit = () => {
 	});
 };
 
+// 根据任务属性获取 HttpJobMessage
+const getHttpJobMessage = (properties: string | undefined | null): HttpJobMessage => {
+	if (properties === undefined || properties === null || properties === '') return {};
+
+	const propData = JSON.parse(properties);
+	const httpJobMessageNet = JSON.parse(propData['HttpJob']); // 后端大写开头的 HttpJobMessage
+
+	return {
+		requestUri: httpJobMessageNet.RequestUri,
+		httpMethod: JSON.stringify(httpJobMessageNet.HttpMethod),
+		body: httpJobMessageNet.Body,
+	};
+};
+
 // 导出对象
-defineExpose({ openDialog });
+defineExpose({ httpMethodDef, openDialog, getHttpJobMessage });
 </script>

+ 99 - 45
Web/src/views/system/job/index.vue

@@ -44,28 +44,28 @@
 			<el-table :data="state.jobData" style="width: 100%" v-loading="state.loading" border>
 				<el-table-column type="expand" fixed>
 					<template #default="scope">
-						<el-table style="margin-left: 48px; width: calc(100% - 48px)" :data="scope.row.jobTriggers" border size="small">
+						<el-table style="margin-left: 48px; width: calc(100% - 48px)" :data="(scope.row as JobOutput).jobTriggers" border size="small">
 							<el-table-column type="index" label="序号" width="55" align="center" fixed />
 							<el-table-column prop="triggerId" label="触发器编号" width="120" fixed show-overflow-tooltip />
 							<el-table-column prop="triggerType" label="类型" show-overflow-tooltip />
-							<el-table-column prop="assemblyName" label="程序集" show-overflow-tooltip />
+							<!-- <el-table-column prop="assemblyName" label="程序集" show-overflow-tooltip /> -->
 							<el-table-column prop="args" label="参数" show-overflow-tooltip />
 							<el-table-column prop="description" label="描述" width="120" show-overflow-tooltip />
 							<el-table-column prop="status" label="状态" width="100" align="center" show-overflow-tooltip>
 								<template #default="scope">
-									<el-tag type="warning" effect="plain" v-if="scope.row.status == 0"> 积压 </el-tag>
-									<el-tag type="" effect="plain" v-if="scope.row.status == 1"> 就绪 </el-tag>
-									<el-tag type="success" effect="plain" v-if="scope.row.status == 2"> 正在运行 </el-tag>
-									<el-tag type="danger" effect="plain" v-if="scope.row.status == 3"> 暂停 </el-tag>
-									<el-tag type="danger" effect="plain" v-if="scope.row.status == 4"> 阻塞 </el-tag>
-									<el-tag type="" effect="plain" v-if="scope.row.status == 5"> 由失败进入就绪 </el-tag>
-									<el-tag type="danger" effect="plain" v-if="scope.row.status == 6"> 归档 </el-tag>
-									<el-tag type="danger" effect="plain" v-if="scope.row.status == 7"> 崩溃 </el-tag>
-									<el-tag type="danger" effect="plain" v-if="scope.row.status == 8"> 超限 </el-tag>
-									<el-tag type="danger" effect="plain" v-if="scope.row.status == 9"> 无触发时间 </el-tag>
-									<el-tag type="danger" effect="plain" v-if="scope.row.status == 10"> 未启动 </el-tag>
-									<el-tag type="danger" effect="plain" v-if="scope.row.status == 11"> 未知作业触发器 </el-tag>
-									<el-tag type="danger" effect="plain" v-if="scope.row.status == 12"> 未知作业处理程序 </el-tag>
+									<el-tag type="warning" effect="plain" v-if="(scope.row as SysJobTrigger).status == 0"> 积压 </el-tag>
+									<el-tag type="" effect="plain" v-if="(scope.row as SysJobTrigger).status == 1"> 就绪 </el-tag>
+									<el-tag type="success" effect="plain" v-if="(scope.row as SysJobTrigger).status == 2"> 正在运行 </el-tag>
+									<el-tag type="danger" effect="plain" v-if="(scope.row as SysJobTrigger).status == 3"> 暂停 </el-tag>
+									<el-tag type="danger" effect="plain" v-if="(scope.row as SysJobTrigger).status == 4"> 阻塞 </el-tag>
+									<el-tag type="" effect="plain" v-if="(scope.row as SysJobTrigger).status == 5"> 由失败进入就绪 </el-tag>
+									<el-tag type="danger" effect="plain" v-if="(scope.row as SysJobTrigger).status == 6"> 归档 </el-tag>
+									<el-tag type="danger" effect="plain" v-if="(scope.row as SysJobTrigger).status == 7"> 崩溃 </el-tag>
+									<el-tag type="danger" effect="plain" v-if="(scope.row as SysJobTrigger).status == 8"> 超限 </el-tag>
+									<el-tag type="danger" effect="plain" v-if="(scope.row as SysJobTrigger).status == 9"> 无触发时间 </el-tag>
+									<el-tag type="danger" effect="plain" v-if="(scope.row as SysJobTrigger).status == 10"> 未启动 </el-tag>
+									<el-tag type="danger" effect="plain" v-if="(scope.row as SysJobTrigger).status == 11"> 未知作业触发器 </el-tag>
+									<el-tag type="danger" effect="plain" v-if="(scope.row as SysJobTrigger).status == 12"> 未知作业处理程序 </el-tag>
 								</template>
 							</el-table-column>
 							<el-table-column prop="startTime" label="起始时间" width="100" align="center" show-overflow-tooltip />
@@ -80,19 +80,19 @@
 							<el-table-column prop="retryTimeout" label="重试间隔ms" width="100" align="center" show-overflow-tooltip />
 							<el-table-column prop="startNow" label="是否立即启动" width="100" align="center" show-overflow-tooltip>
 								<template #default="scope">
-									<el-tag v-if="scope.row.startNow == true"> 是 </el-tag>
+									<el-tag v-if="(scope.row as SysJobTrigger).startNow == true"> 是 </el-tag>
 									<el-tag type="info" v-else> 否 </el-tag>
 								</template>
 							</el-table-column>
 							<el-table-column prop="runOnStart" label="是否启动时执行一次" width="150" align="center" show-overflow-tooltip>
 								<template #default="scope">
-									<el-tag v-if="scope.row.runOnStart == true"> 是 </el-tag>
+									<el-tag v-if="(scope.row as SysJobTrigger).runOnStart == true"> 是 </el-tag>
 									<el-tag type="info" v-else> 否 </el-tag>
 								</template>
 							</el-table-column>
 							<el-table-column prop="resetOnlyOnce" label="是否重置触发次数" width="120" align="center" show-overflow-tooltip>
 								<template #default="scope">
-									<el-tag v-if="scope.row.resetOnlyOnce == true"> 是 </el-tag>
+									<el-tag v-if="(scope.row as SysJobTrigger).resetOnlyOnce == true"> 是 </el-tag>
 									<el-tag type="info" v-else> 否 </el-tag>
 								</template>
 							</el-table-column>
@@ -117,37 +117,60 @@
 					</template>
 				</el-table-column>
 				<el-table-column type="index" label="序号" width="55" align="center" fixed />
-				<el-table-column prop="jobDetail.jobId" label="作业编号" width="150" fixed>
+				<el-table-column prop="jobDetail.jobId" label="作业编号" width="180" fixed>
 					<template #default="scope">
 						<div style="display: flex; align-items: center">
 							<el-icon><timer /></el-icon>
-							<span style="margin-left: 5px">{{ scope.row.jobDetail.jobId }}</span>
+							<span style="margin-left: 5px">{{ (scope.row as JobOutput).jobDetail?.jobId }}</span>
 						</div>
 					</template>
 				</el-table-column>
-				<el-table-column prop="jobDetail.groupName" label="组名称" show-overflow-tooltip />
+				<el-table-column prop="jobDetail.groupName" label="组名称" width="100" show-overflow-tooltip />
 				<el-table-column prop="jobDetail.jobType" label="类型" show-overflow-tooltip />
-				<el-table-column prop="jobDetail.assemblyName" label="程序集" show-overflow-tooltip />
+				<!-- <el-table-column prop="jobDetail.assemblyName" label="程序集" show-overflow-tooltip /> -->
 				<el-table-column prop="jobDetail.description" label="描述" show-overflow-tooltip />
-				<el-table-column prop="jobDetail.concurrent" label="执行方式" width="100" align="center" show-overflow-tooltip>
+				<el-table-column prop="jobDetail.concurrent" label="执行方式" width="90" align="center" show-overflow-tooltip>
 					<template #default="scope">
-						<el-tag type="success" v-if="scope.row.jobDetail.concurrent == true"> 并行 </el-tag>
+						<el-tag type="success" v-if="(scope.row as JobOutput).jobDetail?.concurrent == true"> 并行 </el-tag>
 						<el-tag type="warning" v-else> 串行 </el-tag>
 					</template>
 				</el-table-column>
-				<el-table-column prop="jobDetail.createFromScript" label="脚本创建" width="100" align="center" show-overflow-tooltip>
+				<el-table-column prop="jobDetail.createType" label="作业创建类型" width="110" align="center" show-overflow-tooltip>
 					<template #default="scope">
-						<el-tag v-if="scope.row.jobDetail.createFromScript == true"> 是 </el-tag>
-						<el-tag type="info" v-else> 否 </el-tag>
+						<el-tag type="info" v-if="(scope.row as JobOutput).jobDetail?.createType == JobCreateTypeEnum.NUMBER_0"> 内置 </el-tag>
+						<el-tag type="warning" v-if="(scope.row as JobOutput).jobDetail?.createType == JobCreateTypeEnum.NUMBER_1"> 脚本 </el-tag>
+						<el-tag type="success" v-if="(scope.row as JobOutput).jobDetail?.createType == JobCreateTypeEnum.NUMBER_2"> HTTP请求 </el-tag>
 					</template>
 				</el-table-column>
 				<!-- <el-table-column prop="jobDetail.includeAnnotations" label="扫描特性触发器" align="center" show-overflow-tooltip>
 					<template #default="scope">
-						<el-tag v-if="scope.row.jobDetail.includeAnnotations == true"> 是 </el-tag>
+						<el-tag v-if="(scope.row as JobOutput).jobDetail?.includeAnnotations == true"> 是 </el-tag>
 						<el-tag v-else> 否 </el-tag>
 					</template>
 				</el-table-column> -->
-				<el-table-column prop="jobDetail.properties" label="额外数据" show-overflow-tooltip />
+				<el-table-column prop="jobDetail.properties" label="额外数据" show-overflow-tooltip>
+					<template #default="scope">
+						<span v-if="(scope.row as JobOutput).jobDetail?.createType != JobCreateTypeEnum.NUMBER_2"> {{ (scope.row as JobOutput).jobDetail?.properties }} </span>
+						<div v-else style="text-align: center">
+							<el-popover placement="left" :width="400" trigger="hover">
+								<template #reference>
+									<el-tag effect="plain" type="info"> 请求参数 </el-tag>
+								</template>
+								<el-descriptions title="Http 请求参数" :column="1" size="small" :border="true">
+									<el-descriptions-item label="请求地址" label-align="right" label-class-name="job-index-descriptions-label-style">
+										{{ getHttpJobMessage((scope.row as JobOutput).jobDetail?.properties).requestUri }}
+									</el-descriptions-item>
+									<el-descriptions-item label="请求方法" label-align="right" label-class-name="job-index-descriptions-label-style">
+										{{ getHttpMethodDesc(getHttpJobMessage((scope.row as JobOutput).jobDetail?.properties).httpMethod) }}
+									</el-descriptions-item>
+									<el-descriptions-item label="请求报文体" label-align="right" label-class-name="job-index-descriptions-label-style">
+										{{ getHttpJobMessage((scope.row as JobOutput).jobDetail?.properties).body }}
+									</el-descriptions-item>
+								</el-descriptions>
+							</el-popover>
+						</div>
+					</template>
+				</el-table-column>
 				<el-table-column prop="jobDetail.updatedTime" label="更新时间" width="160" align="center" show-overflow-tooltip />
 				<el-table-column label="操作" width="170" fixed="right" align="center" show-overflow-tooltip>
 					<template #default="scope">
@@ -199,7 +222,7 @@ import JobCluster from '/@/views/system/job/component/jobCluster.vue';
 
 import { getAPI } from '/@/utils/axios-utils';
 import { SysJobApi } from '/@/api-services/api';
-import { JobOutput } from '/@/api-services/models';
+import { JobCreateTypeEnum, JobOutput, SysJobTrigger } from '/@/api-services/models';
 
 const router = useRouter();
 const editJobDetailRef = ref<InstanceType<typeof EditJobDetail>>();
@@ -253,24 +276,24 @@ const resetQuery = () => {
 // 打开新增作业页面
 const openAddJobDetail = () => {
 	state.editJobDetailTitle = '添加作业';
-	editJobDetailRef.value?.openDialog({ concurrent: true, includeAnnotations: true, groupName: 'default', createFromScript: true });
+	editJobDetailRef.value?.openDialog({ concurrent: true, includeAnnotations: true, groupName: 'default', createType: JobCreateTypeEnum.NUMBER_2 });
 };
 
 // 打开编辑作业页面
-const openEditJobDetail = (row: any) => {
+const openEditJobDetail = (row: JobOutput) => {
 	state.editJobDetailTitle = '编辑作业';
 	editJobDetailRef.value?.openDialog(row.jobDetail);
 };
 
 // 删除作业
-const delJobDetail = (row: any) => {
-	ElMessageBox.confirm(`确定删除作业:【${row.jobDetail.jobId}】?`, '提示', {
+const delJobDetail = (row: JobOutput) => {
+	ElMessageBox.confirm(`确定删除作业:【${row.jobDetail?.jobId}】?`, '提示', {
 		confirmButtonText: '确定',
 		cancelButtonText: '取消',
 		type: 'warning',
 	})
 		.then(async () => {
-			await getAPI(SysJobApi).apiSysJobDeleteJobDetailPost({ jobId: row.jobDetail.jobId });
+			await getAPI(SysJobApi).apiSysJobDeleteJobDetailPost({ jobId: row.jobDetail?.jobId });
 			handleQuery();
 			ElMessage.success('删除成功');
 		})
@@ -278,19 +301,19 @@ const delJobDetail = (row: any) => {
 };
 
 // 打开新增触发器页面
-const openAddJobTrigger = (row: any) => {
+const openAddJobTrigger = (row: JobOutput) => {
 	state.editJobTriggerTitle = '添加触发器';
-	editJobTriggerRef.value?.openDialog({ jobId: row.jobDetail.jobId, retryTimeout: 1000, startNow: true, runOnStart: true, resetOnlyOnce: true, triggerType: 'Furion.Schedule.PeriodTrigger' });
+	editJobTriggerRef.value?.openDialog({ jobId: row.jobDetail?.jobId, retryTimeout: 1000, startNow: true, runOnStart: true, resetOnlyOnce: true, triggerType: 'Furion.Schedule.PeriodTrigger' });
 };
 
 // 打开编辑触发器页面
-const openEditJobTrigger = (row: any) => {
+const openEditJobTrigger = (row: SysJobTrigger) => {
 	state.editJobTriggerTitle = '编辑触发器';
 	editJobTriggerRef.value?.openDialog(row);
 };
 
 // 删除触发器
-const delJobTrigger = (row: any) => {
+const delJobTrigger = (row: SysJobTrigger) => {
 	ElMessageBox.confirm(`确定删除触发器:【${row.triggerId}】?`, '提示', {
 		confirmButtonText: '确定',
 		cancelButtonText: '取消',
@@ -329,25 +352,25 @@ const pauseAllJob = async () => {
 };
 
 // 启动某个作业
-const startJob = async (row: any) => {
-	await getAPI(SysJobApi).apiSysJobStartJobPost({ jobId: row.jobDetail.jobId });
+const startJob = async (row: JobOutput) => {
+	await getAPI(SysJobApi).apiSysJobStartJobPost({ jobId: row.jobDetail?.jobId });
 	ElMessage.success('启动作业');
 };
 
 // 暂停某个作业
-const pauseJob = async (row: any) => {
-	await getAPI(SysJobApi).apiSysJobPauseJobPost({ jobId: row.jobDetail.jobId });
+const pauseJob = async (row: JobOutput) => {
+	await getAPI(SysJobApi).apiSysJobPauseJobPost({ jobId: row.jobDetail?.jobId });
 	ElMessage.success('暂停作业');
 };
 
 // 启动触发器
-const startTrigger = async (row: any) => {
+const startTrigger = async (row: SysJobTrigger) => {
 	await getAPI(SysJobApi).apiSysJobStartTriggerPost({ jobId: row.jobId, triggerId: row.triggerId });
 	ElMessage.success('启动触发器');
 };
 
 // 暂停触发器
-const pauseTrigger = async (row: any) => {
+const pauseTrigger = async (row: SysJobTrigger) => {
 	await getAPI(SysJobApi).apiSysJobPauseTriggerPost({ jobId: row.jobId, triggerId: row.triggerId });
 	ElMessage.success('暂停触发器');
 };
@@ -375,4 +398,35 @@ const openJobDashboard = () => {
 		path: '/platform/job/dashboard',
 	});
 };
+
+// 根据任务属性获取 HttpJobMessage
+const getHttpJobMessage = (properties: string | undefined | null): HttpJobMessage => {
+	if (properties === undefined || properties === null || properties === '') return {};
+
+	const propData = JSON.parse(properties);
+	const httpJobMessageNet = JSON.parse(propData['HttpJob']); // 后端大写开头的 HttpJobMessage
+
+	return {
+		requestUri: httpJobMessageNet.RequestUri,
+		httpMethod: JSON.stringify(httpJobMessageNet.HttpMethod),
+		body: httpJobMessageNet.Body,
+	};
+};
+
+// 获取请求方法的对应描述
+const getHttpMethodDesc = (httpMethodStr: string | undefined | null): string => {
+	if (httpMethodStr === undefined || httpMethodStr === null || httpMethodStr === '') return '';
+
+	for (const key in editJobDetailRef.value?.httpMethodDef) {
+		if (editJobDetailRef.value?.httpMethodDef[key] === httpMethodStr) return key;
+	}
+	return '';
+};
 </script>
+
+<style>
+/* 此样式不能为 scoped */
+.job-index-descriptions-label-style {
+	width: 80px;
+}
+</style>

+ 3 - 1
Web/src/views/system/region/index.vue

@@ -77,6 +77,7 @@ const state = reactive({
 	regionData: [] as Array<SysRegion>, // 列表数据
 	queryParams: {
 		id: -1,
+    pid: undefined,
 		name: undefined,
 		code: undefined,
 	},
@@ -116,6 +117,7 @@ const handleQuery = async () => {
 // 重置操作
 const resetQuery = () => {
 	state.queryParams.id = -1;
+  state.queryParams.pid = undefined;
 	state.queryParams.name = undefined;
 	state.queryParams.code = undefined;
 	handleQuery();
@@ -150,7 +152,7 @@ const delRegion = (row: any) => {
 
 // 树组件点击
 const nodeClick = async (node: any) => {
-	state.queryParams.id = node.id;
+	state.queryParams.pid = node.id;
 	state.queryParams.name = undefined;
 	state.queryParams.code = undefined;
 	handleQuery();

+ 8 - 3
docker/app/Configuration/App.json

@@ -1,5 +1,5 @@
 {
-    "$schema": "https://gitee.com/dotnetchina/Furion/raw/net6/schemas/v3/furion-schema.json",
+    "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
 
     "Urls": "http://*:5050", // 配置默认端口
     //"https_port": 44326,
@@ -10,10 +10,10 @@
         "InjectSpecificationDocument": true // 生产环境是否开启Swagger
     },
     "DynamicApiControllerSettings": {
-        "DefaultRoutePrefix": "api", // 默认路由前缀
+        //"DefaultRoutePrefix": "api", // 默认路由前缀
         "CamelCaseSeparator": "", // 骆驼(驼峰)/帕斯卡命名分隔符
         "LowercaseRoute": false, // 小写路由格式
-        "AsLowerCamelCase": true, // 启用小驼峰命名(首字母小写)
+        "AsLowerCamelCase": true // 启用小驼峰命名(首字母小写)
         //"KeepVerb": false // 保留动作谓词
         //"KeepName": true // 保留默认名称
     },
@@ -30,6 +30,11 @@
         "WithExposedHeaders": [ "Content-Disposition", "X-Pagination", "access-token", "x-access-token" ], // 如果前端不代理且是axios请求
         "SignalRSupport": true // 启用 SignalR 跨域支持
     },
+    "SnowId": {
+        "WorkerId": 1, // 机器码 全局唯一
+        "WorkerIdBitLength": 1, // 机器码位长 默认值6,取值范围 [1, 19]
+        "SeqBitLength": 6 // 序列数位长 默认值6,取值范围 [3, 21](建议不小于4)
+    },
     "Cryptogram": {
         "CryptoType": "SM2", // 密码加密算法 MD5、SM2(国密)
         "PublicKey": "04F6E0C3345AE42B51E06BF50B98834988D54EBC7460FE135A48171BC0629EAE205EEDE253A530608178A98F1E19BB737302813BA39ED3FA3C51639D7A20C7391A", // 公钥

+ 2 - 0
docker/app/Configuration/Database.json

@@ -8,6 +8,7 @@
                 "DbType": "MySql", // MySql、SqlServer、Sqlite、Oracle、PostgreSQL、Dm、Kdbndp、Oscar、MySqlConnector、Access、OpenGauss、QuestDB、HG、ClickHouse、GBase、Odbc、Custom
                 "ConnectionString": "server=mysql;Database=admin;Uid=root;Pwd=root;",
                 "EnableInitDb": true, // 启用库表初始化
+				"EnableInitSeed": true, // 启用种子初始化
                 "EnableDiffLog": false, // 启用库表差异日志
                 "EnableUnderLine": true // 启用驼峰转下划线
             },
@@ -16,6 +17,7 @@
                 "DbType": "MySql",
                 "ConnectionString": "server=mysql;Database=test;Uid=root;Pwd=root;",
                 "EnableInitDb": true, // 启用库表初始化
+				"EnableInitSeed": true, // 启用种子初始化
                 "EnableDiffLog": false, // 启用库表差异日志
                 "EnableUnderLine": true // 启用驼峰转下划线
             }

+ 2 - 2
docker/nginx/conf/nginx.conf

@@ -25,8 +25,8 @@ http {
         listen       80;
         server_name  localhost;
         charset utf-8;
-		ssl_certificate      /etc/nginx/key/server.pem;
-        ssl_certificate_key  /etc/nginx/key/server.key;
+		ssl_certificate      /etc/nginx/key/abc.admin.com.pem;
+        ssl_certificate_key  /etc/nginx/key/abc.admin.com.key;
         ssl_session_cache    shared:SSL:1m;
         location / {
             root   /usr/share/nginx/html;

+ 23 - 0
docker/nginx/key/abc.admin.com.crt

@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIID6TCCAtGgAwIBAgIUaMxuYItti+c4Rj+p/bT43EdG6mcwDQYJKoZIhvcNAQEL
+BQAwZzELMAkGA1UEBhMCVVMxDTALBgNVBAgMBFV0YWgxDTALBgNVBAcMBExlaGkx
+GTAXBgNVBAoMEEFCQyBDb21wYW55LEluYy4xCzAJBgNVBAsMAklUMRIwEAYDVQQD
+DAlhZG1pbi5jb20wHhcNMjMwMzI4MDg0NDA0WhcNMzYxMjA0MDg0NDA0WjBrMQsw
+CQYDVQQGEwJVUzENMAsGA1UECAwEVXRhaDENMAsGA1UEBwwETGVoaTEZMBcGA1UE
+CgwQQUJDIENvbXBhbnksSW5jLjELMAkGA1UECwwCSVQxFjAUBgNVBAMMDWFiYy5h
+ZG1pbi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCn0L97ITGf
+i2KFMBm8lzz9VGfZ0iKMi0ijHH5pVOPqsgA19phQ0DZ6G4Wy1EbdF3wnWZdDEYke
+nqxHVykzulFN9W3Tc5Ao67zBZLcBc8Oe9zo88nh/J03ds8nyPhY3zTptAGKsEeoS
+Ko0LY7m1Ozf2npLa2E+NH815/+WzMoM3jvi3iCXWJ4bvvhjNPDp+oqY+6wzcU9SM
+T+zMvRPoVmVvevVhzSpfH2dhZG44mBcTdkaxnvxuEJm8uAfAA1vFCyM/2n3gDUGO
+IxQSv6nNKgVnIqsa9/gWOjR3EoOejw6a+Hlx9hFL9Tv4hsJ0o2AKsjGl5WchNvIt
+ONQgeeHAGUMzAgMBAAGjgYgwgYUwQwYDVR0RBDwwOocEfwAAAYcEwKgBAYcEwKgA
+/IINYWJjLmFkbWluLmNvbYIMbXguYWRtaW4uY29tgglsb2NhbGhvc3QwHQYDVR0O
+BBYEFB0HsgY6EF2yi6+Czg6xUn/25NmzMB8GA1UdIwQYMBaAFJFdp03B0hlqnbc+
+Ko98wa7Wj7EpMA0GCSqGSIb3DQEBCwUAA4IBAQAFAvdmaSGZtyGwbeZtft9R7BHP
+dxYDgCYvKZJ0BNtE06E5V6m8b8GilVPLGvDwWftXWPMX5Vq2WSq22fPVqG0pdmPR
+bit80G7rlauY5Ub/ws785F9ZoTPM71kO55eHHAFaKqGT7UMGairyk8Je8fYV4SZ/
+YCseDOidSN47Rq1ZRbbc3og5zTtFwrfWuv8uP0acgUayT1cAVg/D3SOmljIp3X+S
+5i+OQQK96AC6RbFczL8ErCJwhS0CAwHc1Q3EBTliOBXMeMy/B965DtwQl5rMwCHk
+HIFTMIj4006O3tEksR/33DThqENnxj6bKL3Pt0Mu5XkRKVl6k1vf2IgYM29L
+-----END CERTIFICATE-----

+ 17 - 0
docker/nginx/key/abc.admin.com.csr

@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICsDCCAZgCAQAwazELMAkGA1UEBhMCVVMxDTALBgNVBAgMBFV0YWgxDTALBgNV
+BAcMBExlaGkxGTAXBgNVBAoMEEFCQyBDb21wYW55LEluYy4xCzAJBgNVBAsMAklU
+MRYwFAYDVQQDDA1hYmMuYWRtaW4uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAp9C/eyExn4tihTAZvJc8/VRn2dIijItIoxx+aVTj6rIANfaYUNA2
+ehuFstRG3Rd8J1mXQxGJHp6sR1cpM7pRTfVt03OQKOu8wWS3AXPDnvc6PPJ4fydN
+3bPJ8j4WN806bQBirBHqEiqNC2O5tTs39p6S2thPjR/Nef/lszKDN474t4gl1ieG
+774YzTw6fqKmPusM3FPUjE/szL0T6FZlb3r1Yc0qXx9nYWRuOJgXE3ZGsZ78bhCZ
+vLgHwANbxQsjP9p94A1BjiMUEr+pzSoFZyKrGvf4Fjo0dxKDno8Omvh5cfYRS/U7
++IbCdKNgCrIxpeVnITbyLTjUIHnhwBlDMwIDAQABoAAwDQYJKoZIhvcNAQELBQAD
+ggEBACLBJSKDMGJd97ruygNmlzboOi+1dTbxvYM9dkB5EEbz9ixif5M81fE+/oMk
+IbuBiqiKATjBlwXnU5nTBK+llw9r+Ro2pa4pSjEcpfD1cZS9r/ap1EAOxy++x215
+Jt87U2/xFMnYdsmSZgb+LtkaVJyiaK1tW/dbPbqhu0/wWaB394XxnfkJre4u207o
+TRMHLaVzU1t8OJ/aFkisoiWKhAQ32DK1gulLUoujBeFmN7HSQpXmIueV9T1nfHFU
+2XMYNQ4o1w35rt4n2oAguUlqZ6w8z90xfBbxI3V0QP4ejw5Z4hIRLajDano5GymP
+jcTrbtN5b1dUt52DZ73jXaVXdU0=
+-----END CERTIFICATE REQUEST-----

+ 28 - 0
docker/nginx/key/abc.admin.com.key

@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCn0L97ITGfi2KF
+MBm8lzz9VGfZ0iKMi0ijHH5pVOPqsgA19phQ0DZ6G4Wy1EbdF3wnWZdDEYkenqxH
+VykzulFN9W3Tc5Ao67zBZLcBc8Oe9zo88nh/J03ds8nyPhY3zTptAGKsEeoSKo0L
+Y7m1Ozf2npLa2E+NH815/+WzMoM3jvi3iCXWJ4bvvhjNPDp+oqY+6wzcU9SMT+zM
+vRPoVmVvevVhzSpfH2dhZG44mBcTdkaxnvxuEJm8uAfAA1vFCyM/2n3gDUGOIxQS
+v6nNKgVnIqsa9/gWOjR3EoOejw6a+Hlx9hFL9Tv4hsJ0o2AKsjGl5WchNvItONQg
+eeHAGUMzAgMBAAECggEAO7Rok7GVGpq4FAOvfGngYI7pndUFxrP9RU7raKUzq3nl
+2k0gFsxlPV9SW3PrvFhRKxzUVJ/GBZdVWtJXTdiReaeCifL5DJ4GW1XuSD18ETAL
+T8jCdxawPNrs09skA3loOoSjFm4PNaRe5vj1htWJTRxQyjygXOi+LZQOEIm9poOL
+UZwlDUDco4K46lrW1znwym6idpEkZ0tYh5c9Szf0KOwmrP6cp63bqRK3Yr7pt7ry
+ooKDzhxe/kvdOOlz1RrI+NWiJxYwcG+LEIVWRggqQmC4Aw2EgqOSsqmKLlBaZruA
+LcmmS7ZBQQx93NAB6BBLC5W5yCq2K5FnF/C6oJvimQKBgQDKZAIsi+SLfshqLxwB
+tCx6xE4/94hhbBmKKDMgsREQLUHwxL31V9WO92dl9n7DSe/TFIrEnjhNZcOH7SSM
+rsszYbRkmngxeU25xZQIqY8/cSzzobmdWAQ9HMZkcyqJlPxjFervW0HKvAJf1Yxk
+B0I1ZZWGXRGVe+IZi0JKyu1iiwKBgQDURDaJUuRyGLK/T5lIkq2Mq2fSFxnXs+5t
+uLoYhMmt8LQAi0fae+wEggHQcInOPmo/RR8sBMkQLpXoEdGLDuilEzuaFxCDq6xj
+h2UenM5pVUFdmWKikXVDkwOZcVBz1vpLDqhNEZKTdhAMjQ1Y/yt2SFRXshiRQ6d/
+JHSn9Jx++QKBgCUhGcEAXQo2VSAdyl6JpktTbiOQDsYIpdrRqyeJNF8qXlmETnEP
+Dw+uVZrAENtU2hl4QEj32c5hJ/Ds0XK5sm+XshduuzQgU+EL3S+Fo9D4u01q0vmJ
+pyVq/P56nkglO/QVlkcZD8XYnfrk21+ScVQIcdj3g/1Pf9g90wiTl98nAoGAfCcZ
+ruBo9cM0aWlpQmVoVOq8YslYOC3puwtc7ZJdU/uBjP/qGwR4W3qfDQeF0rf29OK9
+BMYXw/s7eu1RHoCt2j+RkOMEqb7zqZM7tdgJctqGzPQ2GNfzOn72j/0TDW4kH1qH
+Xex1SwK3CGBH+lHlXd2YV2K3s99aTKdKBCKyliECgYAIzxFHKtE5rR4s6jjCvkVR
+chCdB4+ZOhcq6kxFQZfL3wEHGPNACgV8SxaYKxvMC901tfnwF8mYFjNOKHvCv51v
+zGU1MZeRNqvylA1qEBk2YC8EYW++8vxtPZi3sqt5XWPuPAsiM+wq0CTEsnRbnMBz
+1CN0ZpoW8SJlP1I/0+D1UQ==
+-----END PRIVATE KEY-----

+ 20 - 0
docker/nginx/key/abc.admin.com.pem

@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDWzCCAkMCFGGtfh5AXKkyuDGfnTa1i/qhdKxrMA0GCSqGSIb3DQEBCwUAMGcx
+CzAJBgNVBAYTAlVTMQ0wCwYDVQQIDARVdGFoMQ0wCwYDVQQHDARMZWhpMRkwFwYD
+VQQKDBBBQkMgQ29tcGFueSxJbmMuMQswCQYDVQQLDAJJVDESMBAGA1UEAwwJYWRt
+aW4uY29tMCAXDTIzMDMyODA4NDQwNFoYDzIxMjMwMzA0MDg0NDA0WjBrMQswCQYD
+VQQGEwJVUzENMAsGA1UECAwEVXRhaDENMAsGA1UEBwwETGVoaTEZMBcGA1UECgwQ
+QUJDIENvbXBhbnksSW5jLjELMAkGA1UECwwCSVQxFjAUBgNVBAMMDWFiYy5hZG1p
+bi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCn0L97ITGfi2KF
+MBm8lzz9VGfZ0iKMi0ijHH5pVOPqsgA19phQ0DZ6G4Wy1EbdF3wnWZdDEYkenqxH
+VykzulFN9W3Tc5Ao67zBZLcBc8Oe9zo88nh/J03ds8nyPhY3zTptAGKsEeoSKo0L
+Y7m1Ozf2npLa2E+NH815/+WzMoM3jvi3iCXWJ4bvvhjNPDp+oqY+6wzcU9SMT+zM
+vRPoVmVvevVhzSpfH2dhZG44mBcTdkaxnvxuEJm8uAfAA1vFCyM/2n3gDUGOIxQS
+v6nNKgVnIqsa9/gWOjR3EoOejw6a+Hlx9hFL9Tv4hsJ0o2AKsjGl5WchNvItONQg
+eeHAGUMzAgMBAAEwDQYJKoZIhvcNAQELBQADggEBADvGF9b/ih7+ru3U9+YBN1SI
+h5MMK9WI5IZBQfeyY5aD1UmMb68e0SjnfFhDhpl0U1xUNkqINq/8+JAAwUkOm2B1
+nb/2uySOvONO8WnGvWlYPHPycnlAOwQNAlArE+F8TC6aKdlcB63NByacxnUt9Gcz
+92N2PJJr3QU0uKF5xDnWgDKCPStH8cCRn/PufSngljuevxou45roKXNRAV6sAGJ7
+wybuZVZ9RxjaLB5CKuLoO42CxJFzZyhUG7ixpWLsoC62P7bOK6IVo8G77wn185qX
+gskY2bwNisuMYD+k2SoTiLmaqUh4n+j+BJaHyQc4vFRZ475+y6hC0NRU0cNxMlc=
+-----END CERTIFICATE-----

+ 22 - 0
docker/nginx/key/admin.com.crt

@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDrzCCApegAwIBAgIUNv3hC7V8ueWe5ztnEpC5drzUE70wDQYJKoZIhvcNAQEL
+BQAwZzELMAkGA1UEBhMCVVMxDTALBgNVBAgMBFV0YWgxDTALBgNVBAcMBExlaGkx
+GTAXBgNVBAoMEEFCQyBDb21wYW55LEluYy4xCzAJBgNVBAsMAklUMRIwEAYDVQQD
+DAlhZG1pbi5jb20wHhcNMjMwMzI4MDg0NDA0WhcNMzYxMjA0MDg0NDA0WjBnMQsw
+CQYDVQQGEwJVUzENMAsGA1UECAwEVXRhaDENMAsGA1UEBwwETGVoaTEZMBcGA1UE
+CgwQQUJDIENvbXBhbnksSW5jLjELMAkGA1UECwwCSVQxEjAQBgNVBAMMCWFkbWlu
+LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALcCIGMfuoXia4zK
+Zp6JFiqjz9MFWsepJjVF3IkrvJuMB8dfGoVEaB82frVoEzFFMyfnD+vM1yib0oj+
+gj3z5cxLeo5zuoy6KGaPfOMLyMgCiNGgLCbEvQ/yNtDZx26qAGw10S51EeOQFzg3
+wW4ysouh8RyT+ljkmMeB4ym7GuMDh00mI/ecHOK/Prl7hkBPk+dpc7/A+EUvmqNf
+IcgbZiw49NqbWGsFCAAYCWRVUhOU36GJTSX1pojTsKUwyifHgSGE7BQRBddQTaAz
+j2VnoJhMcj4/Lk7xxoRi2m/xQEHMnfYprhyajUCe38/zK81Wuh10K8QT2deaP8Qb
+uwVbWR8CAwEAAaNTMFEwHQYDVR0OBBYEFJFdp03B0hlqnbc+Ko98wa7Wj7EpMB8G
+A1UdIwQYMBaAFJFdp03B0hlqnbc+Ko98wa7Wj7EpMA8GA1UdEwEB/wQFMAMBAf8w
+DQYJKoZIhvcNAQELBQADggEBAGzMI5EIQ5VICdxFTBz+9DhDcRt44pBmwGbVEo3L
+a2ndjRA2Mz0eUcsTWtzy8ZEjBQdFyCo63xj96yHAhUR6yUJo4lUVMvfi3SswW/AO
+aataw55ya7yK7yR8PHw3Bxh69OmEXzQJWV0r8vMBrm7Bwn1AEcyLj/m5mnZA6Rjt
+2CdLtWMPF26mVrRBRw8uLLm4f1/WO38XRPPiR7pc1ZhcrXUZfzZ/nLx/a3w4D66G
+FCWVdyfvBAK7ajoO9htZufVdPgO1xr1zmQlbEZ5/Wri3HufohnnbjLQr8Gu/eL+d
+qvUpj3mgAX+2jg+voviSlZWb1r1QSTTWvUPiKgcLbAH6cZY=
+-----END CERTIFICATE-----

+ 28 - 0
docker/nginx/key/admin.com.key

@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC3AiBjH7qF4muM
+ymaeiRYqo8/TBVrHqSY1RdyJK7ybjAfHXxqFRGgfNn61aBMxRTMn5w/rzNcom9KI
+/oI98+XMS3qOc7qMuihmj3zjC8jIAojRoCwmxL0P8jbQ2cduqgBsNdEudRHjkBc4
+N8FuMrKLofEck/pY5JjHgeMpuxrjA4dNJiP3nBzivz65e4ZAT5PnaXO/wPhFL5qj
+XyHIG2YsOPTam1hrBQgAGAlkVVITlN+hiU0l9aaI07ClMMonx4EhhOwUEQXXUE2g
+M49lZ6CYTHI+Py5O8caEYtpv8UBBzJ32Ka4cmo1Ant/P8yvNVroddCvEE9nXmj/E
+G7sFW1kfAgMBAAECggEAFcXN/p0Gvuj6LKzj2paqqXYFwrBPZZOtNQdTvooSjVry
+jfi1mgdSb+w21PRF3EXEWUn3LfGX43/uY1gMPLyoqU6NjScdmaKILfOCQyzivVD3
+4CCzQAWGDMCfXueZ/4OAO1+HvIQ3FaDN8mVHwQmNDmm82s6MKUlBF/NPCGb3Quyz
+Uad7o/SiZowUjHaBZA3homssP508+zWHfZSD59eMoIpAWUFT4BLnhZGLCzryUK1J
+R+lw+hWJjE2cqdVsC8gULW0vrgASGE46c/ZBwprjA8pWUR05OWQHV+ukLcn68yby
+q+hCN27wAvOfxS86TjAcpmXAWR515dBcbpKKDkQKcQKBgQC3HvzrKvaZSe4H0ESA
+cIMudgv6zjZveSrCW1brr1Xxp43cs9yFJEDmobhd4zOQlqcbNZjBOeOGQEsk3OYQ
+5Z4qzDQDA90Do9aRl0lttQuZZlfgRwrHyGfwBJXwuWUXdTk8td0Tz7aD1IhDJgez
+JTdrpOq8reQQKTrtW4og2qXkSQKBgQD/16b2j4CQqJgdUO7cOgEzwaYDA4zxyFuR
+KURpTgMAe6SpprTwMHJjnEMVwokpjHBpZtOoNQJYbuj6YfK8G7WzRG2JlBG6SL2k
+MRQ7mUoUsz2e0khRsGza3iFsFFBQKWX6ObwiAoTF9Ckr/Jf+ToovCGYD7G3f7tkf
+8jTLjeUCJwKBgQCjT3iCBlPcS0mEIGInJbBoLBDtASEc8zOGF82B7WG5XROwQ5uk
+Bbv3szxoRurCxQiMxJTRpl3aadZaLsLjSNRxGKI+GiDuURxXxVNQCskoalRuiQz9
+NSY0sPJDuCOG8x0znoFmXLVKBq3rLKxrQQKW9oH9+RrOquaJrjyWpkiSOQKBgDHD
+9QpI56073jr1n0DfV5SFupEjg6sUWhtmd5Q0RIk3g9QsRU3jXpzZrILzEFMwqj0W
+b11s0kP5bwAlRV4p1bJFQTldwAUIWTszAMiHDM3x/66BIOgi9Umto7quSOEO7HM7
+/8htzP3kfI292KLzDBYSACYLO2QvxbRdHL/rnfxJAoGBAKFJ+XojL5d0uVZ/rrlf
+s0QwWpG8wIlyLqsiB4VOfwhAI+bTQd8D+wY72iDqu86e2QMWmf4lSeYufOBjVyCN
+uIj5o4ILRKhEj33/Q1fCtcB+zE4RQVihtsnCJYYGymDgY2mW4mGCXzBderMMehuL
+/Qina3knHwaK/RPH/xn5UkCG
+-----END PRIVATE KEY-----

+ 22 - 0
docker/nginx/key/admin.com.pem

@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDsTCCApmgAwIBAgIUWwu7jhpXsbRfKhA6SZ+hhCZAEKIwDQYJKoZIhvcNAQEL
+BQAwZzELMAkGA1UEBhMCVVMxDTALBgNVBAgMBFV0YWgxDTALBgNVBAcMBExlaGkx
+GTAXBgNVBAoMEEFCQyBDb21wYW55LEluYy4xCzAJBgNVBAsMAklUMRIwEAYDVQQD
+DAlhZG1pbi5jb20wIBcNMjMwMzI4MDg0NDA0WhgPMjEyMzAzMDQwODQ0MDRaMGcx
+CzAJBgNVBAYTAlVTMQ0wCwYDVQQIDARVdGFoMQ0wCwYDVQQHDARMZWhpMRkwFwYD
+VQQKDBBBQkMgQ29tcGFueSxJbmMuMQswCQYDVQQLDAJJVDESMBAGA1UEAwwJYWRt
+aW4uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtwIgYx+6heJr
+jMpmnokWKqPP0wVax6kmNUXciSu8m4wHx18ahURoHzZ+tWgTMUUzJ+cP68zXKJvS
+iP6CPfPlzEt6jnO6jLooZo984wvIyAKI0aAsJsS9D/I20NnHbqoAbDXRLnUR45AX
+ODfBbjKyi6HxHJP6WOSYx4HjKbsa4wOHTSYj95wc4r8+uXuGQE+T52lzv8D4RS+a
+o18hyBtmLDj02ptYawUIABgJZFVSE5TfoYlNJfWmiNOwpTDKJ8eBIYTsFBEF11BN
+oDOPZWegmExyPj8uTvHGhGLab/FAQcyd9imuHJqNQJ7fz/MrzVa6HXQrxBPZ15o/
+xBu7BVtZHwIDAQABo1MwUTAdBgNVHQ4EFgQUkV2nTcHSGWqdtz4qj3zBrtaPsSkw
+HwYDVR0jBBgwFoAUkV2nTcHSGWqdtz4qj3zBrtaPsSkwDwYDVR0TAQH/BAUwAwEB
+/zANBgkqhkiG9w0BAQsFAAOCAQEARdXGosx7WvGYQl4hD5ROuiu/iixPera8+tkj
+aFSOlSouhl9MrFocqzlz5vnpgtCgc8d5TKFkhKGXMa/CDC4GOSC0KNzdoAuZagJJ
+0XtthkQ4t3mhEgwdEFyHBYUEVvJFwxQFXlNvPqykeVeqZNRrzpHZCxG5atjtvWWV
+APHACk7IvHWsu84lEvwomUr4oHnjv7DldCZ6e41j6bCjGg+/GiIuCcOKwK2WzhUZ
+aoK4FyWoy1oNfBUI4/tJS4ea95n4UehQ9OklwL8yRh+w6LwyJFEhCQsSR+k+95/9
+8OPgmo0bFBDHknGXTQp/inFGTgghrOoQtSayLonWbWe+rg906w==
+-----END CERTIFICATE-----

+ 0 - 28
docker/nginx/key/rootCA.key

@@ -1,28 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAQC/fby+rsUFyQrH
-AFsD1rVmEMwJFZTaLfI1LqFmu9PQeVchHrULBs49NHZHsmZM1DRVGa/F/29HGZlh
-0rvzFZ9ufcWaKZzOuTw7nVSwtNqqaMmttBcdL7aSEH2TyKUNLTQir/NUEm4SI28Z
-q7jR0MnhtGMdht9UBPWTC1jdKRhZ5CvGZMKIFrXuYs9YNkNn63pSwaFXjcUEoots
-cX6i0uNXc20MqRiHkJKm/zdNwO5CVUTKs+T+09IabToc1pNQqAzsPNByn/IETfZQ
-GrwAW82tZFzq89ByzItioxkdzch7jYbXcru7cnbkFCt9lSDUPWqBxf/D6uDASFN+
-11w1vuF7AgMBAAECgf9T03Ldn+h9n9nTqf7YaxQw3jqVezJp6dU/tvbOm9D7YO+h
-Oq3kFMFE1pBGBcGPegA7hPIG/zEdu5+cmYGLPXR8cnBBYY+YqvV/8BtWDF41TBBS
-tcesy/H9/vXG3f2nC0Tpg/qJjt0o8WsXnownb0/f02zlbwMhb06Z7ghfDJ5YEAw+
-LrgMbqVbEKpUHNvlSTjTbvHLyOgvTQLMMLHK/K2Pqh77JbQ8uY9LxkPJaBTGY/nP
-Wwk7BY9OXlqwWLEg3XZDurUmMoJM3YY9Vn6SiGsaaE3oXF0S/aVCn3UE3z4WQs3o
-1HR0LQYNyeKesGn4LzbLfBi7nOjD2gw7m5f+kNECgYEA7Xtwmm/iYGBIuqQ6kVuV
-7TY8smQcjQmEt/vMz7RxehKzXPV9lLWefEREPRO5vUxxkgqyfLf83Qo0scDTXE7f
-9DS9WBr93b/p4mNGLOzTYrMsqi0b9JeK5qkUdo10ySKukQjkIoWGt84TMcpjGzkp
-6QQ4VcqHGMyDzq0yjkYTKPMCgYEAzmw8bezC0Hsd1wo6xayrU5g0cHuZVx4gHsBJ
-3DMuiV4paYh4YSIi+sYFiXfY5GaSo9MLz2irHqax7CF0kBQAnkimhRuLGknHnpL9
-OATZwxI4cUxj9JmSPHEQHke2+ORv4mGXXEFsti9ohQa1hgFERsDx0Hagct9MLh/y
-Qm7tB1kCgYEA3u3+sWsQNeqMu3BJboRsBGbiqY+i4Z6q0M913xEDaVW+vCfTQFMR
-uJOY/0DSHmpxPmf+T2ej3pejCa36e2+reiI8EEYeRBjQ5GzOxoN2l/OcnQ+Fa6EK
-iib0h6mYlOuStaGEDwgLg+XWTOoxCLArsIr+m0JoeZYasVwS1k3f1JMCgYBGVuOQ
-oakQ2aMlb7rvORN4fNkBq1xpLz7Ku8NvYZFuBcQezf4XO0aoJWolmc0ypzE42eWg
-W45T94GRcSUDI43CYgc8PFJ+Nr3q7zOSLzT1H/RTxzAYXWxTZEOVzeIvlcf6YD7v
-lOuyeR0ol0yrySq24XCFFKc//Y87+G7Y7GugoQKBgEtC3URF/I516wB0SBBdDajQ
-6Bv7t+2HRawoCrAr/ypwhfVpqVK/cR5ic1ZnKF+HWI6DAeXewX+oxqJ1qa8moR9f
-kAHccvmD7gNlT0S6Cu/GWXamQ2EbiqduoBIvZjMXXobQzVNUkWlJZcOuK6VP3OK/
-658W86CTTAkOaptkRKJ3
------END PRIVATE KEY-----

+ 0 - 22
docker/nginx/key/rootCA.pem

@@ -1,22 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDtzCCAp+gAwIBAgIULdTDO28ZEBkePNYBqXBRD2Oi/4EwDQYJKoZIhvcNAQEL
-BQAwajELMAkGA1UEBhMCVVMxDTALBgNVBAgMBFV0YWgxDTALBgNVBAcMBExlaGkx
-GzAZBgNVBAoMEllvdXIgQ29tcGFueSwgSW5jLjELMAkGA1UECwwCSVQxEzARBgNV
-BAMMCnJvb3RjYS5jb20wIBcNMjMwMjEzMTIwMTA3WhgPMjEyMzAxMjAxMjAxMDda
-MGoxCzAJBgNVBAYTAlVTMQ0wCwYDVQQIDARVdGFoMQ0wCwYDVQQHDARMZWhpMRsw
-GQYDVQQKDBJZb3VyIENvbXBhbnksIEluYy4xCzAJBgNVBAsMAklUMRMwEQYDVQQD
-DApyb290Y2EuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv328
-vq7FBckKxwBbA9a1ZhDMCRWU2i3yNS6hZrvT0HlXIR61CwbOPTR2R7JmTNQ0VRmv
-xf9vRxmZYdK78xWfbn3Fmimczrk8O51UsLTaqmjJrbQXHS+2khB9k8ilDS00Iq/z
-VBJuEiNvGau40dDJ4bRjHYbfVAT1kwtY3SkYWeQrxmTCiBa17mLPWDZDZ+t6UsGh
-V43FBKKLbHF+otLjV3NtDKkYh5CSpv83TcDuQlVEyrPk/tPSGm06HNaTUKgM7DzQ
-cp/yBE32UBq8AFvNrWRc6vPQcsyLYqMZHc3Ie42G13K7u3J25BQrfZUg1D1qgcX/
-w+rgwEhTftdcNb7hewIDAQABo1MwUTAdBgNVHQ4EFgQUdiQRjsHS0UtFL2GvbO4w
-LdGsBuYwHwYDVR0jBBgwFoAUdiQRjsHS0UtFL2GvbO4wLdGsBuYwDwYDVR0TAQH/
-BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAe7m0BcWvIn1XBVcZMnpl3sUbv95d
-PMgP6i6A9Uz10ctqG6ArolkQyhDIDSZC1jTj+X1vqi7WZHCAF1VLXiboXQ7SuOid
-UTfK2SeqqJczZ1HeHvGc0zP692k5hKH/8orTnkGuhirEclKATxzQLq8ted352ntM
-Swf9xDUAauWRDmiVA3FJFsCQ2AkWSxpqgzs3y3Ti2wj3hVkOdVmAqDfMYj6nlh0O
-NP+lci8KGboeC879h1wtB+aob4ro7ysnIaq19PrvYMUUeIEWy6F8plfhp5WSCfR9
-aQ61VG/pSH/hKlJ0Tt9goBzbXOrQqxtNTCxXnyNjy08uOJro5q41GLk6Cw==
------END CERTIFICATE-----

+ 0 - 17
docker/nginx/key/server.csr

@@ -1,17 +0,0 @@
------BEGIN CERTIFICATE REQUEST-----
-MIICrzCCAZcCAQAwajELMAkGA1UEBhMCVVMxDTALBgNVBAgMBFV0YWgxDTALBgNV
-BAcMBExlaGkxGzAZBgNVBAoMEllvdXIgQ29tcGFueSwgSW5jLjELMAkGA1UECwwC
-SVQxEzARBgNVBAMMCnRlc3QtcmVkaXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
-ggEKAoIBAQCwBqR84rO6u/68nBt3/N0WB15GzG98aYe/7CPZSeZmTx+2y86mX+G3
-V/ZHr3JqnyZ9M+OC5qfyAzSKCB9GMpmfXYuPefu/QHt/HlDFon3kFT9q9bQqpudC
-i5EElc+XEf0RKtt9buG+bU75gBP0XaJQ/v0GDEFG8VWssCVSh/zRieQPHynNUJrZ
-fF0hEOEwkrvSBgz412WzAMo5jslSTEW2WNYUrsw986IutWCP9REU8L0jQiU53jp7
-QHLIo55jJaCjrpaL6Zb55LIA8G8DxgX5zMRBpiE3S8iXup4pp8KQMj5O/8iZb47Y
-+FD8c4VpapNvUXiohVZ2JfNG++lzfoU5AgMBAAGgADANBgkqhkiG9w0BAQsFAAOC
-AQEAmIot1a3AwFUIDy/lYoArLHmIgD24XHTApOuQgIvIp2SNMCZXJ++nVRAuWc8s
-Dwvm8XzHIIY+Dnux0WF61wEKILWdCzkO7X5+DSnVHEJsJmrh69ZlolnDIQ6WWwFn
-HpaatvVM3DoPo0mLQzNsywDdp3XEhSF9WQtXyLrEsxnfwKxjalePT+IucuD7y/xQ
-p+zcodaXId1f9QBfWJK7OJGlgNZA29hhhsfzLi4IDAmu7gz3z4VmK47eSL4QrZPP
-EEyMKGf66bFLnuqeiqIvZMfUW/ZAEeA7bvL3GytEjThX0QxrXiipCJNlTSeGiQVw
-3vMLoVS3B77gk1Q+bFrIea39DA==
------END CERTIFICATE REQUEST-----

+ 0 - 28
docker/nginx/key/server.key

@@ -1,28 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCwBqR84rO6u/68
-nBt3/N0WB15GzG98aYe/7CPZSeZmTx+2y86mX+G3V/ZHr3JqnyZ9M+OC5qfyAzSK
-CB9GMpmfXYuPefu/QHt/HlDFon3kFT9q9bQqpudCi5EElc+XEf0RKtt9buG+bU75
-gBP0XaJQ/v0GDEFG8VWssCVSh/zRieQPHynNUJrZfF0hEOEwkrvSBgz412WzAMo5
-jslSTEW2WNYUrsw986IutWCP9REU8L0jQiU53jp7QHLIo55jJaCjrpaL6Zb55LIA
-8G8DxgX5zMRBpiE3S8iXup4pp8KQMj5O/8iZb47Y+FD8c4VpapNvUXiohVZ2JfNG
-++lzfoU5AgMBAAECggEALWNBFYyVAFDKMdLkyE8UqMH0nrfHBWLmpGecpMIH3RiI
-2mb53W96sX5GXBySmYh48a6n+tBDvMTzzqWifsS8VNnXiwLOlXVogpIMDLHF2UJb
-TFaXgqnvlnqLRY3lbZQvVzZgSxsErUfdJbtPKeLc4BqnnmAZktPWngT7UqkK2PJS
-ICsM2zKekXlmZM5BsiTE9wpr8sf+il3tZ6Qjbc4zNNZT2A0/o4M1yicRRyvIRafv
-qSn2YwVN0OWTHJl9Og32NDIWxVMTBmodz1ozkKoEsNirO35+EyYfgk3V10nrKDFG
-GNmMQ+Bm5x4rcpGjxZLRi3bR7Vhu7zIOjqT3tGN+WwKBgQDdc8T5ldJcVVnu1Qc6
-aDh0q7ZLUVL6WNHVltSuIdc4Ti9bKB9GaT0fTD8tOZA7AEEcIPS/bDrEuXQNlafK
-vJ4SOA+j3fZHO5/QVQ11oikU4grn1lLtL5AXziuni2j07K+eWAMyQji3ZTqeZ0BF
-az1g0hp9eHRd3tbGGfgiW8GE4wKBgQDLfKovCAfk4GD/1T4NhNkXQhMF78e5AnJn
-VGtzOup1hQsp6kd+H6DdrxHp1F/UjTnFNtiBTpn0z5nfUofQ9foeaW9Zdgd8KyzQ
-QgAnJEerMENqmau6G1F0MuyLuRX98MPYfhAe2hgGFM6WibNY2X+w+E1EdliMETkj
-VVWMVqSEMwKBgQC7waUW65UAXgky+oD3X1fGa7PSZfARe+7kxc4qmVyNS5TRF9J0
-c1O0ToQeBvknXQ7XF4YLKmslUgt4XRN3S7ZFwixYhh+Bw6a7DvGrc8KbBw+yAsAq
-gzILTO0sT4G8b1RyzzJekVDfBT/O/8G5WbQfe+Ojz9XxpLa6HViJYPxRewKBgGzW
-+3g4hXBoi7mLZ6t3eV61WtN8E4njwyl9wBNcWfgN95Ct3Rua80Jf1+cIT1GzUEkq
-MtfHIRYOzLDkxfyA9Q27O3HQbeR+e3PROZ+2CheIsyabl3zuC71pV5jMoPS5CSgN
-FbZK1Tq7elyOvr0xaNlRlpKd8nLI65T4mc98sHZ9AoGAP1dNd7HTtujB1asu9BhB
-glmArau0+VK6wj2Z4fkRNQRfUK9aTShh3ncC36Yz/42yhsq4j/DXyFUHmYZSllc+
-aB6O87bu8U1Fl07RsojPl/rr9uUlaRFvl01lDb5ZkFblroJE6fBHs7btMXV5LMRw
-pNnhs3GZTdUSq2QBwnpBJ18=
------END PRIVATE KEY-----

+ 0 - 21
docker/nginx/key/server.pem

@@ -1,21 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDXTCCAkUCFBLO6MbB0GilC6mLepE/DhA/mvLKMA0GCSqGSIb3DQEBCwUAMGox
-CzAJBgNVBAYTAlVTMQ0wCwYDVQQIDARVdGFoMQ0wCwYDVQQHDARMZWhpMRswGQYD
-VQQKDBJZb3VyIENvbXBhbnksIEluYy4xCzAJBgNVBAsMAklUMRMwEQYDVQQDDApy
-b290Y2EuY29tMCAXDTIzMDIxMzEyMDEwN1oYDzIxMjMwMTIwMTIwMTA3WjBqMQsw
-CQYDVQQGEwJVUzENMAsGA1UECAwEVXRhaDENMAsGA1UEBwwETGVoaTEbMBkGA1UE
-CgwSWW91ciBDb21wYW55LCBJbmMuMQswCQYDVQQLDAJJVDETMBEGA1UEAwwKdGVz
-dC1yZWRpczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALAGpHzis7q7
-/rycG3f83RYHXkbMb3xph7/sI9lJ5mZPH7bLzqZf4bdX9kevcmqfJn0z44Lmp/ID
-NIoIH0YymZ9di495+79Ae38eUMWifeQVP2r1tCqm50KLkQSVz5cR/REq231u4b5t
-TvmAE/RdolD+/QYMQUbxVaywJVKH/NGJ5A8fKc1Qmtl8XSEQ4TCSu9IGDPjXZbMA
-yjmOyVJMRbZY1hSuzD3zoi61YI/1ERTwvSNCJTneOntAcsijnmMloKOulovplvnk
-sgDwbwPGBfnMxEGmITdLyJe6nimnwpAyPk7/yJlvjtj4UPxzhWlqk29ReKiFVnYl
-80b76XN+hTkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAvx/cdvUwYsJdxiEOnk4H
-bD8QMcqIuNmHuMimC6Wlz/NMOboV7W6jZqyrCnAg1LV35bhYmhBftbeldnblJcBV
-VLkKVz8RQNEScjzpRcX3QcPciYSSOBfjrlDOT8EM9xzk8SlbyN/tylQSAjXiB6Jc
-PlBulIKxbPRRaaRWYpkyVSJFItHItDeh/HcNK19ouZhgHoG0puFoLqkp5hK1M6Ht
-zhCHCrruU5XJwZtDxWSNO96N0gtRd7dH6uI/Ifm2c5Jfg2Cz4vUduN2Y4FGLUafM
-HhPrz9y5S4xRK8qSKhDiobIBLtCibBDvg2RR/O89lPqzgEFD//iX3tvEFncDLZCV
-bw==
------END CERTIFICATE-----

+ 12 - 5
docker/nginx/key/ssl.sh

@@ -1,6 +1,13 @@
-openssl genrsa -out rootCA.key 2048
-openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 36500 -out rootCA.pem -subj "/C=US/ST=Utah/L=Lehi/O=Your Company, Inc./OU=IT/CN=rootca.com"
-openssl genrsa -out server.key 2048
-openssl req -new -key server.key -out server.csr -subj "/C=US/ST=Utah/L=Lehi/O=Your Company, Inc./OU=IT/CN=test-redis"
-openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.pem -days 36500 -sha256
+# 生成根证书
+openssl genrsa -out admin.com.key 2048
+openssl req -x509 -new -nodes -key  admin.com.key -subj "/C=US/ST=Utah/L=Lehi/O=ABC Company,Inc./OU=IT/CN=admin.com" -days 5000 -out admin.com.crt
+# 生成服务证书请求
+openssl genrsa -out abc.admin.com.key 2048
+openssl req -new -key abc.admin.com.key -subj "/C=US/ST=Utah/L=Lehi/O=ABC Company,Inc./OU=IT/CN=abc.admin.com" -out abc.admin.com.csr
+# 用根证书签发服务器证书
+openssl x509 -req -in abc.admin.com.csr -CA admin.com.crt -CAkey admin.com.key -CAcreateserial -out abc.admin.com.crt -days 5000 -extfile <(printf "subjectAltName=IP:127.0.0.1,IP:192.168.1.1,IP:192.168.0.252,DNS:abc.admin.com,DNS:mx.admin.com,DNS:localhost")
+# extfile可选,可以为服务器证书关联多个IP或者域名
+
+openssl req -x509 -new -nodes -key admin.com.key -sha256 -days 36500 -out admin.com.pem -subj "/C=US/ST=Utah/L=Lehi/O=ABC Company,Inc./OU=IT/CN=admin.com"
+openssl x509 -req -in abc.admin.com.csr -CA admin.com.pem -CAkey admin.com.key -CAcreateserial -out abc.admin.com.pem -days 36500 -sha256