diff --git a/database/common/mml_command.sql b/database/common/mml_command.sql index 43d1e488..ef32e0d4 100644 --- a/database/common/mml_command.sql +++ b/database/common/mml_command.sql @@ -1,22 +1,3 @@ -/* - Navicat Premium Data Transfer - - Source Server : local_mariadb - Source Server Type : MariaDB - Source Server Version : 100338 (10.3.38-MariaDB) - Source Host : localhost:33066 - Source Schema : omc_db - - Target Server Type : MariaDB - Target Server Version : 100338 (10.3.38-MariaDB) - File Encoding : 65001 - - Date: 14/05/2024 11:55:53 -*/ - -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - -- ---------------------------- -- Table structure for mml_command -- ---------------------------- @@ -31,9 +12,8 @@ CREATE TABLE `mml_command` ( `mml_display` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `param_json` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL, `status` enum('Active','Inactive') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'Active' COMMENT '激活: Active 未激活: Inactive', - PRIMARY KEY (`id`) USING BTREE, - INDEX `id`(`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1626 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of mml_command @@ -71,5 +51,3 @@ INSERT INTO `mml_command` VALUES (1622, 'OMC', 'logManagement', 'Log Management' INSERT INTO `mml_command` VALUES (1623, 'OMC', 'logManagement', 'Log Management', 'lst', 'eventlog', 'List NE Event Log', '[{\"alias\":\"ne_type\",\"apostr\":\"true\",\"comment\":\"\",\"display\":\"NE type\",\"filter\":\"\",\"loc\":\"true\",\"name\":\"netype\",\"optional\":\"true\",\"type\":\"string\"},{\"alias\":\"ne_id\",\"apostr\":\"true\",\"comment\":\"\",\"display\":\"NE ID\",\"filter\":\"\",\"loc\":\"true\",\"name\":\"neid\",\"optional\":\"true\",\"type\":\"string\"},{\"alias\":\"log_time\\u003e\",\"apostr\":\"true\",\"comment\":\"\",\"display\":\"Log time(\\u003e=)\",\"filter\":\"\",\"name\":\"starttime\",\"optional\":\"true\",\"type\":\"string\"},{\"alias\":\"log_time\\u003c\",\"apostr\":\"true\",\"comment\":\"\",\"display\":\"Log time(\\u003c=)\",\"filter\":\"\",\"name\":\"endtime\",\"optional\":\"true\",\"type\":\"string\"}]', 'Active'); INSERT INTO `mml_command` VALUES (1624, 'OMC', 'mmlManagement', 'MML Management', 'lst', 'mmlcmd', 'List MML Command', '[{\"alias\":\"ne_type\",\"apostr\":\"true\",\"comment\":\"\",\"display\":\"Category\",\"filter\":\"\",\"name\":\"category\",\"optional\":\"true\",\"type\":\"string\"},{\"alias\":\"operation\",\"apostr\":\"true\",\"comment\":\"\",\"display\":\"Operation\",\"filter\":\"\",\"name\":\"operation\",\"optional\":\"true\",\"type\":\"string\"},{\"alias\":\"object\",\"apostr\":\"true\",\"comment\":\"\",\"display\":\"Object\",\"filter\":\"\",\"name\":\"object\",\"optional\":\"true\",\"type\":\"string\"}]', 'Active'); INSERT INTO `mml_command` VALUES (1625, 'OMC', 'systemManagement', 'System Management', 'dsp', 'sysinfo', 'Display NE System Information', '[{\"alias\":\"neType\",\"apostr\":\"false\",\"comment\":\"\",\"display\":\"NE type\",\"filter\":\"\",\"name\":\"netype\",\"optional\":\"true\",\"type\":\"string\"},{\"alias\":\"neId\",\"comment\":\"\",\"display\":\"NE ID\",\"filter\":\"\",\"name\":\"neid\",\"optional\":\"true\",\"type\":\"string\"}]', 'Active'); - -SET FOREIGN_KEY_CHECKS = 1; diff --git a/database/install/sys_dict_data0.sql b/database/install/sys_dict_data0.sql index daa4ad58..2a95102d 100644 --- a/database/install/sys_dict_data0.sql +++ b/database/install/sys_dict_data0.sql @@ -189,6 +189,10 @@ INSERT INTO `sys_dict_data` VALUES (161, 22, 'dictData.trace_interfaces.22', 'N2 INSERT INTO `sys_dict_data` VALUES (162, 40, 'dictData.trace_interfaces.40', 'N40', 'trace_interfaces', '', '', '1', 'supervisor', 1712720201349, '', 0, ''); INSERT INTO `sys_dict_data` VALUES (163, 14, 'dictData.trace_interfaces.14', 'N14', 'trace_interfaces', '', '', '1', 'supervisor', 1712720201349, '', 0, ''); INSERT INTO `sys_dict_data` VALUES (164, 5, 'dictData.trace_interfaces.5', 'N5', 'trace_interfaces', '', '', '1', 'supervisor', 1712720201349, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (165, 1, 'dictData.sys_user_type.system', 'System', 'sys_user_type', '', 'default', '1', 'supervisor', 1712720201349, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (166, 2, 'dictData.sys_user_type.ldap', 'LDAP', 'sys_user_type', '', 'lime', '1', 'supervisor', 1712720201349, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (167, 3, 'dictData.sys_user_type.smtp', 'SMTP', 'sys_user_type', '', 'magenta', '1', 'supervisor', 1712720201349, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (168, 4, 'dictData.sys_user_type.oauth2', 'OAuth2', 'sys_user_type', '', 'gold', '1', 'supervisor', 1712720201349, '', 0, ''); -- 多租户 INSERT INTO `sys_dict_data` VALUES (10000, 10000, 'dictData.tenancy.imsi', 'IMSI', 'tenancy_type', NULL, NULL, '1', 'supervisor', 1699350000000, NULL, 0, NULL); diff --git a/database/install/sys_dict_data1_i18n_zh.sql b/database/install/sys_dict_data1_i18n_zh.sql index f04372e6..5804c992 100644 --- a/database/install/sys_dict_data1_i18n_zh.sql +++ b/database/install/sys_dict_data1_i18n_zh.sql @@ -747,6 +747,14 @@ INSERT INTO `sys_dict_data` VALUES (2236, 2236, 'job.backup_export_cdr', '备份 INSERT INTO `sys_dict_data` VALUES (2237, 2237, 'job.backup_export_cdr_remark', 'dataType: 类型支持 ims/smf/sgwc/smsc\nfileType: 文件类型 csv/xlsx\nhour: 数据时间从任务执行时间前的小时数', 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); INSERT INTO `sys_dict_data` VALUES (2238, 2238, 'dictData.trace_interfaces.14', 'N14', 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); INSERT INTO `sys_dict_data` VALUES (2239, 2239, 'dictData.trace_interfaces.5', 'N5', 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (2240, 2240, "dictType.sys_user_type", "用户类型", 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (2241, 2241, "dictData.sys_user_type.system", "系统", 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (2242, 2242, "dictData.sys_user_type.ldap", "LDAP", 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (2243, 2243, "dictData.sys_user_type.smtp", "SMTP", 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (2244, 2244, "dictData.sys_user_type.oauth2", "OAuth2", 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (2245, 2245, "user.export.userType", "用户类型", 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (2246, 2246, "menu.system.loginSource", "第三方登录认证", 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (2247, 2247, "log.operate.title.sysLoginSource", "认证源", 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); -- multi-tenancy INSERT INTO `sys_dict_data` VALUES (11000, 11000, 'menu.security.tenant', '租户管理', 'i18n_zh', NULL, NULL, '1', 'supervisor', 1700000000000, NULL, 0, NULL); diff --git a/database/install/sys_dict_data2_i18n_en.sql b/database/install/sys_dict_data2_i18n_en.sql index 5d0cfe67..3581a178 100644 --- a/database/install/sys_dict_data2_i18n_en.sql +++ b/database/install/sys_dict_data2_i18n_en.sql @@ -747,6 +747,14 @@ INSERT INTO `sys_dict_data` VALUES (4236, 4236, 'job.backup_export_cdr', 'Backup INSERT INTO `sys_dict_data` VALUES (4237, 4237, 'job.backup_export_cdr_remark', 'Backup-Periodic export of dataType: type support ims/smf/sgwc/smsc\nfileType: file type csv/xlsx\nhour: data time from the hour before the task execution time', 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); INSERT INTO `sys_dict_data` VALUES (4238, 4238, 'dictData.trace_interfaces.14', 'N14', 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); INSERT INTO `sys_dict_data` VALUES (4239, 4239, 'dictData.trace_interfaces.5', 'N5', 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (4240, 4240, "dictType.sys_user_type", "User Type", 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (4241, 4241, "dictData.sys_user_type.system", "System", 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (4242, 4242, "dictData.sys_user_type.ldap", "LDAP", 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (4243, 4243, "dictData.sys_user_type.smtp", "SMTP", 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (4244, 4244, "dictData.sys_user_type.oauth2", "OAuth2", 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (4245, 4245, "user.export.userType", "User Type", 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (4246, 4246, "menu.system.loginSource", "Third Party Login Source", 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +INSERT INTO `sys_dict_data` VALUES (4247, 4247, "log.operate.title.sysLoginSource", "Login Source", 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); -- 多租户 INSERT INTO `sys_dict_data` VALUES (14000, 14000, 'menu.security.tenant', 'Tenant Management', 'i18n_en', '', '', '1', 'supervisor', 1705550000000, '', 0, ''); diff --git a/database/install/sys_dict_type.sql b/database/install/sys_dict_type.sql index 19e02782..b55730c2 100644 --- a/database/install/sys_dict_type.sql +++ b/database/install/sys_dict_type.sql @@ -31,6 +31,7 @@ INSERT INTO `sys_dict_type` VALUES (5, 'dictType.sys_job_group', 'sys_job_group' INSERT INTO `sys_dict_type` VALUES (6, 'dictType.sys_yes_no', 'sys_yes_no', '1', 'supervisor', 1699350000000, NULL, 0, 'dictType.sys_yes_no_remark'); INSERT INTO `sys_dict_type` VALUES (9, 'dictType.sys_oper_type', 'sys_oper_type', '1', 'supervisor', 1699350000000, NULL, 0, 'dictType.sys_oper_type_remark'); INSERT INTO `sys_dict_type` VALUES (10, 'dictType.sys_common_status', 'sys_common_status', '1', 'supervisor', 1699350000000, NULL, 0, 'dictType.sys_common_status_remark'); +INSERT INTO `sys_dict_type` VALUES (11, 'dictType.sys_user_type', 'sys_user_type', '1', 'supervisor', 1699350000000, NULL, 0, ''); INSERT INTO `sys_dict_type` VALUES (100, 'dictType.trace_type', 'trace_type', '1', 'supervisor', 1699350000000, NULL, 0, 'dictType.trace_type_remark'); -- INSERT INTO `sys_dict_type` VALUES (101, 'dictType.operation_log_type', 'operation_log_type', '1', 'supervisor', 1699350000000, NULL, 0, 'dictType.operation_log_type_remark'); INSERT INTO `sys_dict_type` VALUES (102, 'dictType.alarm_status', 'alarm_status', '1', 'supervisor', 1699350000000, NULL, 0, 'dictType.alarm_status_remark'); diff --git a/database/install/sys_login_source.sql b/database/install/sys_login_source.sql new file mode 100644 index 00000000..073189af --- /dev/null +++ b/database/install/sys_login_source.sql @@ -0,0 +1,24 @@ +-- +-- Table structure for table `sys_login_source` +-- + +DROP TABLE IF EXISTS `sys_login_source`; +CREATE TABLE `sys_login_source` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID', + `uid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'UID 16位长度字符串', + `type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '认证类型 LDAP SMTP OAuth2', + `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '认证名称', + `icon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '图标', + `active_flag` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '激活标记(0未激活 1激活)', + `sync_flag` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '同步标记(0未同步 1同步)', + `config` text COLLATE utf8mb4_general_ci COMMENT '认证配置', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` bigint NULL DEFAULT 0 COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` bigint NULL DEFAULT 0 COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '备注', + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_ls_type_name` (`type`,`name`) USING BTREE COMMENT '认证类型_认证名称' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='系统_认证源表'; + +-- Dump completed on 2025-08-05 16:20:56 diff --git a/database/install/sys_menu.sql b/database/install/sys_menu.sql index 7ff42433..fa22fc92 100644 --- a/database/install/sys_menu.sql +++ b/database/install/sys_menu.sql @@ -66,6 +66,7 @@ INSERT INTO `sys_menu` VALUES (105, 'menu.security.post', 2113, 6, 'post', 'syst INSERT INTO `sys_menu` VALUES (106, 'menu.system.dictType', 1, 7, 'dict', 'system/dict/index', '1', '1', 'M', '1', '1', 'system:dict:list', 'icon-tubiaoku', 'supervisor', 1700000000000, NULL, 0, 'menu.system.dictTypeRemark'); INSERT INTO `sys_menu` VALUES (107, 'menu.system.dictData', 1, 8, 'dict/inline/data/:dictId', 'system/dict/data', '1', '1', 'M', '0', '1', 'system:dict:data', '#', 'supervisor', 1700000000000, NULL, 0, 'menu.system.dictDataRemark'); INSERT INTO `sys_menu` VALUES (108, 'menu.system.paramSet', 1, 9, 'config', 'system/config/index', '1', '1', 'M', '1', '1', 'system:config:list', 'icon-gongnengjieshao', 'supervisor', 1700000000000, NULL, 0, 'menu.system.paramSetRemark'); +INSERT INTO `sys_menu` VALUES (109, 'menu.system.loginSource', 2113, 12, 'login-source', 'system/login-source/index', '1', '1', 'M', '1', '1', 'system:loginSource:list', 'icon-xiangmuchengyuan', 'supervisor', 1700000000000, NULL, 0, ''); INSERT INTO `sys_menu` VALUES (111, 'menu.system.systemLog', 1, 11, 'log', NULL, '1', '1', 'D', '0', '0', NULL, '#', 'supervisor', 1700000000000, NULL, 0, 'menu.system.systemLogRemark'); INSERT INTO `sys_menu` VALUES (112, 'menu.system.systemInfo', 1, 5, 'system-info', 'monitor/system/info', '1', '1', 'M', '1', '1', 'monitor:system:info', 'icon-fuzhidaima', 'supervisor', 1700000000000, NULL, 0, 'menu.system.systemInfoRemark'); INSERT INTO `sys_menu` VALUES (113, 'menu.system.cacheInfo', 1, 8, 'cache-info', 'monitor/cache/info', '1', '1', 'M', '1', '1', 'monitor:cache:info', 'icon-gongnengjieshao', 'supervisor', 1700000000000, NULL, 0, 'menu.system.cacheInfoRemark'); @@ -128,6 +129,10 @@ INSERT INTO `sys_menu` VALUES (1053, 'menu.common.edit', 116, 3, '#', NULL, '1', INSERT INTO `sys_menu` VALUES (1054, 'menu.common.delete', 116, 4, '#', NULL, '1', '1', 'B', '1', '1', 'monitor:job:remove', '#', 'supervisor', 1700000000000, NULL, 0, NULL); INSERT INTO `sys_menu` VALUES (1055, 'menu.common.edit', 116, 5, '#', NULL, '1', '1', 'B', '1', '1', 'monitor:job:changeStatus', '#', 'supervisor', 1700000000000, NULL, 0, NULL); INSERT INTO `sys_menu` VALUES (1056, 'menu.common.export', 116, 6, '#', NULL, '1', '1', 'B', '1', '1', 'monitor:job:export', '#', 'supervisor', 1700000000000, NULL, 0, NULL); +INSERT INTO `sys_menu` VALUES (1057, 'menu.common.query', 109, 1, NULL, NULL, '1', '1', 'B', '1', '1', 'system:loginSource:query', '#', 'supervisor', 1700000000000, NULL, 0, NULL); +INSERT INTO `sys_menu` VALUES (1058, 'menu.common.add', 109, 2, NULL, NULL, '1', '1', 'B', '1', '1', 'system:loginSource:add', '#', 'supervisor', 1700000000000, NULL, 0, NULL); +INSERT INTO `sys_menu` VALUES (1059, 'menu.common.edit', 109, 3, NULL, NULL, '1', '1', 'B', '1', '1', 'system:loginSource:edit', '#', 'supervisor', 1700000000000, NULL, 0, NULL); +INSERT INTO `sys_menu` VALUES (1060, 'menu.common.delete', 109, 4, NULL, NULL, '1', '1', 'B', '1', '1', 'system:loginSource:remove', '#', 'supervisor', 1700000000000, NULL, 0, NULL); INSERT INTO `sys_menu` VALUES (2009, 'menu.ueUser.authUDM', 5, 1, 'auth', 'neUser/auth/index', '1', '1', 'M', '1', '1', 'neUser:auth:index', 'icon-xiangmuchengyuan', 'supervisor', 1700000000000, NULL, 0, 'menu.ueUser.authUDMRemark'); INSERT INTO `sys_menu` VALUES (2010, 'menu.ueUser.subUDM', 5, 2, 'sub', 'neUser/sub/index', '1', '1', 'M', '1', '1', 'neUser:sub:index', 'icon-xiangmuchengyuan', 'supervisor', 1700000000000, NULL, 0, 'menu.ueUser.subUDMRemark'); INSERT INTO `sys_menu` VALUES (2011, 'menu.ueUser.voipUDM', 5, 3, 'voip', 'neUser/voip/index', '1', '1', 'M', '1', '1', 'neUser:voip:index', 'icon-xiangmuchengyuan', 'supervisor', 1700000000000, NULL, 0, 'menu.ueUser.voipUDMRemark'); diff --git a/database/install/sys_role_menu.sql b/database/install/sys_role_menu.sql index 387b4e00..b588e7d4 100644 --- a/database/install/sys_role_menu.sql +++ b/database/install/sys_role_menu.sql @@ -1,6 +1,3 @@ -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - -- ---------------------------- -- Table structure for sys_role_menu -- ---------------------------- @@ -27,6 +24,7 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (2, 101); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 102); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 103); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 108); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 109); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 115); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 116); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 117); @@ -62,6 +60,10 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1050); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1051); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1053); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1055); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1057); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1058); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1059); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1060); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2009); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2010); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2011); @@ -270,5 +272,3 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (100, 10019); INSERT IGNORE INTO `sys_role_menu` VALUES (100, 10020); INSERT IGNORE INTO `sys_role_menu` VALUES (100, 10021); INSERT IGNORE INTO `sys_role_menu` VALUES (100, 10022); - -SET FOREIGN_KEY_CHECKS = 1; diff --git a/database/install/sys_user.sql b/database/install/sys_user.sql index f191e38f..6e2df326 100644 --- a/database/install/sys_user.sql +++ b/database/install/sys_user.sql @@ -27,7 +27,8 @@ CREATE TABLE `sys_user` ( `tenant_id` bigint(20) NULL DEFAULT NULL COMMENT 'Tenant ID', `user_name` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户账号', `nick_name` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户昵称', - `user_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'sys' COMMENT '用户类型(sys系统用户)', + `user_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'System' COMMENT '用户类型(System系统用户)', + `user_source` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '#' COMMENT '用户来源UID(#系统)', `email` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '用户邮箱', `phonenumber` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '手机号码', `sex` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '用户性别(0未知 1男 2女)', @@ -51,10 +52,10 @@ CREATE TABLE `sys_user` ( LOCK TABLES `sys_user` WRITE; /*!40000 ALTER TABLE `sys_user` DISABLE KEYS */; -INSERT INTO `sys_user` VALUES (1, 100, null, 'supervisor', 'supervisor', 'sys', '', '', '0', '', '$2a$10$QgIcp6yuOEGrEU0TNU12K.uQRLbcufesEU7hiRYlRSSdUO7OAkoTq', '1', '0', '127.0.0.1', 0, 'system', 0, '', 0, ''); -INSERT INTO `sys_user` VALUES (2, 100, null, 'admin', 'admin', 'sys', '', '', '0', '', '$2a$10$QgIcp6yuOEGrEU0TNU12K.uQRLbcufesEU7hiRYlRSSdUO7OAkoTq', '1', '0', '127.0.0.1', 0, 'system', 0, '', 0, ''); -INSERT INTO `sys_user` VALUES (3, 100, null, 'manager', 'manager', 'sys', '', '', '0', '', '$2a$10$RND3fUw9Ai.WcggYSI57tu.u3OIlktdPxFzlWkmiHC1paV038t0I2', '1', '0', '127.0.0.1', 0, 'system', 0, '', 0, ''); -INSERT INTO `sys_user` VALUES (4, 100, null, 'monitor', 'monitor', 'sys', '', '', '0', '', '$2a$10$t3zpKQ0olECotFyI1yO43.tCoS0EXoSRBDcqwl09xvrsmn14qFHHy', '1', '0', '127.0.0.1', 0, 'system', 0, '', 0, ''); +INSERT INTO `sys_user` VALUES (1, 100, null, 'supervisor', 'supervisor', 'System', '#', '', '', '0', '', '$2a$10$QgIcp6yuOEGrEU0TNU12K.uQRLbcufesEU7hiRYlRSSdUO7OAkoTq', '1', '0', '127.0.0.1', 0, 'system', 0, '', 0, ''); +INSERT INTO `sys_user` VALUES (2, 100, null, 'admin', 'admin', 'System', '#', '', '', '0', '', '$2a$10$QgIcp6yuOEGrEU0TNU12K.uQRLbcufesEU7hiRYlRSSdUO7OAkoTq', '1', '0', '127.0.0.1', 0, 'system', 0, '', 0, ''); +INSERT INTO `sys_user` VALUES (3, 100, null, 'manager', 'manager', 'System', '#', '', '', '0', '', '$2a$10$RND3fUw9Ai.WcggYSI57tu.u3OIlktdPxFzlWkmiHC1paV038t0I2', '1', '0', '127.0.0.1', 0, 'system', 0, '', 0, ''); +INSERT INTO `sys_user` VALUES (4, 100, null, 'monitor', 'monitor', 'System', '#', '', '', '0', '', '$2a$10$t3zpKQ0olECotFyI1yO43.tCoS0EXoSRBDcqwl09xvrsmn14qFHHy', '1', '0', '127.0.0.1', 0, 'system', 0, '', 0, ''); UNLOCK TABLES; diff --git a/database/upgrade/upg_sys_dict_data0.sql b/database/upgrade/upg_sys_dict_data0.sql index 3a7d8d86..eaab8311 100644 --- a/database/upgrade/upg_sys_dict_data0.sql +++ b/database/upgrade/upg_sys_dict_data0.sql @@ -189,6 +189,10 @@ REPLACE INTO `sys_dict_data` VALUES (161, 22, 'dictData.trace_interfaces.22', 'N REPLACE INTO `sys_dict_data` VALUES (162, 40, 'dictData.trace_interfaces.40', 'N40', 'trace_interfaces', '', '', '1', 'supervisor', 1712720201349, '', 0, ''); REPLACE INTO `sys_dict_data` VALUES (163, 14, 'dictData.trace_interfaces.14', 'N14', 'trace_interfaces', '', '', '1', 'supervisor', 1712720201349, '', 0, ''); REPLACE INTO `sys_dict_data` VALUES (164, 5, 'dictData.trace_interfaces.5', 'N5', 'trace_interfaces', '', '', '1', 'supervisor', 1712720201349, '', 0, ''); +REPLACE INTO `sys_dict_data` VALUES (165, 1, 'dictData.sys_user_type.system', 'System', 'sys_user_type', '', 'default', '1', 'supervisor', 1712720201349, '', 0, ''); +REPLACE INTO `sys_dict_data` VALUES (166, 2, 'dictData.sys_user_type.ldap', 'LDAP', 'sys_user_type', '', 'lime', '1', 'supervisor', 1712720201349, '', 0, ''); +REPLACE INTO `sys_dict_data` VALUES (167, 3, 'dictData.sys_user_type.smtp', 'SMTP', 'sys_user_type', '', 'magenta', '1', 'supervisor', 1712720201349, '', 0, ''); +REPLACE INTO `sys_dict_data` VALUES (168, 4, 'dictData.sys_user_type.oauth2', 'OAuth2', 'sys_user_type', '', 'gold', '1', 'supervisor', 1712720201349, '', 0, ''); -- 指定记录条件更新 diff --git a/database/upgrade/upg_sys_dict_data1_i18n_zh.sql b/database/upgrade/upg_sys_dict_data1_i18n_zh.sql index 104bc1bc..62e63fa1 100644 --- a/database/upgrade/upg_sys_dict_data1_i18n_zh.sql +++ b/database/upgrade/upg_sys_dict_data1_i18n_zh.sql @@ -754,6 +754,14 @@ REPLACE INTO `sys_dict_data` VALUES (2236, 2236, 'job.backup_export_cdr', '备 REPLACE INTO `sys_dict_data` VALUES (2237, 2237, 'job.backup_export_cdr_remark', 'dataType: 类型支持 ims/smf/sgwc/smsc\nfileType: 文件类型 csv/xlsx\nhour: 数据时间从任务执行时间前的小时数', 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); REPLACE INTO `sys_dict_data` VALUES (2238, 2238, 'dictData.trace_interfaces.14', 'N14', 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); REPLACE INTO `sys_dict_data` VALUES (2239, 2239, 'dictData.trace_interfaces.5', 'N5', 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +REPLACE INTO `sys_dict_data` VALUES (2240, 2240, "dictType.sys_user_type", "用户类型", 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +REPLACE INTO `sys_dict_data` VALUES (2241, 2241, "dictData.sys_user_type.system", "系统", 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +REPLACE INTO `sys_dict_data` VALUES (2242, 2242, "dictData.sys_user_type.ldap", "LDAP", 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +REPLACE INTO `sys_dict_data` VALUES (2243, 2243, "dictData.sys_user_type.smtp", "SMTP", 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +REPLACE INTO `sys_dict_data` VALUES (2244, 2244, "dictData.sys_user_type.oauth2", "OAuth2", 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +REPLACE INTO `sys_dict_data` VALUES (2245, 2245, "user.export.userType", "用户类型", 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +REPLACE INTO `sys_dict_data` VALUES (2246, 2246, "menu.system.loginSource", "第三方登录认证", 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +REPLACE INTO `sys_dict_data` VALUES (2247, 2247, "log.operate.title.sysLoginSource", "认证源", 'i18n_zh', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); -- multi-tenancy REPLACE INTO `sys_dict_data` VALUES (11000, 11000, 'menu.security.tenant', '租户管理', 'i18n_zh', NULL, NULL, '1', 'supervisor', 1700000000000, NULL, 0, NULL); diff --git a/database/upgrade/upg_sys_dict_data2_i18n_en.sql b/database/upgrade/upg_sys_dict_data2_i18n_en.sql index 238de793..87136860 100644 --- a/database/upgrade/upg_sys_dict_data2_i18n_en.sql +++ b/database/upgrade/upg_sys_dict_data2_i18n_en.sql @@ -755,6 +755,14 @@ REPLACE INTO `sys_dict_data` VALUES (4236, 4236, 'job.backup_export_cdr', 'Backu REPLACE INTO `sys_dict_data` VALUES (4237, 4237, 'job.backup_export_cdr_remark', 'Backup-Periodic export of dataType: type support ims/smf/sgwc/smsc\nfileType: file type csv/xlsx\nhour: data time from the hour before the task execution time', 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); REPLACE INTO `sys_dict_data` VALUES (4238, 4238, 'dictData.trace_interfaces.14', 'N14', 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); REPLACE INTO `sys_dict_data` VALUES (4239, 4239, 'dictData.trace_interfaces.5', 'N5', 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +REPLACE INTO `sys_dict_data` VALUES (4240, 4240, "dictType.sys_user_type", "User Type", 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +REPLACE INTO `sys_dict_data` VALUES (4241, 4241, "dictData.sys_user_type.system", "System", 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +REPLACE INTO `sys_dict_data` VALUES (4242, 4242, "dictData.sys_user_type.ldap", "LDAP", 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +REPLACE INTO `sys_dict_data` VALUES (4243, 4243, "dictData.sys_user_type.smtp", "SMTP", 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +REPLACE INTO `sys_dict_data` VALUES (4244, 4244, "dictData.sys_user_type.oauth2", "OAuth2", 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +REPLACE INTO `sys_dict_data` VALUES (4245, 4245, "user.export.userType", "User Type", 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +REPLACE INTO `sys_dict_data` VALUES (4246, 4246, "menu.system.loginSource", "Third Party Login Source", 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); +REPLACE INTO `sys_dict_data` VALUES (4247, 4247, "log.operate.title.sysLoginSource", "Login Source", 'i18n_en', '', '', '1', 'supervisor', 1721902269805, '', 0, ''); -- 多租户 REPLACE INTO `sys_dict_data` VALUES (14000, 14000, 'menu.security.tenant', 'Tenant Management', 'i18n_en', '', '', '1', 'supervisor', 1705550000000, '', 0, ''); diff --git a/database/upgrade/upg_sys_dict_type.sql b/database/upgrade/upg_sys_dict_type.sql index b183b3c3..6d7290de 100644 --- a/database/upgrade/upg_sys_dict_type.sql +++ b/database/upgrade/upg_sys_dict_type.sql @@ -29,6 +29,7 @@ REPLACE INTO `sys_dict_type` VALUES (5, 'dictType.sys_job_group', 'sys_job_group REPLACE INTO `sys_dict_type` VALUES (6, 'dictType.sys_yes_no', 'sys_yes_no', '1', 'supervisor', 1699350000000, NULL, 0, 'dictType.sys_yes_no_remark'); REPLACE INTO `sys_dict_type` VALUES (9, 'dictType.sys_oper_type', 'sys_oper_type', '1', 'supervisor', 1699350000000, NULL, 0, 'dictType.sys_oper_type_remark'); REPLACE INTO `sys_dict_type` VALUES (10, 'dictType.sys_common_status', 'sys_common_status', '1', 'supervisor', 1699350000000, NULL, 0, 'dictType.sys_common_status_remark'); +REPLACE INTO `sys_dict_type` VALUES (11, 'dictType.sys_user_type', 'sys_user_type', '1', 'supervisor', 1699350000000, NULL, 0, ''); REPLACE INTO `sys_dict_type` VALUES (100, 'dictType.trace_type', 'trace_type', '1', 'supervisor', 1699350000000, NULL, 0, 'dictType.trace_type_remark'); -- REPLACE INTO `sys_dict_type` VALUES (101, 'dictType.operation_log_type', 'operation_log_type', '1', 'supervisor', 1699350000000, NULL, 0, 'dictType.operation_log_type_remark'); REPLACE INTO `sys_dict_type` VALUES (102, 'dictType.alarm_status', 'alarm_status', '1', 'supervisor', 1699350000000, NULL, 0, 'dictType.alarm_status_remark'); diff --git a/database/upgrade/upg_sys_login_source.sql b/database/upgrade/upg_sys_login_source.sql new file mode 100644 index 00000000..e68e205a --- /dev/null +++ b/database/upgrade/upg_sys_login_source.sql @@ -0,0 +1,23 @@ +-- +-- Table structure for table `sys_login_source` +-- + +CREATE TABLE IF NOT EXISTS `sys_login_source` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID', + `uid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'UID 16位长度字符串', + `type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '认证类型 LDAP SMTP OAuth2', + `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '认证名称', + `icon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '图标', + `active_flag` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '激活标记(0未激活 1激活)', + `sync_flag` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '同步标记(0未同步 1同步)', + `config` text COLLATE utf8mb4_general_ci COMMENT '认证配置', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` bigint NULL DEFAULT 0 COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` bigint NULL DEFAULT 0 COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '备注', + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_ls_type_name` (`type`,`name`) USING BTREE COMMENT '认证类型_认证名称' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='系统_认证源表'; + +-- Dump completed on 2025-08-05 16:20:56 diff --git a/database/upgrade/upg_sys_menu.sql b/database/upgrade/upg_sys_menu.sql index 50b926e4..d0841bae 100644 --- a/database/upgrade/upg_sys_menu.sql +++ b/database/upgrade/upg_sys_menu.sql @@ -49,6 +49,7 @@ REPLACE INTO `sys_menu` VALUES (105, 'menu.security.post', 2113, 6, 'post', 'sys REPLACE INTO `sys_menu` VALUES (106, 'menu.system.dictType', 1, 7, 'dict', 'system/dict/index', '1', '1', 'M', '1', '1', 'system:dict:list', 'icon-tubiaoku', 'supervisor', 1700000000000, NULL, 0, 'menu.system.dictTypeRemark'); REPLACE INTO `sys_menu` VALUES (107, 'menu.system.dictData', 1, 8, 'dict/inline/data/:dictId', 'system/dict/data', '1', '1', 'M', '0', '1', 'system:dict:data', '#', 'supervisor', 1700000000000, NULL, 0, 'menu.system.dictDataRemark'); REPLACE INTO `sys_menu` VALUES (108, 'menu.system.paramSet', 1, 9, 'config', 'system/config/index', '1', '1', 'M', '1', '1', 'system:config:list', 'icon-gongnengjieshao', 'supervisor', 1700000000000, NULL, 0, 'menu.system.paramSetRemark'); +REPLACE INTO `sys_menu` VALUES (109, 'menu.system.loginSource', 2113, 12, 'login-source', 'system/login-source/index', '1', '1', 'M', '1', '1', 'system:loginSource:list', 'icon-xiangmuchengyuan', 'supervisor', 1700000000000, NULL, 0, ''); REPLACE INTO `sys_menu` VALUES (111, 'menu.system.systemLog', 1, 11, 'log', NULL, '1', '1', 'D', '0', '0', NULL, '#', 'supervisor', 1700000000000, NULL, 0, 'menu.system.systemLogRemark'); REPLACE INTO `sys_menu` VALUES (112, 'menu.system.systemInfo', 1, 5, 'system-info', 'monitor/system/info', '1', '1', 'M', '1', '1', 'monitor:system:info', 'icon-fuzhidaima', 'supervisor', 1700000000000, NULL, 0, 'menu.system.systemInfoRemark'); REPLACE INTO `sys_menu` VALUES (113, 'menu.system.cacheInfo', 1, 8, 'cache-info', 'monitor/cache/info', '1', '1', 'M', '1', '1', 'monitor:cache:info', 'icon-gongnengjieshao', 'supervisor', 1700000000000, NULL, 0, 'menu.system.cacheInfoRemark'); @@ -111,6 +112,10 @@ REPLACE INTO `sys_menu` VALUES (1053, 'menu.common.edit', 116, 3, '#', NULL, '1' REPLACE INTO `sys_menu` VALUES (1054, 'menu.common.delete', 116, 4, '#', NULL, '1', '1', 'B', '1', '1', 'monitor:job:remove', '#', 'supervisor', 1700000000000, NULL, 0, NULL); REPLACE INTO `sys_menu` VALUES (1055, 'menu.common.edit', 116, 5, '#', NULL, '1', '1', 'B', '1', '1', 'monitor:job:changeStatus', '#', 'supervisor', 1700000000000, NULL, 0, NULL); REPLACE INTO `sys_menu` VALUES (1056, 'menu.common.export', 116, 6, '#', NULL, '1', '1', 'B', '1', '1', 'monitor:job:export', '#', 'supervisor', 1700000000000, NULL, 0, NULL); +REPLACE INTO `sys_menu` VALUES (1057, 'menu.common.query', 109, 1, NULL, NULL, '1', '1', 'B', '1', '1', 'system:loginSource:query', '#', 'supervisor', 1700000000000, NULL, 0, NULL); +REPLACE INTO `sys_menu` VALUES (1058, 'menu.common.add', 109, 2, NULL, NULL, '1', '1', 'B', '1', '1', 'system:loginSource:add', '#', 'supervisor', 1700000000000, NULL, 0, NULL); +REPLACE INTO `sys_menu` VALUES (1059, 'menu.common.edit', 109, 3, NULL, NULL, '1', '1', 'B', '1', '1', 'system:loginSource:edit', '#', 'supervisor', 1700000000000, NULL, 0, NULL); +REPLACE INTO `sys_menu` VALUES (1060, 'menu.common.delete', 109, 4, NULL, NULL, '1', '1', 'B', '1', '1', 'system:loginSource:remove', '#', 'supervisor', 1700000000000, NULL, 0, NULL); REPLACE INTO `sys_menu` VALUES (2009, 'menu.ueUser.authUDM', 5, 1, 'auth', 'neUser/auth/index', '1', '1', 'M', '1', '1', 'neUser:auth:index', 'icon-xiangmuchengyuan', 'supervisor', 1700000000000, NULL, 0, 'menu.ueUser.authUDMRemark'); REPLACE INTO `sys_menu` VALUES (2010, 'menu.ueUser.subUDM', 5, 2, 'sub', 'neUser/sub/index', '1', '1', 'M', '1', '1', 'neUser:sub:index', 'icon-xiangmuchengyuan', 'supervisor', 1700000000000, NULL, 0, 'menu.ueUser.subUDMRemark'); REPLACE INTO `sys_menu` VALUES (2011, 'menu.ueUser.voipUDM', 5, 3, 'voip', 'neUser/voip/index', '1', '1', 'M', '1', '1', 'neUser:voip:index', 'icon-xiangmuchengyuan', 'supervisor', 1700000000000, NULL, 0, 'menu.ueUser.voipUDMRemark'); diff --git a/database/upgrade/upg_sys_role_menu.sql b/database/upgrade/upg_sys_role_menu.sql index e36ebe34..246ac982 100644 --- a/database/upgrade/upg_sys_role_menu.sql +++ b/database/upgrade/upg_sys_role_menu.sql @@ -1,6 +1,3 @@ -SET NAMES utf8mb4; -SET FOREIGN_KEY_CHECKS = 0; - -- ---------------------------- -- Table structure for sys_role_menu -- ---------------------------- @@ -11,6 +8,7 @@ CREATE TABLE IF NOT EXISTS `sys_role_menu` ( PRIMARY KEY (`role_id`, `menu_id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色和菜单关联表' ROW_FORMAT = Dynamic; +DELETE FROM `sys_role_menu` WHERE `role_id` IN (2,3,4,5); -- ---------------------------- -- Records of sys_role_menu -- ---------------------------- @@ -28,6 +26,7 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (2, 101); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 102); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 103); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 108); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 109); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 115); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 116); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 117); @@ -63,6 +62,10 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1050); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1051); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1053); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1055); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1057); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1058); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1059); +INSERT IGNORE INTO `sys_role_menu` VALUES (2, 1060); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2009); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2010); INSERT IGNORE INTO `sys_role_menu` VALUES (2, 2011); @@ -271,5 +274,3 @@ INSERT IGNORE INTO `sys_role_menu` VALUES (100, 10019); INSERT IGNORE INTO `sys_role_menu` VALUES (100, 10020); INSERT IGNORE INTO `sys_role_menu` VALUES (100, 10021); INSERT IGNORE INTO `sys_role_menu` VALUES (100, 10022); - -SET FOREIGN_KEY_CHECKS = 1; diff --git a/database/upgrade/upg_sys_user.sql b/database/upgrade/upg_sys_user.sql index 11c526b0..aeca6d49 100644 --- a/database/upgrade/upg_sys_user.sql +++ b/database/upgrade/upg_sys_user.sql @@ -5,7 +5,8 @@ CREATE TABLE IF NOT EXISTS `sys_user` ( `dept_id` bigint DEFAULT '0' COMMENT '部门ID', `user_name` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户账号', `nick_name` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户昵称', - `user_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'sys' COMMENT '用户类型(sys系统用户)', + `user_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'System' COMMENT '用户类型(System系统用户)', + `user_source` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '#' COMMENT '用户来源UID (系统#)', `email` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '用户邮箱', `phonenumber` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '手机号码', `sex` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '用户性别(0未知 1男 2女)', @@ -25,5 +26,8 @@ CREATE TABLE IF NOT EXISTS `sys_user` ( -- multi-tenancy ALTER TABLE `sys_user` ADD COLUMN IF NOT EXISTS `tenant_id` bigint(20) NULL DEFAULT NULL DEFAULT NULL COMMENT 'Tenant ID' AFTER `dept_id`; +ALTER TABLE `sys_user` ADD COLUMN IF NOT EXISTS `user_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'System' COMMENT '用户类型(System系统用户)' AFTER `password`; +ALTER TABLE `sys_user` ADD COLUMN IF NOT EXISTS `user_source` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '#' COMMENT '用户来源UID (系统#)' AFTER `user_type`; +UPDATE `sys_user` SET `status` = '1', `user_type` = 'System', `user_source` = '#' WHERE `user_id` in (1,2,3,4); SET FOREIGN_KEY_CHECKS=1; \ No newline at end of file diff --git a/go.mod b/go.mod index d441a5a4..5b1fae31 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,14 @@ module be.ems -go 1.22.0 +go 1.24 require ( github.com/dlclark/regexp2 v1.11.4 - github.com/gin-gonic/gin v1.10.0 + github.com/gin-gonic/gin v1.10.1 + github.com/go-ldap/ldap/v3 v3.4.11 github.com/go-resty/resty/v2 v2.14.0 github.com/go-sql-driver/mysql v1.8.1 - github.com/golang-jwt/jwt/v5 v5.2.1 + github.com/golang-jwt/jwt/v5 v5.3.0 github.com/gopacket/gopacket v1.2.0 github.com/gorilla/mux v1.8.1 github.com/gorilla/websocket v1.5.3 @@ -19,9 +20,9 @@ require ( github.com/mojocn/base64Captcha v1.3.6 github.com/mssola/useragent v1.0.0 github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/pkg/sftp v1.13.6 - github.com/prometheus-community/pro-bing v0.5.0 - github.com/redis/go-redis/v9 v9.7.0 + github.com/pkg/sftp v1.13.9 + github.com/prometheus-community/pro-bing v0.7.0 + github.com/redis/go-redis/v9 v9.12.0 github.com/robfig/cron/v3 v3.0.1 github.com/shirou/gopsutil/v4 v4.24.12 github.com/slayercat/GoSNMPServer v0.5.2 @@ -30,11 +31,13 @@ require ( github.com/swaggo/files v1.0.1 github.com/swaggo/gin-swagger v1.6.0 github.com/swaggo/swag v1.16.4 + github.com/wneessen/go-mail v0.6.2 github.com/xuri/excelize/v2 v2.9.0 github.com/xuri/xgen v0.0.0-20240722131518-d0691b701898 - golang.org/x/crypto v0.31.0 - golang.org/x/term v0.28.0 - golang.org/x/text v0.21.0 + golang.org/x/crypto v0.36.0 + golang.org/x/oauth2 v0.30.0 + golang.org/x/term v0.30.0 + golang.org/x/text v0.23.0 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/yaml.v3 v3.0.1 gorm.io/driver/mysql v1.5.7 @@ -42,10 +45,9 @@ require ( xorm.io/xorm v1.3.9 ) -require golang.org/x/net v0.33.0 // indirect - require ( filippo.io/edwards25519 v1.1.0 // indirect + github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect github.com/KyleBanks/depth v1.2.1 // indirect github.com/beorn7/perks v1.0.1 // indirect; indirect // indirect github.com/bytedance/sonic v1.12.1 // indirect; indirect // indirect @@ -60,6 +62,7 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.5 // indirect github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect github.com/go-forks/fsnotify v1.4.7 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect @@ -83,7 +86,7 @@ require ( github.com/klauspost/compress v1.17.9 // indirect; indirect // indirect github.com/klauspost/cpuid/v2 v2.2.8 // indirect; indirect // indirect github.com/konsorten/go-windows-terminal-sequences v1.0.1 // indirect - github.com/kr/fs v0.1.0 // indirect; indirect // indirect + github.com/kr/fs v0.1.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect; indirect // indirect github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 // indirect github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect @@ -131,8 +134,9 @@ require ( golang.org/x/arch v0.9.0 // indirect golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect golang.org/x/image v0.19.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.29.0 // indirect + golang.org/x/net v0.38.0 // indirect + golang.org/x/sync v0.13.0 // indirect + golang.org/x/sys v0.31.0 // indirect golang.org/x/tools v0.28.0 // indirect golang.org/x/tools/cmd/guru v0.1.1-deprecated // indirect google.golang.org/protobuf v1.34.2 // indirect diff --git a/go.sum b/go.sum index e013b378..d8cef023 100644 --- a/go.sum +++ b/go.sum @@ -2,9 +2,13 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU= +github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= +github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= +github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= @@ -51,10 +55,14 @@ github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= -github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ= +github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo= +github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-forks/fsnotify v1.4.7 h1:lyiU2Wqd4fNGCQDn9dZ4UxSiSFgeU1rM6yIfahk8haY= github.com/go-forks/fsnotify v1.4.7/go.mod h1:AU8mot+GznW5+B4jRJHxKg/2EeO+jMORGRkKSxs0biw= +github.com/go-ldap/ldap/v3 v3.4.11 h1:4k0Yxweg+a3OyBLjdYn5OKglv18JNvfDykSoI8bW0gU= +github.com/go-ldap/ldap/v3 v3.4.11/go.mod h1:bY7t0FLK8OAVpp/vV6sSlpz3EQDGcQwc8pF0ujLgKvM= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= @@ -82,8 +90,8 @@ github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqw github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= -github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= +github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= @@ -117,9 +125,23 @@ github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/gosnmp/gosnmp v1.36.2-0.20231009064202-d306ed5aa998/go.mod h1:O938QjIS4vpSag1UTcnnBq9MfNmimuOGtvQsT1NbErc= github.com/gosnmp/gosnmp v1.38.0 h1:I5ZOMR8kb0DXAFg/88ACurnuwGwYkXWq3eLpJPHMEYc= github.com/gosnmp/gosnmp v1.38.0/go.mod h1:FE+PEZvKrFz9afP9ii1W3cprXuVZ17ypCcyyfYuu5LY= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= +github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= +github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -213,16 +235,16 @@ github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6 github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= -github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= +github.com/pkg/sftp v1.13.9 h1:4NGkvGudBL7GteO3m6qnaQ4pC0Kvf0onSVc9gR3EWBw= +github.com/pkg/sftp v1.13.9/go.mod h1:OBN7bVXdstkFFN/gdnHPUb5TE8eb8G1Rp9wCItqjkkA= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/prometheus-community/pro-bing v0.5.0 h1:Fq+4BUXKIvsPtXUY8K+04ud9dkAuFozqGmRAyNUpffY= -github.com/prometheus-community/pro-bing v0.5.0/go.mod h1:1joR9oXdMEAcAJJvhs+8vNDvTg5thfAZcRFhcUozG2g= +github.com/prometheus-community/pro-bing v0.7.0 h1:KFYFbxC2f2Fp6c+TyxbCOEarf7rbnzr9Gw8eIb0RfZA= +github.com/prometheus-community/pro-bing v0.7.0/go.mod h1:Moob9dvlY50Bfq6i88xIwfyw7xLFHH69LUgx9n5zqCE= github.com/prometheus/client_golang v1.20.0 h1:jBzTZ7B099Rg24tny+qngoynol8LtVYlA2bqx3vEloI= github.com/prometheus/client_golang v1.20.0/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= @@ -232,8 +254,8 @@ github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65 github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= -github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= +github.com/redis/go-redis/v9 v9.12.0 h1:XlVPGlflh4nxfhsNXPA8Qp6EmEfTo0rp8oaBzPipXnU= +github.com/redis/go-redis/v9 v9.12.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM= @@ -316,6 +338,8 @@ github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJ github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/wneessen/go-mail v0.6.2 h1:c6V7c8D2mz868z9WJ+8zDKtUyLfZ1++uAZmo2GRFji8= +github.com/wneessen/go-mail v0.6.2/go.mod h1:L/PYjPK3/2ZlNb2/FjEBIn9n1rUWjW+Toy531oVmeb4= github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d h1:llb0neMWDQe87IzJLS4Ci7psK/lVsjIS2otl+1WyRyY= github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= github.com/xuri/excelize/v2 v2.9.0 h1:1tgOaEq92IOEumR1/JfYS/eR0KHOCsRv/rYXXh6YJQE= @@ -338,13 +362,14 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI= golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk= @@ -369,7 +394,6 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= @@ -377,8 +401,10 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -389,8 +415,10 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= +golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -420,32 +448,36 @@ golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= -golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= -golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/lib/midware/operate_log.go b/lib/midware/operate_log.go index a2647281..284ee6e0 100644 --- a/lib/midware/operate_log.go +++ b/lib/midware/operate_log.go @@ -46,25 +46,31 @@ func LogOperate(options collectlogs.Options) func(http.Handler) http.Handler { lastDotIndex := strings.LastIndex(funcName, "/") funcName = funcName[lastDotIndex+1:] - // 用户名 - username := ctx.LoginUserToUserName(r) - + // 获取登录用户信息 + loginUser, err := ctx.LoginUser(r) + if err != nil { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } // 解析ip地址 ip := strings.Split(r.RemoteAddr, ":")[0] ipaddr := ip2region.ClientIP(ip) location := ip2region.RealAddressByIp(ipaddr) + // 操作日志记录 operLog := model.SysLogOperate{ Title: options.Title, BusinessType: options.BusinessType, - OperatorType: collectlogs.OPERATOR_TYPE_MANAGE, + OperatorType: loginUser.User.UserType, Method: funcName, OperURL: r.RequestURI, RequestMethod: r.Method, OperIP: ipaddr, OperLocation: location, - OperName: username, - DeptName: "", + OperName: loginUser.User.UserName, + DeptName: loginUser.User.Dept.DeptName, + TenantName: loginUser.User.Tenant.TenantName, + TenantID: loginUser.User.Tenant.TenantID, } // 是否需要保存request,参数和值 @@ -120,8 +126,15 @@ func LogOperate(options collectlogs.Options) func(http.Handler) http.Handler { contentDisposition := w.Header().Get("Content-Disposition") contentType := w.Header().Get("Content-Type") content := contentType + contentDisposition - msg := fmt.Sprintf(`{"status":"%s","size":"%s","content-type":"%s"}`, status, size, content) - operLog.OperMsg = msg + msgByte, err := json.Marshal(map[string]any{ + "status": status, + "size": size, + "content-type": content, + }) + if err != nil { + operLog.OperMsg = "" + } + operLog.OperMsg = string(msgByte) } // 日志记录时间 diff --git a/src/framework/database/db/expand.go b/src/framework/database/db/expand.go index 7212e4ca..ec4af539 100644 --- a/src/framework/database/db/expand.go +++ b/src/framework/database/db/expand.go @@ -60,7 +60,7 @@ func ImportSQL() { processSQLFile(db, sqlPath) } - log.Println("process success") + // log.Println("process success") os.Exit(0) } @@ -93,8 +93,36 @@ func processSQLFile(db *gorm.DB, filePath string) { if strings.HasSuffix(line, ";") { // 执行 SQL 语句 if err := db.Exec(sqlBuilder.String()).Error; err != nil { - log.Fatalln(err.Error()) - return + errorStr := strings.ToLower(err.Error()) + // log.Printf("Exec SQL: %s\n", line) + // log.Println(err.Error()) + if strings.Contains(errorStr, "duplicate column") { + // 忽略重复字段错误 + // Error 1060 (42S21): Duplicate column name 'field_name' + // SQL logic error: duplicate column name: title (1) + } else if strings.Contains(errorStr, "duplicate key") { + // 忽略重复索引错误 + // Error 1061 (42000): Duplicate key name 'key_name' + } else if strings.Contains(errorStr, "duplicate entry") { + // 忽略重复记录错误 + // Error 1062 (23000): Duplicate entry 'value' for key 'key_name' + log.Println(err.Error()) + } else if strings.Contains(errorStr, "unknown column") { + // 忽略未知字段错误 + // Error 1054 (42S22): Unknown column 'field_name' in 'table' + } else if strings.Contains(errorStr, "can't drop") { + // 忽略删除字段或索引错误 + // Error 1091 (42000): Can't DROP COLUMN `field_name`; check that it exists + // Error 1091 (42000): Can't DROP 'idx_ne_type_id'; check that column/key exists + } else if strings.Contains(errorStr, "doesn't match") { + // 忽略列数不匹配错误 + // Error 1136 (21S01): Column count doesn't match value count at row 1 + log.Println(err.Error()) + } else { + // 其他错误终止程序 + log.Fatalln(errorStr) + return + } } sqlBuilder.Reset() diff --git a/src/framework/i18n/i18n.go b/src/framework/i18n/i18n.go index 3d24f114..6c4f3e78 100644 --- a/src/framework/i18n/i18n.go +++ b/src/framework/i18n/i18n.go @@ -15,8 +15,14 @@ type localeItem struct { Code string `json:"code"` } +var dataCache map[string][]localeItem = make(map[string][]localeItem) + // LoadLocaleData 加载国际化数据 func LoadLocaleData(language string) []localeItem { + if data, ok := dataCache[language]; ok { + return data + } + dictType := fmt.Sprintf("i18n_%s", language) dictTypeList := systemService.NewSysDictType.DictDataCache(dictType) localeData := []localeItem{} @@ -27,6 +33,7 @@ func LoadLocaleData(language string) []localeItem { Code: v.DictCode, }) } + dataCache[language] = localeData return localeData } diff --git a/src/framework/middleware/collectlogs/operate_log.go b/src/framework/middleware/collectlogs/operate_log.go index 825980fd..56951d72 100644 --- a/src/framework/middleware/collectlogs/operate_log.go +++ b/src/framework/middleware/collectlogs/operate_log.go @@ -2,7 +2,6 @@ package collectlogs import ( "encoding/json" - "fmt" "reflect" "strings" "time" @@ -48,22 +47,11 @@ const ( BUSINESS_TYPE_CLEAN = "8" ) -const ( - // 操作人类别-其它 - OPERATOR_TYPE_OTHER = "0" - - // 操作人类别-后台用户 - OPERATOR_TYPE_MANAGE = "1" - - // 操作人类别-手机端用户 - OPERATOR_TYPE_MOBILE = "2" -) - // Option 操作日志参数 type Options struct { Title string `json:"title"` // 标题 BusinessType string `json:"businessType"` // 类型,默认常量 BUSINESS_TYPE_OTHER - OperatorType string `json:"operatorType"` // 操作人类别,默认常量 OPERATOR_TYPE_OTHER + OperatorType string `json:"operatorType"` // 操作人类别 IsSaveRequestData bool `json:"isSaveRequestData"` // 是否保存请求的参数 IsSaveResponseData bool `json:"isSaveResponseData"` // 是否保存响应的参数 } @@ -79,7 +67,6 @@ func OptionNew(title, businessType string) Options { return Options{ Title: title, BusinessType: businessType, - OperatorType: OPERATOR_TYPE_OTHER, IsSaveRequestData: true, IsSaveResponseData: true, } @@ -113,7 +100,7 @@ func OperateLog(options Options) gin.HandlerFunc { operLog := model.SysLogOperate{ Title: options.Title, BusinessType: options.BusinessType, - OperatorType: options.OperatorType, + OperatorType: loginUser.User.UserType, Method: funcName, OperURL: c.Request.URL.Path, RequestMethod: c.Request.Method, @@ -125,10 +112,6 @@ func OperateLog(options Options) gin.HandlerFunc { TenantID: loginUser.User.Tenant.TenantID, } - if loginUser.User.UserType == "sys" { - operLog.OperatorType = OPERATOR_TYPE_MANAGE - } - // 是否需要保存request,参数和值 if options.IsSaveRequestData { params := ctx.RequestParamsMap(c) @@ -158,8 +141,15 @@ func OperateLog(options Options) gin.HandlerFunc { contentDisposition := c.Writer.Header().Get("Content-Disposition") contentType := c.Writer.Header().Get("Content-Type") content := contentType + contentDisposition - msg := fmt.Sprintf(`{"status":"%d","size":"%d","content-type":"%s"}`, status, c.Writer.Size(), content) - operLog.OperMsg = msg + msgByte, err := json.Marshal(map[string]any{ + "status": status, + "size": c.Writer.Size(), + "content-type": content, + }) + if err != nil { + operLog.OperMsg = "" + } + operLog.OperMsg = string(msgByte) } // 日志记录时间 diff --git a/src/modules/common/common.go b/src/modules/common/common.go index 7d201a24..d703917c 100644 --- a/src/modules/common/common.go +++ b/src/modules/common/common.go @@ -67,6 +67,52 @@ func Setup(router *gin.Engine) { ) } + // 登录认证源 + account := controller.NewAccount + accountGroup := router.Group("/auth") + { + accountGroup.GET("/login/source", + middleware.RateLimit(middleware.LimitOption{ + Time: 300, + Count: 60, + Type: middleware.LIMIT_IP, + }), + account.LoginSource, + ) + accountGroup.POST("/login/ldap", + middleware.RateLimit(middleware.LimitOption{ + Time: 180, + Count: 15, + Type: middleware.LIMIT_IP, + }), + account.LDAP, + ) + accountGroup.POST("/login/smtp", + middleware.RateLimit(middleware.LimitOption{ + Time: 180, + Count: 15, + Type: middleware.LIMIT_IP, + }), + account.SMTP, + ) + accountGroup.GET("/login/oauth2/authorize", + middleware.RateLimit(middleware.LimitOption{ + Time: 180, + Count: 15, + Type: middleware.LIMIT_IP, + }), + account.OAuth2CodeURL, + ) + accountGroup.POST("/login/oauth2/token", + middleware.RateLimit(middleware.LimitOption{ + Time: 180, + Count: 15, + Type: middleware.LIMIT_IP, + }), + account.OAuth2Token, + ) + } + // 账号注册操作处理 { indexGroup.POST("/register", diff --git a/src/modules/common/controller/account.go b/src/modules/common/controller/account.go index 694132bb..0f39b414 100644 --- a/src/modules/common/controller/account.go +++ b/src/modules/common/controller/account.go @@ -5,6 +5,7 @@ import ( commonConstants "be.ems/src/framework/constants/common" tokenConstants "be.ems/src/framework/constants/token" "be.ems/src/framework/i18n" + "be.ems/src/framework/resp" "be.ems/src/framework/utils/ctx" tokenUtils "be.ems/src/framework/utils/token" "be.ems/src/framework/vo" @@ -201,3 +202,11 @@ func (s *AccountController) Logout(c *gin.Context) { c.JSON(200, result.OkMsg(i18n.TKey(language, "app.common.logoutSuccess"))) } + +// LoginSource 登录认证源 +// +// GET /auth/login/source +func (s AccountController) LoginSource(c *gin.Context) { + data := s.accountService.LoginSource() + c.JSON(200, resp.OkData(data)) +} diff --git a/src/modules/common/controller/account_ldap.go b/src/modules/common/controller/account_ldap.go new file mode 100644 index 00000000..d314e0cf --- /dev/null +++ b/src/modules/common/controller/account_ldap.go @@ -0,0 +1,67 @@ +package controller + +import ( + "fmt" + + commonConstants "be.ems/src/framework/constants/common" + tokenConstants "be.ems/src/framework/constants/token" + "be.ems/src/framework/i18n" + "be.ems/src/framework/reqctx" + "be.ems/src/framework/resp" + tokenUtils "be.ems/src/framework/utils/token" + "be.ems/src/framework/vo/result" + "be.ems/src/modules/common/model" + + "github.com/gin-gonic/gin" +) + +// LDAP LDAP认证登录 +// +// POST /auth/ldap +// +// @Tags common/authorization +// @Accept json +// @Produce json +// @Param data body object true "Request Param" +// @Success 200 {object} object "Response Results" +// @Summary System Login +// @Description System Login +// @Router /auth/ldap [post] +func (s AccountController) LDAP(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + var body model.LoginSourceBody + if err := c.ShouldBindJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + + // 当前请求信息 + ipaddr, location := reqctx.IPAddrLocation(c) + os, browser := reqctx.UaOsBrowser(c) + + // 登录用户信息 + loginUser, err := s.accountService.ByLDAP(body) + if err != nil { + c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error()))) + return + } + + // 生成令牌,创建系统访问记录 + tokenStr := tokenUtils.Create(&loginUser, ipaddr, location, os, browser) + if tokenStr == "" { + c.JSON(200, result.Err(nil)) + return + } else { + s.accountService.UpdateLoginDateAndIP(&loginUser) + // 登录成功 + s.sysLogLoginService.CreateSysLogLogin( + body.Username, commonConstants.STATUS_YES, "app.common.loginSuccess", + ipaddr, location, os, browser, + ) + } + + c.JSON(200, result.OkData(map[string]any{ + tokenConstants.RESPONSE_FIELD: tokenStr, + })) +} diff --git a/src/modules/common/controller/account_oauth2.go b/src/modules/common/controller/account_oauth2.go new file mode 100644 index 00000000..9b8f0308 --- /dev/null +++ b/src/modules/common/controller/account_oauth2.go @@ -0,0 +1,94 @@ +package controller + +import ( + "fmt" + + commonConstants "be.ems/src/framework/constants/common" + tokenConstants "be.ems/src/framework/constants/token" + "be.ems/src/framework/i18n" + "be.ems/src/framework/reqctx" + "be.ems/src/framework/resp" + tokenUtils "be.ems/src/framework/utils/token" + "be.ems/src/framework/vo/result" + "be.ems/src/modules/common/model" + + "github.com/gin-gonic/gin" +) + +// OAuth2CodeURL OAuth2认证跳转登录URL +// +// GET /auth/login/oauth2/authorize +// +// @Tags common/authorization +// @Accept json +// @Produce json +// @Param data body object true "Request Param" +// @Success 200 {object} object "Response Results" +// @Summary System Login +// @Description System Login +// @Router /auth/login/oauth2/authorize [get] +func (s AccountController) OAuth2CodeURL(c *gin.Context) { + state := c.Query("state") + if state == "" { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: state is empty")) + return + } + + redirectURL, err := s.accountService.ByOAuth2CodeURL(state) + if err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + c.Redirect(302, redirectURL) +} + +// OAuth2 OAuth2认证登录 +// +// POST /auth/login/oauth2/token +// +// @Tags common/authorization +// @Accept json +// @Produce json +// @Param data body object true "Request Param" +// @Success 200 {object} object "Response Results" +// @Summary System Login +// @Description System Login +// @Router /auth/login/oauth2/token [post] +func (s AccountController) OAuth2Token(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + var body model.LoginSourceOauth2Body + if err := c.ShouldBindJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + + // 当前请求信息 + ipaddr, location := reqctx.IPAddrLocation(c) + os, browser := reqctx.UaOsBrowser(c) + + // 登录用户信息 + loginUser, err := s.accountService.ByOAuth2(body) + if err != nil { + c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error()))) + return + } + + // 生成令牌,创建系统访问记录 + tokenStr := tokenUtils.Create(&loginUser, ipaddr, location, os, browser) + if tokenStr == "" { + c.JSON(200, result.Err(nil)) + return + } else { + s.accountService.UpdateLoginDateAndIP(&loginUser) + // 登录成功 + s.sysLogLoginService.CreateSysLogLogin( + body.State, commonConstants.STATUS_YES, "app.common.loginSuccess", + ipaddr, location, os, browser, + ) + } + + c.JSON(200, result.OkData(map[string]any{ + tokenConstants.RESPONSE_FIELD: tokenStr, + })) +} diff --git a/src/modules/common/controller/account_smtp.go b/src/modules/common/controller/account_smtp.go new file mode 100644 index 00000000..b75eca69 --- /dev/null +++ b/src/modules/common/controller/account_smtp.go @@ -0,0 +1,67 @@ +package controller + +import ( + "fmt" + + commonConstants "be.ems/src/framework/constants/common" + tokenConstants "be.ems/src/framework/constants/token" + "be.ems/src/framework/i18n" + "be.ems/src/framework/reqctx" + "be.ems/src/framework/resp" + tokenUtils "be.ems/src/framework/utils/token" + "be.ems/src/framework/vo/result" + "be.ems/src/modules/common/model" + + "github.com/gin-gonic/gin" +) + +// SMTP SMTP认证登录 +// +// POST /auth/smtp +// +// @Tags common/authorization +// @Accept json +// @Produce json +// @Param data body object true "Request Param" +// @Success 200 {object} object "Response Results" +// @Summary System Login +// @Description System Login +// @Router /auth/smtp [post] +func (s AccountController) SMTP(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + var body model.LoginSourceBody + if err := c.ShouldBindJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + + // 当前请求信息 + ipaddr, location := reqctx.IPAddrLocation(c) + os, browser := reqctx.UaOsBrowser(c) + + // 登录用户信息 + loginUser, err := s.accountService.BySMTP(body) + if err != nil { + c.JSON(200, result.ErrMsg(i18n.TKey(language, err.Error()))) + return + } + + // 生成令牌,创建系统访问记录 + tokenStr := tokenUtils.Create(&loginUser, ipaddr, location, os, browser) + if tokenStr == "" { + c.JSON(200, result.Err(nil)) + return + } else { + s.accountService.UpdateLoginDateAndIP(&loginUser) + // 登录成功 + s.sysLogLoginService.CreateSysLogLogin( + body.Username, commonConstants.STATUS_YES, "app.common.loginSuccess", + ipaddr, location, os, browser, + ) + } + + c.JSON(200, result.OkData(map[string]any{ + tokenConstants.RESPONSE_FIELD: tokenStr, + })) +} diff --git a/src/modules/common/model/login_source_vo.go b/src/modules/common/model/login_source_vo.go new file mode 100644 index 00000000..7b63ad57 --- /dev/null +++ b/src/modules/common/model/login_source_vo.go @@ -0,0 +1,22 @@ +package model + +// LoginSourceVo 认证源登录对象 +type LoginSourceVo struct { + UID string `json:"uid"` // UID 认证源UID + Name string `json:"name"` // Name 认证源名称 + Type string `json:"type"` // Type 认证源类型 + Icon string `json:"icon"` // Icon 认证源图标 +} + +// LoginSourceBody 认证源用户登录对象 +type LoginSourceBody struct { + Username string `json:"username" binding:"required"` // Username 用户名 + Password string `json:"password" binding:"required"` // Password 用户密码 + UID string `json:"uid" binding:"required"` // UID 认证源唯一标识 +} + +// LoginSourceOauth2Body 认证源OAuth2用户登录对象 +type LoginSourceOauth2Body struct { + Code string `json:"code" binding:"required"` // Code 授权码 + State string `json:"state" binding:"required"` // State 状态-认证源唯一标识 +} diff --git a/src/modules/common/service/account.go b/src/modules/common/service/account.go index 6dc4ef38..5f9f499b 100644 --- a/src/modules/common/service/account.go +++ b/src/modules/common/service/account.go @@ -5,6 +5,7 @@ import ( "time" "be.ems/src/framework/config" + "be.ems/src/framework/constants" adminConstants "be.ems/src/framework/constants/admin" "be.ems/src/framework/constants/cachekey" "be.ems/src/framework/constants/common" @@ -12,16 +13,18 @@ import ( "be.ems/src/framework/utils/crypto" "be.ems/src/framework/utils/parse" "be.ems/src/framework/vo" - "be.ems/src/modules/system/model" + "be.ems/src/modules/common/model" + systemModel "be.ems/src/modules/system/model" systemService "be.ems/src/modules/system/service" ) // 实例化服务层 Account 结构体 var NewAccount = &Account{ - sysUserService: systemService.NewSysUserImpl, - sysConfigService: systemService.NewSysConfigImpl, - sysRoleService: systemService.NewSysRoleImpl, - sysMenuService: systemService.NewSysMenuImpl, + sysUserService: systemService.NewSysUserImpl, + sysConfigService: systemService.NewSysConfigImpl, + sysRoleService: systemService.NewSysRoleImpl, + sysMenuService: systemService.NewSysMenuImpl, + sysLogSourceService: systemService.NewSysLoginSource, } // 账号身份操作服务 服务层处理 @@ -33,7 +36,8 @@ type Account struct { // 角色服务 sysRoleService systemService.ISysRole // 菜单服务 - sysMenuService systemService.ISysMenu + sysMenuService systemService.ISysMenu + sysLogSourceService *systemService.SysLoginSource // 认证源 } // ValidateCaptcha 校验验证码 @@ -72,7 +76,7 @@ func (s *Account) LoginByUsername(username, password string) (vo.LoginUser, erro } // 查询用户登录账号 - sysUser := s.sysUserService.SelectUserByUserName(username) + sysUser := s.sysUserService.FindByUserName(username, "System", "#") if sysUser.UserName != username { return loginUser, fmt.Errorf("login.errNameOrPasswd") } @@ -113,7 +117,7 @@ func (s *Account) LoginByUsername(username, password string) (vo.LoginUser, erro // UpdateLoginDateAndIP 更新登录时间和IP func (s *Account) UpdateLoginDateAndIP(loginUser *vo.LoginUser) bool { sysUser := loginUser.User - userInfo := model.SysUser{ + userInfo := systemModel.SysUser{ UserID: sysUser.UserID, LoginIP: sysUser.LoginIP, LoginDate: sysUser.LoginDate, @@ -192,3 +196,44 @@ func (s *Account) RouteMenus(userId string, isAdmin bool) []vo.Router { } return buildMenus } + +// LoginSource 登录认证源 +func (s Account) LoginSource() []model.LoginSourceVo { + rows := s.sysLogSourceService.FindByActive("") + data := make([]model.LoginSourceVo, 0) + for _, v := range rows { + data = append(data, model.LoginSourceVo{ + UID: v.UID, + Name: v.Name, + Type: v.Type, + Icon: v.Icon, + }) + } + return data +} + +// initLoginSourceUser 初始化登录源用户 +func (s *Account) initLoginSourceUser(uid, sType, username, password string) systemModel.SysUser { + sysUser := systemModel.SysUser{ + UserName: username, + NickName: username, // 昵称使用名称账号 + Password: password, // 原始密码 + UserType: sType, + UserSource: uid, + Sex: "0", // 性别未选择 + Status: constants.STATUS_YES, // 账号状态激活 + DeptID: "101", // 归属部门为根节点 + CreateBy: sType, // 创建来源 + } + + // 新增用户的角色管理 + sysUser.RoleIDs = []string{"5"} + // 新增用户的岗位管理 + sysUser.PostIDs = []string{} + + insertId := s.sysUserService.InsertUser(sysUser) + if insertId != "" { + sysUser.UserID = insertId + } + return s.sysUserService.FindByUserName(username, sType, uid) +} diff --git a/src/modules/common/service/account_ldap.go b/src/modules/common/service/account_ldap.go new file mode 100644 index 00000000..3696ac42 --- /dev/null +++ b/src/modules/common/service/account_ldap.go @@ -0,0 +1,111 @@ +package service + +import ( + "encoding/json" + "fmt" + + "github.com/go-ldap/ldap/v3" + + "be.ems/src/framework/config" + adminConstants "be.ems/src/framework/constants/admin" + "be.ems/src/framework/constants/common" + "be.ems/src/framework/utils/parse" + "be.ems/src/framework/vo" + "be.ems/src/modules/common/model" + systemModelVo "be.ems/src/modules/system/model/vo" +) + +// ByLDAP 登录创建用户信息 +func (s *Account) ByLDAP(body model.LoginSourceBody) (vo.LoginUser, error) { + loginUser := vo.LoginUser{} + rows := s.sysLogSourceService.FindByActive(body.UID) + if len(rows) != 1 { + return loginUser, fmt.Errorf("ldap auth source not exist") + } + item := rows[0] + if item.Config == "" { + return loginUser, fmt.Errorf("ldap auth source config is empty") + } + var source systemModelVo.SysLoginSourceLDAP + if err := json.Unmarshal([]byte(item.Config), &source); err != nil { + return loginUser, err + } + + // 校验LDAP用户 + err := ldapAuth(source, body.Username, body.Password) + if err != nil { + return loginUser, err + } + + // 查询用户登录账号 + sysUser := s.sysUserService.FindByUserName(body.Username, item.Type, item.UID) + if sysUser.UserID == "" || sysUser.UserName == "" { + sysUser = s.initLoginSourceUser(item.UID, item.Type, body.Username, body.Password) + } + if sysUser.UserID == "" || sysUser.UserName != body.Username { + return loginUser, fmt.Errorf("login.errNameOrPasswd") + } + if sysUser.DelFlag == common.STATUS_YES { + // 对不起,您的账号已被删除 + return loginUser, fmt.Errorf("login.errDelFlag") + } + if sysUser.Status == common.STATUS_NO { + return loginUser, fmt.Errorf("login.errStatus") + } + + // 登录用户信息 + loginUser.UserID = sysUser.UserID + loginUser.DeptID = sysUser.DeptID + loginUser.User = sysUser + // 用户权限组标识 + isAdmin := config.IsAdmin(sysUser.UserID) + if isAdmin { + loginUser.Permissions = []string{adminConstants.PERMISSION} + } else { + perms := s.sysMenuService.SelectMenuPermsByUserId(sysUser.UserID) + loginUser.Permissions = parse.RemoveDuplicates(perms) + } + return loginUser, nil +} + +// ldapAuth 校验LDAP用户 +func ldapAuth(source systemModelVo.SysLoginSourceLDAP, username, password string) error { + // 连接LDAP + l, err := ldap.DialURL(source.URL) + if err != nil { + return err + } + defer l.Close() + + // 绑定DN校验 + if source.BindDN != "" && source.BindPassword != "" { + if err := l.Bind(source.BindDN, source.BindPassword); err != nil { + return fmt.Errorf("ldap user bind %s", err) + } + } + + // 搜索用户 + searchRequest := ldap.NewSearchRequest( + source.BaseDN, + ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, + fmt.Sprintf(source.UserFilter, ldap.EscapeFilter(username)), + []string{"dn", "uid"}, + nil, + ) + sr, err := l.Search(searchRequest) + if err != nil { + return fmt.Errorf("ldap user search %s", err) + } + // for _, entry := range sr.Entries { + // fmt.Printf("%s ==== %v\n", entry.DN, entry.GetAttributeValue("uid")) + // } + if len(sr.Entries) != 1 { + return fmt.Errorf("ldap user does not exist or too many entries returned") + } + + // 校验密码 + if err = l.Bind(sr.Entries[0].DN, password); err != nil { + return fmt.Errorf("ldap user bind %s", err) + } + return nil +} diff --git a/src/modules/common/service/account_oauth2.go b/src/modules/common/service/account_oauth2.go new file mode 100644 index 00000000..f6790ca8 --- /dev/null +++ b/src/modules/common/service/account_oauth2.go @@ -0,0 +1,171 @@ +package service + +import ( + "context" + "encoding/json" + "fmt" + "reflect" + "strings" + "time" + + "golang.org/x/oauth2" + + "be.ems/src/framework/config" + adminConstants "be.ems/src/framework/constants/admin" + "be.ems/src/framework/constants/common" + "be.ems/src/framework/utils/parse" + "be.ems/src/framework/vo" + "be.ems/src/modules/common/model" + systemModelVo "be.ems/src/modules/system/model/vo" +) + +// ByOAuth2CodeURL 获取OAuth2登录URL +func (s *Account) ByOAuth2CodeURL(state string) (string, error) { + rows := s.sysLogSourceService.FindByActive(state) + if len(rows) != 1 { + return "", fmt.Errorf("oauth2 auth source not exist") + } + item := rows[0] + if item.Config == "" { + return "", fmt.Errorf("oauth2 auth source config is empty") + } + var source systemModelVo.SysLoginSourceOAuth2 + json.Unmarshal([]byte(item.Config), &source) + + conf := oauth2.Config{ + ClientID: source.ClientID, + ClientSecret: source.ClientSecret, + RedirectURL: source.RedirectURL, + Scopes: source.Scopes, + Endpoint: oauth2.Endpoint{ + AuthURL: source.AuthURL, + TokenURL: source.TokenURL, + }, + } + return conf.AuthCodeURL(state, oauth2.AccessTypeOffline), nil +} + +// ByOAuth2 登录创建用户信息 +func (s *Account) ByOAuth2(body model.LoginSourceOauth2Body) (vo.LoginUser, error) { + loginUser := vo.LoginUser{} + rows := s.sysLogSourceService.FindByActive(body.State) + if len(rows) != 1 { + return loginUser, fmt.Errorf("oauth2 auth source not exist") + } + item := rows[0] + if item.Config == "" { + return loginUser, fmt.Errorf("oauth2 auth source config is empty") + } + var source systemModelVo.SysLoginSourceOAuth2 + if err := json.Unmarshal([]byte(item.Config), &source); err != nil { + return loginUser, err + } + + // 校验OAuth2用户 + account, err := oauth2Auth(source, body.Code) + if err != nil { + return loginUser, err + } + + // 查询用户登录账号 + sysUser := s.sysUserService.FindByUserName(account, item.Type, item.UID) + if sysUser.UserID == "" || sysUser.UserName == "" { + sysUser = s.initLoginSourceUser(item.UID, item.Type, account, account) + } + if sysUser.UserID == "" || sysUser.UserName != account { + return loginUser, fmt.Errorf("login.errNameOrPasswd") + } + if sysUser.DelFlag == common.STATUS_YES { + // 对不起,您的账号已被删除 + return loginUser, fmt.Errorf("login.errDelFlag") + } + if sysUser.Status == common.STATUS_NO { + return loginUser, fmt.Errorf("login.errStatus") + } + + // 登录用户信息 + loginUser.UserID = sysUser.UserID + loginUser.DeptID = sysUser.DeptID + loginUser.User = sysUser + // 用户权限组标识 + isAdmin := config.IsAdmin(sysUser.UserID) + if isAdmin { + loginUser.Permissions = []string{adminConstants.PERMISSION} + } else { + perms := s.sysMenuService.SelectMenuPermsByUserId(sysUser.UserID) + loginUser.Permissions = parse.RemoveDuplicates(perms) + } + return loginUser, nil +} + +// oauth2Auth 校验OAuth2用户 +func oauth2Auth(source systemModelVo.SysLoginSourceOAuth2, code string) (string, error) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + conf := oauth2.Config{ + ClientID: source.ClientID, + ClientSecret: source.ClientSecret, + RedirectURL: source.RedirectURL, + Scopes: source.Scopes, + Endpoint: oauth2.Endpoint{ + AuthURL: source.AuthURL, + TokenURL: source.TokenURL, + }, + } + token, err := conf.Exchange(ctx, code) + if err != nil { + return "", err + } + // 使用token创建HTTP客户端 请求用户信息 + resp, err := conf.Client(ctx, token).Get(source.UserURL) + if err != nil { + return "", err + } + defer resp.Body.Close() + // 解析用户信息 + var userInfo map[string]any + if err := json.NewDecoder(resp.Body).Decode(&userInfo); err != nil { + return "", err + } + + // 读取嵌套数据 + value, found := getValueByPath(userInfo, source.AccountField) + if !found { + return "", fmt.Errorf("oauth2 auth source account field not exist") + } + return fmt.Sprintf("%v", value), nil +} + +// getValueByPath 从嵌套的 map[string]any 获取嵌套键对应的值 +func getValueByPath(data map[string]any, path string) (any, bool) { + keys := strings.Split(path, ".") // 按照 "." 拆分路径 + return getValue(data, keys) +} + +// getValue 是递归查找嵌套 map 的函数 +func getValue(data map[string]any, keys []string) (any, bool) { + if len(keys) == 0 { + return data, false + } + + // 获取当前键 + key := keys[0] + + // 获取当前键的值 + val, ok := data[key] + if !ok { + return nil, false // 找不到键,返回 false + } + + // 如果还有嵌套键,继续查找 + if len(keys) > 1 { + // 递归查找嵌套 map + if reflect.TypeOf(val).Kind() == reflect.Map { + // 将 `any` 转换为 `map[string]any` 类型 + if nestedMap, ok := val.(map[string]any); ok { + return getValue(nestedMap, keys[1:]) + } + } + } + return val, true +} diff --git a/src/modules/common/service/account_smtp.go b/src/modules/common/service/account_smtp.go new file mode 100644 index 00000000..13e3fda2 --- /dev/null +++ b/src/modules/common/service/account_smtp.go @@ -0,0 +1,91 @@ +package service + +import ( + "context" + "crypto/tls" + "encoding/json" + "fmt" + + "github.com/wneessen/go-mail" + + "be.ems/src/framework/config" + adminConstants "be.ems/src/framework/constants/admin" + "be.ems/src/framework/constants/common" + "be.ems/src/framework/utils/parse" + "be.ems/src/framework/vo" + "be.ems/src/modules/common/model" + systemModelVo "be.ems/src/modules/system/model/vo" +) + +// BySMTP 登录创建用户信息 +func (s *Account) BySMTP(body model.LoginSourceBody) (vo.LoginUser, error) { + loginUser := vo.LoginUser{} + rows := s.sysLogSourceService.FindByActive(body.UID) + if len(rows) != 1 { + return loginUser, fmt.Errorf("smtp auth source not exist") + } + item := rows[0] + if item.Config == "" { + return loginUser, fmt.Errorf("smtp auth source config is empty") + } + var source systemModelVo.SysLoginSourceSMTP + if err := json.Unmarshal([]byte(item.Config), &source); err != nil { + return loginUser, err + } + + // 校验SMTP用户 + err := smtpAuth(source, body.Username, body.Password) + if err != nil { + return loginUser, err + } + + // 查询用户登录账号 + sysUser := s.sysUserService.FindByUserName(body.Username, item.Type, item.UID) + if sysUser.UserID == "" || sysUser.UserName == "" { + sysUser = s.initLoginSourceUser(item.UID, item.Type, body.Username, body.Password) + } + if sysUser.UserID == "" || sysUser.UserName != body.Username { + return loginUser, fmt.Errorf("login.errNameOrPasswd") + } + if sysUser.DelFlag == common.STATUS_YES { + // 对不起,您的账号已被删除 + return loginUser, fmt.Errorf("login.errDelFlag") + } + if sysUser.Status == common.STATUS_NO { + return loginUser, fmt.Errorf("login.errStatus") + } + + // 登录用户信息 + loginUser.UserID = sysUser.UserID + loginUser.DeptID = sysUser.DeptID + loginUser.User = sysUser + // 用户权限组标识 + isAdmin := config.IsAdmin(sysUser.UserID) + if isAdmin { + loginUser.Permissions = []string{adminConstants.PERMISSION} + } else { + perms := s.sysMenuService.SelectMenuPermsByUserId(sysUser.UserID) + loginUser.Permissions = parse.RemoveDuplicates(perms) + } + return loginUser, nil +} + +// smtpAuth 校验SMTP用户 +func smtpAuth(source systemModelVo.SysLoginSourceSMTP, username, password string) error { + client, err := mail.NewClient(source.Host, + mail.WithSMTPAuth(mail.SMTPAuthAutoDiscover), + mail.WithUsername(username), + mail.WithPort(source.Port), + mail.WithPassword(password), + mail.WithTLSConfig(&tls.Config{InsecureSkipVerify: true}), + ) + if err != nil { + return fmt.Errorf("failed to create mail client %s", err) + } + // 连接到邮件SMTP服务器 + if err = client.DialWithContext(context.Background()); err != nil { + return err + } + defer client.Close() + return nil +} diff --git a/src/modules/system/controller/sys_login_source.go b/src/modules/system/controller/sys_login_source.go new file mode 100644 index 00000000..2349af9b --- /dev/null +++ b/src/modules/system/controller/sys_login_source.go @@ -0,0 +1,163 @@ +package controller + +import ( + "encoding/json" + "fmt" + + "github.com/gin-gonic/gin" + + "be.ems/src/framework/i18n" + "be.ems/src/framework/reqctx" + "be.ems/src/framework/resp" + "be.ems/src/framework/utils/parse" + "be.ems/src/modules/system/model" + "be.ems/src/modules/system/service" +) + +// NewLoginSource 实例化控制层 +var NewSysLoginSource = &SysLoginSourceController{ + sysLoginSourceService: service.NewSysLoginSource, +} + +// SysLoginSourceController 认证源管理 控制层处理 +// +// PATH /sys/login-source +type SysLoginSourceController struct { + sysLoginSourceService *service.SysLoginSource // 认证源信息服务 +} + +// List 列表 +// +// GET /list +func (s SysLoginSourceController) List(c *gin.Context) { + query := reqctx.QueryMap(c) + rows, total := s.sysLoginSourceService.FindByPage(query) + c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) +} + +// Info 信息 +// +// GET /:id +func (s SysLoginSourceController) Info(c *gin.Context) { + id := c.Param("id") + if id == "" { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty")) + return + } + + info := s.sysLoginSourceService.FindById(parse.Number(id)) + if info.Id == parse.Number(id) { + c.JSON(200, resp.OkData(info)) + return + } + c.JSON(200, resp.ErrMsg("id does not exist")) +} + +// Add 新增 +// +// POST / +func (s SysLoginSourceController) Add(c *gin.Context) { + var body model.SysLoginSource + if err := c.ShouldBindBodyWithJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + if body.Id > 0 { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id not is empty")) + return + } + if len(body.Config) < 7 || !json.Valid([]byte(body.Config)) { + c.JSON(200, resp.ErrMsg("config json format error")) + return + } + configStr, err := s.sysLoginSourceService.CheckConfigJSON(body.Type, body.Config) + if err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + body.Config = configStr + + body.CreateBy = reqctx.LoginUserToUserName(c) + insertId := s.sysLoginSourceService.Insert(body) + if insertId > 0 { + c.JSON(200, resp.OkData(insertId)) + return + } + c.JSON(200, resp.Err(nil)) +} + +// Edit 更新 +// +// PUT / +func (s SysLoginSourceController) Edit(c *gin.Context) { + var body model.SysLoginSource + if err := c.ShouldBindBodyWithJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + if body.Id <= 0 { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty")) + return + } + if len(body.Config) < 7 || !json.Valid([]byte(body.Config)) { + c.JSON(200, resp.ErrMsg("config json format error")) + return + } + configStr, err := s.sysLoginSourceService.CheckConfigJSON(body.Type, body.Config) + if err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + body.Config = configStr + + // 查询信息 + info := s.sysLoginSourceService.FindById(body.Id) + if info.Id != body.Id { + c.JSON(200, resp.ErrMsg("modification failed, data not exist")) + return + } + + info.Type = body.Type + info.Name = body.Name + info.Icon = body.Icon + info.Config = body.Config + info.ActiveFlag = body.ActiveFlag + info.Remark = body.Remark + info.UpdateBy = reqctx.LoginUserToUserName(c) + rowsAffected := s.sysLoginSourceService.Update(info) + if rowsAffected > 0 { + c.JSON(200, resp.Ok(nil)) + return + } + c.JSON(200, resp.Err(nil)) +} + +// Remove 删除 +// +// DELETE /:id +func (s SysLoginSourceController) Remove(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + id := c.Param("id") + if id == "" { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty")) + return + } + + // 处理字符转id数组后去重 + uniqueIDs := parse.RemoveDuplicatesToArray(id, ",") + // 转换成int64数组类型 + ids := make([]int64, 0) + for _, v := range uniqueIDs { + ids = append(ids, parse.Number(v)) + } + + rows, err := s.sysLoginSourceService.DeleteByIds(ids) + if err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows}) + c.JSON(200, resp.OkMsg(msg)) +} diff --git a/src/modules/system/controller/sys_profile.go b/src/modules/system/controller/sys_profile.go index 5c414e52..1cf253e7 100644 --- a/src/modules/system/controller/sys_profile.go +++ b/src/modules/system/controller/sys_profile.go @@ -181,7 +181,7 @@ func (s *SysProfileController) UpdateProfile(c *gin.Context) { rows := s.sysUserService.UpdateUser(sysUser) if rows > 0 { // 更新缓存用户信息 - loginUser.User = s.sysUserService.SelectUserByUserName(userName) + loginUser.User = s.sysUserService.FindByUserName(userName, "System", "#") // 用户权限组标识 isAdmin := config.IsAdmin(sysUser.UserID) if isAdmin { @@ -323,7 +323,7 @@ func (s *SysProfileController) Avatar(c *gin.Context) { rows := s.sysUserService.UpdateUser(sysUser) if rows > 0 { // 更新缓存用户信息 - loginUser.User = s.sysUserService.SelectUserByUserName(loginUser.User.UserName) + loginUser.User = s.sysUserService.FindByUserName(loginUser.User.UserName, "System", "#") // 用户权限组标识 isAdmin := config.IsAdmin(sysUser.UserID) if isAdmin { diff --git a/src/modules/system/controller/sys_user.go b/src/modules/system/controller/sys_user.go index b546bb38..6ff2ae39 100644 --- a/src/modules/system/controller/sys_user.go +++ b/src/modules/system/controller/sys_user.go @@ -526,9 +526,10 @@ func (s *SysUserController) Export(c *gin.Context) { "C1": i18n.TKey(language, "user.export.nick"), "D1": i18n.TKey(language, "user.export.role"), "E1": i18n.TKey(language, "user.export.deptName"), - "F1": i18n.TKey(language, "user.export.loginIP"), - "G1": i18n.TKey(language, "user.export.loginDate"), - "H1": i18n.TKey(language, "user.export.status"), + "F1": i18n.TKey(language, "user.export.userType"), + "G1": i18n.TKey(language, "user.export.loginIP"), + "H1": i18n.TKey(language, "user.export.loginDate"), + "I1": i18n.TKey(language, "user.export.status"), // "F1": i18n.TKey(language, "user.export.sex"), // "E1": i18n.TKey(language, "user.export.phone"), // "D1": i18n.TKey(language, "user.export.email"), @@ -536,6 +537,8 @@ func (s *SysUserController) Export(c *gin.Context) { // "K1": i18n.TKey(language, "user.export.deptLeader"), } // 读取用户性别字典数据 + dictSysUserType := s.sysDictDataService.SelectDictDataByType("sys_user_type") + // 读取用户性别字典数据 // dictSysUserSex := s.sysDictDataService.SelectDictDataByType("sys_user_sex") // 从第二行开始的数据 dataCells := make([]map[string]any, 0) @@ -549,6 +552,14 @@ func (s *SysUserController) Export(c *gin.Context) { // break // } // } + // 用户类型 + userType := row.UserType + for _, v := range dictSysUserType { + if row.UserType == v.DictValue && row.UserSource != "#" { + userType = i18n.TKey(language, v.DictLabel) + " " + row.UserSource + break + } + } // 帐号状态 statusValue := i18n.TKey(language, "dictData.disable") if row.Status == "1" { @@ -557,7 +568,11 @@ func (s *SysUserController) Export(c *gin.Context) { // 用户角色, 默认导出首个 userRole := "" if len(row.Roles) > 0 { - userRole = i18n.TKey(language, row.Roles[0].RoleName) + arr := make([]string, 0) + for _, v := range row.Roles { + arr = append(arr, i18n.TKey(language, v.RoleName)) + } + userRole = strings.Join(arr, ",") } dataCells = append(dataCells, map[string]any{ "A" + idx: row.UserID, @@ -565,9 +580,10 @@ func (s *SysUserController) Export(c *gin.Context) { "C" + idx: row.NickName, "D" + idx: userRole, "E" + idx: row.Dept.DeptName, - "F" + idx: row.LoginIP, - "G" + idx: date.ParseDateToStr(row.LoginDate, date.YYYY_MM_DD_HH_MM_SS), - "H" + idx: statusValue, + "F" + idx: userType, + "G" + idx: row.LoginIP, + "H" + idx: date.ParseDateToStr(row.LoginDate, date.YYYY_MM_DD_HH_MM_SS), + "I" + idx: statusValue, // "E" + idx: row.PhoneNumber, // "F" + idx: sysUserSex, // "D" + idx: row.Email, @@ -752,7 +768,7 @@ func (s *SysUserController) ImportData(c *gin.Context) { } // 验证是否存在这个用户 - userInfo := s.sysUserService.SelectUserByUserName(newSysUser.UserName) + userInfo := s.sysUserService.FindByUserName(newSysUser.UserName, "System", "#") if userInfo.UserName != newSysUser.UserName { newSysUser.CreateBy = operName insertId := s.sysUserService.InsertUser(newSysUser) diff --git a/src/modules/system/model/sys_login_source.go b/src/modules/system/model/sys_login_source.go new file mode 100644 index 00000000..6f62dedb --- /dev/null +++ b/src/modules/system/model/sys_login_source.go @@ -0,0 +1,22 @@ +package model + +// SysLoginSource 系统第三方认证源 sys_login_source +type SysLoginSource struct { + Id int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"` // ID + UID string `gorm:"column:uid" json:"uid"` // UID 16位长度字符串 + Type string `gorm:"column:type" json:"type" binding:"required,oneof=LDAP SMTP OAuth2"` // 认证类型 LDAP SMTP OAuth2 + Name string `gorm:"column:name" json:"name" binding:"required"` // 认证名称 + Icon string `gorm:"column:icon" json:"icon"` // 图标 + ActiveFlag string `gorm:"column:active_flag" json:"activeFlag"` // 激活标记(0未激活 1激活) + SyncFlag string `gorm:"column:sync_flag" json:"syncFlag"` // 同步标记(0未同步 1同步) + Config string `gorm:"column:config" json:"config" binding:"required"` // 配置JSON字符串 + CreateBy string `gorm:"column:create_by" json:"createBy"` // 创建者 + CreateTime int64 `gorm:"column:create_time" json:"createTime"` // 创建时间 + UpdateBy string `gorm:"column:update_by" json:"updateBy"` // 更新者 + UpdateTime int64 `gorm:"column:update_time" json:"updateTime"` // 更新时间 + Remark string `gorm:"column:remark" json:"remark"` // 备注 +} + +func (*SysLoginSource) TableName() string { + return "sys_login_source" +} diff --git a/src/modules/system/model/sys_user.go b/src/modules/system/model/sys_user.go index 4f1464a8..48ce2707 100644 --- a/src/modules/system/model/sys_user.go +++ b/src/modules/system/model/sys_user.go @@ -3,58 +3,64 @@ package model // SysUser 用户对象 sys_user type SysUser struct { // 用户ID - UserID string `json:"userId"` + UserID string `json:"userId" gorm:"column:user_id;type:bigint;primaryKey"` // 部门ID - DeptID string `json:"deptId"` + DeptID string `json:"deptId" gorm:"column:dept_id"` // 租户ID - TenantID string `json:"tenantId"` + TenantID string `json:"tenantId" gorm:"column:tenant_id"` // 用户账号 - UserName string `json:"userName" binding:"required"` + UserName string `json:"userName" binding:"required" gorm:"column:user_name"` // 用户昵称 - NickName string `json:"nickName" binding:"required"` - // 用户类型(sys系统用户) - UserType string `json:"userType"` + NickName string `json:"nickName" binding:"required" gorm:"column:nick_name"` + // 用户类型(System系统用户) + UserType string `json:"userType" gorm:"column:user_type"` + UserSource string `json:"userSource" gorm:"column:user_source"` // 用户来源UID (系统#)) // 用户邮箱 - Email string `json:"email"` + Email string `json:"email" gorm:"column:email"` // 手机号码 - PhoneNumber string `json:"phonenumber"` + PhoneNumber string `json:"phonenumber" gorm:"column:phonenumber"` // 用户性别(0未知 1男 2女) - Sex string `json:"sex"` + Sex string `json:"sex" gorm:"column:sex"` // 头像地址 - Avatar string `json:"avatar"` + Avatar string `json:"avatar" gorm:"column:avatar"` // 密码 - Password string `json:"-"` + Password string `json:"-" gorm:"column:password"` // 帐号状态(0停用 1正常) - Status string `json:"status"` + Status string `json:"status" gorm:"column:status"` // 删除标志(0代表存在 1代表删除) - DelFlag string `json:"delFlag"` + DelFlag string `json:"delFlag" gorm:"column:del_flag"` // 最后登录IP - LoginIP string `json:"loginIp"` + LoginIP string `json:"loginIp" gorm:"column:login_ip"` // 最后登录时间 - LoginDate int64 `json:"loginDate"` + LoginDate int64 `json:"loginDate" gorm:"column:login_date"` // 创建者 - CreateBy string `json:"createBy"` + CreateBy string `json:"createBy" gorm:"column:create_by"` // 创建时间 - CreateTime int64 `json:"createTime"` + CreateTime int64 `json:"createTime" gorm:"column:create_time"` // 更新者 - UpdateBy string `json:"updateBy"` + UpdateBy string `json:"updateBy" gorm:"column:update_by"` // 更新时间 - UpdateTime int64 `json:"updateTime"` + UpdateTime int64 `json:"updateTime" gorm:"column:update_time"` // 备注 - Remark string `json:"remark"` + Remark string `json:"remark" gorm:"column:remark"` // ====== 非数据库字段属性 ====== // 部门对象 - Dept SysDept `json:"dept,omitempty" binding:"structonly"` + Dept SysDept `json:"dept,omitempty" binding:"structonly" gorm:"-"` // 租户对象 - Tenant SysTenant `json:"tenant,omitempty" binding:"structonly"` + Tenant SysTenant `json:"tenant,omitempty" binding:"structonly" gorm:"-"` // 角色对象组 - Roles []SysRole `json:"roles"` + Roles []SysRole `json:"roles" gorm:"-"` // 角色ID - RoleID string `json:"roleId,omitempty"` + RoleID string `json:"roleId,omitempty" gorm:"-"` // 角色组 - RoleIDs []string `json:"roleIds,omitempty"` + RoleIDs []string `json:"roleIds,omitempty" gorm:"-"` // 岗位组 - PostIDs []string `json:"postIds,omitempty"` + PostIDs []string `json:"postIds,omitempty" gorm:"-"` +} + +// TableName 表名称 +func (*SysUser) TableName() string { + return "sys_user" } diff --git a/src/modules/system/model/vo/login_source.go b/src/modules/system/model/vo/login_source.go new file mode 100644 index 00000000..5f401d6e --- /dev/null +++ b/src/modules/system/model/vo/login_source.go @@ -0,0 +1,28 @@ +package vo + +// SysLoginSourceLDAP LDAP认证源 +type SysLoginSourceLDAP struct { + URL string `json:"url"` // LDAP 服务器(ldap://192.168.9.58:11389) + BaseDN string `json:"baseDN"` // base DN(dc=example,dc=org) + UserFilter string `json:"userFilter"` // 用户过滤规则((&(objectClass=organizationalPerson)(uid=%s))) + BindDN string `json:"bindDN"` // 绑定 DN(cn=admin,dc=example,dc=org) + BindPassword string `json:"bindPassword"` // 绑定密码(adminpassword) +} + +// SysLoginSourceSMTP SMTP认证源 +type SysLoginSourceSMTP struct { + Host string `json:"host"` // SMTP 服务器(smtp.gmail.com) + Port int `json:"port"` // SMTP 端口(587) +} + +// SysLoginSourceOAuth2 OAuth2认证源 +type SysLoginSourceOAuth2 struct { + ClientID string `json:"clientID"` // 客户端ID + ClientSecret string `json:"clientSecret"` // 客户端密钥 + AuthURL string `json:"authURL"` // 认证URL + TokenURL string `json:"tokenURL"` // 令牌URL + Scopes []string `json:"scopes"` // 授权范围 + RedirectURL string `json:"redirectURL"` // 重定向URL + UserURL string `json:"userURL"` // 用户信息URL + AccountField string `json:"accountField"` // 账号字段从用户信息中获取 +} diff --git a/src/modules/system/repository/sys_dept.go b/src/modules/system/repository/sys_dept.go index 99b4aead..db7b69f1 100644 --- a/src/modules/system/repository/sys_dept.go +++ b/src/modules/system/repository/sys_dept.go @@ -39,4 +39,7 @@ type ISysDept interface { // DeleteDeptById 删除部门管理信息 DeleteDeptById(deptId string) int64 + + // SelectById 通过ID查询信息 + SelectById(deptId string) model.SysDept } diff --git a/src/modules/system/repository/sys_dept.impl.go b/src/modules/system/repository/sys_dept.impl.go index 62ec2d26..31fd09fa 100644 --- a/src/modules/system/repository/sys_dept.impl.go +++ b/src/modules/system/repository/sys_dept.impl.go @@ -391,3 +391,25 @@ func (r *SysDeptImpl) DeleteDeptById(deptId string) int64 { } return results } + +// SelectById 通过ID查询信息 +func (r *SysDeptImpl) SelectById(deptId string) model.SysDept { + if deptId == "" { + return model.SysDept{} + } + querySql := `select d.dept_id, d.parent_id, d.ancestors, + d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, + (select dept_name from sys_dept where dept_id = d.parent_id) parent_name + from sys_dept d where d.dept_id = ?` + results, err := datasource.RawDB("", querySql, []any{deptId}) + if err != nil { + logger.Errorf("query err => %v", err) + return model.SysDept{} + } + // 转换实体 + rows := r.convertResultRows(results) + if len(rows) > 0 { + return rows[0] + } + return model.SysDept{} +} diff --git a/src/modules/system/repository/sys_login_source.go b/src/modules/system/repository/sys_login_source.go new file mode 100644 index 00000000..c9170f8b --- /dev/null +++ b/src/modules/system/repository/sys_login_source.go @@ -0,0 +1,150 @@ +package repository + +import ( + "fmt" + "time" + + "be.ems/src/framework/database/db" + "be.ems/src/framework/logger" + "be.ems/src/modules/system/model" +) + +// NewSysLoginSource 实例化数据层 +var NewSysLoginSource = &SysLoginSource{} + +// SysLoginSource 认证源数据层处理 +type SysLoginSource struct{} + +// SelectByPage 分页查询集合 +func (r SysLoginSource) SelectByPage(query map[string]string) ([]model.SysLoginSource, int64) { + tx := db.DB("").Model(&model.SysLoginSource{}) + // 查询条件拼接 + if v, ok := query["name"]; ok && v != "" { + tx = tx.Where("name like ?", v+"%") + } + if v, ok := query["type"]; ok && v != "" { + tx = tx.Where("type = ?", v) + } + if v, ok := query["beginTime"]; ok && v != "" { + if len(v) == 10 { + v = fmt.Sprintf("%s000", v) + } + tx = tx.Where("create_time >= ?", v) + } + if v, ok := query["endTime"]; ok && v != "" { + if len(v) == 10 { + v = fmt.Sprintf("%s999", v) + } + tx = tx.Where("create_time <= ?", v) + } + + // 查询结果 + var total int64 = 0 + rows := []model.SysLoginSource{} + + // 查询数量为0直接返回 + if err := tx.Count(&total).Error; err != nil || total <= 0 { + return rows, total + } + + // 查询数据分页 + pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"]) + tx = tx.Limit(pageSize).Offset(pageSize * pageNum) + err := tx.Find(&rows).Error + if err != nil { + return rows, total + } + return rows, total +} + +// Select 查询集合 +func (r SysLoginSource) Select(param model.SysLoginSource) []model.SysLoginSource { + tx := db.DB("").Model(&model.SysLoginSource{}) + // 查询条件拼接 + if param.UID != "" { + tx = tx.Where("uid = ?", param.UID) + } + if param.Type != "" { + tx = tx.Where("type = ?", param.Type) + } + if param.Name != "" { + tx = tx.Where("name = ?", param.Name) + } + if param.ActiveFlag != "" { + tx = tx.Where("active_flag = ?", param.ActiveFlag) + } + + // 查询数据 + rows := []model.SysLoginSource{} + if err := tx.Find(&rows).Error; err != nil { + return rows + } + return rows +} + +// SelectByIds 通过ID查询信息 +func (r SysLoginSource) SelectByIds(ids []int64) []model.SysLoginSource { + rows := []model.SysLoginSource{} + if len(ids) <= 0 { + return rows + } + tx := db.DB("").Model(&model.SysLoginSource{}) + // 构建查询条件 + tx = tx.Where("id in ?", ids) + // 查询数据 + if err := tx.Find(&rows).Error; err != nil { + logger.Errorf("query find err => %v", err.Error()) + return rows + } + return rows +} + +// Insert 新增信息 返回新增数据ID +func (r SysLoginSource) Insert(param model.SysLoginSource) int64 { + if param.CreateBy != "" { + ms := time.Now().UnixMilli() + param.UpdateBy = param.CreateBy + param.UpdateTime = ms + param.CreateTime = ms + } + // 执行插入 + if err := db.DB("").Create(¶m).Error; err != nil { + logger.Errorf("insert err => %v", err.Error()) + return 0 + } + return param.Id +} + +// Update 修改信息 返回受影响行数 +func (r SysLoginSource) Update(param model.SysLoginSource) int64 { + if param.Id <= 0 { + return 0 + } + if param.UpdateBy != "" { + param.UpdateTime = time.Now().UnixMilli() + } + tx := db.DB("").Model(&model.SysLoginSource{}) + // 构建查询条件 + tx = tx.Where("id = ?", param.Id) + tx = tx.Omit("id", "create_by", "create_time") + // 执行更新 + if err := tx.Updates(param).Error; err != nil { + logger.Errorf("update err => %v", err.Error()) + return 0 + } + return tx.RowsAffected +} + +// DeleteByIds 批量删除信息 返回受影响行数 +func (r SysLoginSource) DeleteByIds(ids []int64) int64 { + if len(ids) <= 0 { + return 0 + } + tx := db.DB("").Where("id in ?", ids) + // 执行删除 + if err := tx.Delete(&model.SysLoginSource{}).Error; err != nil { + logger.Errorf("delete err => %v", err.Error()) + return 0 + } + return tx.RowsAffected +} diff --git a/src/modules/system/repository/sys_role.go b/src/modules/system/repository/sys_role.go index 85fd822f..8735471b 100644 --- a/src/modules/system/repository/sys_role.go +++ b/src/modules/system/repository/sys_role.go @@ -27,4 +27,7 @@ type ISysRole interface { // CheckUniqueRole 校验角色是否唯一 CheckUniqueRole(sysRole model.SysRole) string + + // SelectByUserId 根据用户ID获取角色信息 + SelectByUserId(userId string) []model.SysRole } diff --git a/src/modules/system/repository/sys_role.impl.go b/src/modules/system/repository/sys_role.impl.go index 8fe89fa3..e9d216b3 100644 --- a/src/modules/system/repository/sys_role.impl.go +++ b/src/modules/system/repository/sys_role.impl.go @@ -373,3 +373,14 @@ func (r *SysRoleImpl) CheckUniqueRole(sysRole model.SysRole) string { } return "" } + +// SelectByUserId 根据用户ID获取角色信息 +func (r *SysRoleImpl) SelectByUserId(userId string) []model.SysRole { + querySql := r.selectSql + " where r.del_flag = '0' and ur.user_id = ?" + results, err := datasource.RawDB("", querySql, []any{userId}) + if err != nil { + logger.Errorf("query err => %v", err) + return []model.SysRole{} + } + return r.convertResultRows(results) +} diff --git a/src/modules/system/repository/sys_user.go b/src/modules/system/repository/sys_user.go index cb45da28..fe7170b3 100644 --- a/src/modules/system/repository/sys_user.go +++ b/src/modules/system/repository/sys_user.go @@ -30,4 +30,7 @@ type ISysUser interface { // CheckUniqueUser 校验用户信息是否唯一 CheckUniqueUser(sysUser model.SysUser) string + + // SelectByUserName 通过登录账号查询信息 + SelectByUserName(userName, userType, userSource string) model.SysUser } diff --git a/src/modules/system/repository/sys_user.impl.go b/src/modules/system/repository/sys_user.impl.go index 02b2eb40..8c301743 100644 --- a/src/modules/system/repository/sys_user.impl.go +++ b/src/modules/system/repository/sys_user.impl.go @@ -16,7 +16,7 @@ import ( // 实例化数据层 SysUserImpl 结构体 var NewSysUserImpl = &SysUserImpl{ selectSql: `select - u.user_id, u.dept_id, u.tenant_id, u.user_name, u.nick_name, u.user_type, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, + u.user_id, u.dept_id, u.tenant_id, u.user_name, u.nick_name, u.user_type, u.user_source, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status, t.tenant_id, t.parent_id, t.ancestors, t.tenant_name, t.order_num, t.tenancy_type, t.tenancy_key, t.status as tenant_status, r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status @@ -33,6 +33,7 @@ var NewSysUserImpl = &SysUserImpl{ "user_name": "UserName", "nick_name": "NickName", "user_type": "UserType", + "user_source": "UserSource", "email": "Email", "phonenumber": "PhoneNumber", "sex": "Sex", @@ -171,6 +172,14 @@ func (r *SysUserImpl) SelectUserPage(query map[string]any, dataScopeSQL string) conditions = append(conditions, "u.phonenumber like concat(?, '%')") params = append(params, v) } + if v, ok := query["userType"]; ok && v != "" { + conditions = append(conditions, "u.user_type = ?") + params = append(params, v) + } + if v, ok := query["userSource"]; ok && v != "" { + conditions = append(conditions, "u.user_source = ?") + params = append(params, v) + } beginTime, ok := query["beginTime"] if !ok { beginTime, ok = query["params[beginTime]"] @@ -398,6 +407,32 @@ func (r *SysUserImpl) SelectUserByIds(userIds []string) []model.SysUser { return r.convertResultRows(results) } +// SelectByUserName 通过登录账号查询信息 +func (r *SysUserImpl) SelectByUserName(userName, userType, userSource string) model.SysUser { + item := model.SysUser{} + if userName == "" { + return item + } + if userType == "" { + userType = "System" + } + if userSource == "" { + userSource = "#" + } + querySql := r.selectSql + " where u.del_flag = '0' and u.user_name = ? and u.user_type = ? and u.user_source = ?" + results, err := datasource.RawDB("", querySql, []any{userName, userType, userSource}) + if err != nil { + logger.Errorf("query err => %v", err) + return model.SysUser{} + } + // 转换实体 + rows := r.convertResultRows(results) + if len(rows) > 0 { + return rows[0] + } + return item +} + // SelectUserByUserName 通过用户登录账号查询用户 func (r *SysUserImpl) SelectUserByUserName(userName string) model.SysUser { querySql := r.selectSql + " where u.del_flag = '0' and u.user_name = ?" @@ -436,6 +471,9 @@ func (r *SysUserImpl) InsertUser(sysUser model.SysUser) string { if sysUser.UserType != "" { params["user_type"] = sysUser.UserType } + if sysUser.UserSource != "" { + params["user_source"] = sysUser.UserSource + } if sysUser.Avatar != "" { params["avatar"] = sysUser.Avatar } @@ -509,6 +547,9 @@ func (r *SysUserImpl) UpdateUser(sysUser model.SysUser) int64 { if sysUser.UserType != "" { params["user_type"] = sysUser.UserType } + if sysUser.UserSource != "" { + params["user_source"] = sysUser.UserSource + } if sysUser.Avatar != "" { params["avatar"] = sysUser.Avatar } @@ -582,6 +623,14 @@ func (r *SysUserImpl) CheckUniqueUser(sysUser model.SysUser) string { conditions = append(conditions, "email = ?") params = append(params, sysUser.Email) } + if sysUser.UserType != "" { + conditions = append(conditions, "user_type = ?") + params = append(params, sysUser.UserType) + } + if sysUser.UserSource != "" { + conditions = append(conditions, "user_source = ?") + params = append(params, sysUser.UserSource) + } // 构建查询条件语句 whereSql := "" diff --git a/src/modules/system/service/sys_login_source.go b/src/modules/system/service/sys_login_source.go new file mode 100644 index 00000000..b6a9b949 --- /dev/null +++ b/src/modules/system/service/sys_login_source.go @@ -0,0 +1,95 @@ +package service + +import ( + "encoding/json" + "fmt" + + "be.ems/src/framework/utils/generate" + "be.ems/src/modules/system/model" + "be.ems/src/modules/system/model/vo" + "be.ems/src/modules/system/repository" +) + +// NewSysLoginSource 实例化服务层 +var NewSysLoginSource = &SysLoginSource{ + sysLoginSourceRepository: repository.NewSysLoginSource, +} + +// SysLoginSource 认证源 服务层处理 +type SysLoginSource struct { + sysLoginSourceRepository *repository.SysLoginSource // 认证源表 +} + +// FindByPage 分页查询 +func (s SysLoginSource) FindByPage(query map[string]string) ([]model.SysLoginSource, int64) { + return s.sysLoginSourceRepository.SelectByPage(query) +} + +// FindById 查询ID +func (s SysLoginSource) FindById(id int64) model.SysLoginSource { + rows := s.sysLoginSourceRepository.SelectByIds([]int64{id}) + if len(rows) > 0 { + return rows[0] + } + return model.SysLoginSource{} +} + +// Insert 新增 +func (s SysLoginSource) Insert(param model.SysLoginSource) int64 { + param.UID = generate.Code(8) + return s.sysLoginSourceRepository.Insert(param) +} + +// Update 更新 +func (s SysLoginSource) Update(param model.SysLoginSource) int64 { + return s.sysLoginSourceRepository.Update(param) +} + +// DeleteByIds 批量删除 +func (s SysLoginSource) DeleteByIds(ids []int64) (int64, error) { + // 检查是否存在 + arr := s.sysLoginSourceRepository.SelectByIds(ids) + if len(arr) <= 0 { + // return 0, fmt.Errorf("没有权限访问认证源数据!") + return 0, fmt.Errorf("no permission to access authentication source data") + } + if len(arr) == len(ids) { + return s.sysLoginSourceRepository.DeleteByIds(ids), nil + } + // return 0, fmt.Errorf("删除认证源信息失败!") + return 0, fmt.Errorf("failed to delete authentication source information") +} + +// FindByActive 查询激活 +func (s SysLoginSource) FindByActive(uid string) []model.SysLoginSource { + param := model.SysLoginSource{ + ActiveFlag: "1", + } + if uid != "" { + param.UID = uid + } + return s.sysLoginSourceRepository.Select(param) +} + +// CheckConfigJSON 检查配置JSON +func (s SysLoginSource) CheckConfigJSON(sType, sConfig string) (string, error) { + var source any + switch sType { + case "LDAP": + source = new(vo.SysLoginSourceLDAP) + case "SMTP": + source = new(vo.SysLoginSourceSMTP) + case "OAuth2": + source = new(vo.SysLoginSourceOAuth2) + default: + return "", fmt.Errorf("unsupported login source type: %s", sType) + } + if err := json.Unmarshal([]byte(sConfig), &source); err != nil { + return "", fmt.Errorf("config json format error for %s type: %s", sType, err.Error()) + } + configByte, err := json.Marshal(source) + if err != nil { + return "", fmt.Errorf("config json format error") + } + return string(configByte), nil +} diff --git a/src/modules/system/service/sys_user.go b/src/modules/system/service/sys_user.go index 7c149ea1..e89dba63 100644 --- a/src/modules/system/service/sys_user.go +++ b/src/modules/system/service/sys_user.go @@ -13,6 +13,11 @@ type ISysUser interface { // SelectAllocatedPage 根据条件分页查询分配用户角色列表 SelectAllocatedPage(query map[string]any, dataScopeSQL string) map[string]any + // FindByUserName 通过用户名查询用户信息 + // userType 系统sys + // userSource 系统# + FindByUserName(userName, userType, userSource string) model.SysUser + // SelectUserByUserName 通过用户名查询用户 SelectUserByUserName(userName string) model.SysUser diff --git a/src/modules/system/service/sys_user.impl.go b/src/modules/system/service/sys_user.impl.go index 8f1baf2e..622bd582 100644 --- a/src/modules/system/service/sys_user.impl.go +++ b/src/modules/system/service/sys_user.impl.go @@ -13,6 +13,8 @@ var NewSysUserImpl = &SysUserImpl{ sysUserRepository: repository.NewSysUserImpl, sysUserRoleRepository: repository.NewSysUserRoleImpl, sysUserPostRepository: repository.NewSysUserPostImpl, + sysDeptRepository: repository.NewSysDeptImpl, + sysRoleRepository: repository.NewSysRoleImpl, } // SysUserImpl 用户 服务层处理 @@ -23,6 +25,10 @@ type SysUserImpl struct { sysUserRoleRepository repository.ISysUserRole // 用户与岗位服务 sysUserPostRepository repository.ISysUserPost + // 部门服务 + sysDeptRepository repository.ISysDept + // 角色服务 + sysRoleRepository repository.ISysRole } // SelectUserPage 根据条件分页查询用户列表 @@ -40,6 +46,30 @@ func (r *SysUserImpl) SelectAllocatedPage(query map[string]any, dataScopeSQL str return r.sysUserRepository.SelectAllocatedPage(query, dataScopeSQL) } +// FindByUserName 通过用户名查询用户信息 +// userType 系统sys +// userSource 系统# +func (s SysUserImpl) FindByUserName(userName, userType, userSource string) model.SysUser { + userinfo := s.sysUserRepository.SelectByUserName(userName, userType, userSource) + if userinfo.UserName != userName { + return userinfo + } + // 部门 + deptInfo := s.sysDeptRepository.SelectById(userinfo.DeptID) + userinfo.Dept = deptInfo + // 角色 + roleArr := s.sysRoleRepository.SelectByUserId(userinfo.UserID) + roles := make([]model.SysRole, 0) + roleIds := make([]string, 0) + for _, role := range roleArr { + roles = append(roles, role) + roleIds = append(roleIds, role.RoleID) + } + userinfo.Roles = roles + userinfo.RoleIDs = roleIds + return userinfo +} + // SelectUserByUserName 通过用户名查询用户 func (r *SysUserImpl) SelectUserByUserName(userName string) model.SysUser { return r.sysUserRepository.SelectUserByUserName(userName) @@ -147,7 +177,9 @@ func (r *SysUserImpl) DeleteUserByIds(userIds []string) (int64, error) { // CheckUniqueUserName 校验用户名称是否唯一 func (r *SysUserImpl) CheckUniqueUserName(userName, userId string) bool { uniqueId := r.sysUserRepository.CheckUniqueUser(model.SysUser{ - UserName: userName, + UserName: userName, + UserType: "System", + UserSource: "#", }) if uniqueId == userId { return true @@ -159,6 +191,8 @@ func (r *SysUserImpl) CheckUniqueUserName(userName, userId string) bool { func (r *SysUserImpl) CheckUniquePhone(phonenumber, userId string) bool { uniqueId := r.sysUserRepository.CheckUniqueUser(model.SysUser{ PhoneNumber: phonenumber, + UserType: "System", + UserSource: "#", }) if uniqueId == userId { return true @@ -169,7 +203,9 @@ func (r *SysUserImpl) CheckUniquePhone(phonenumber, userId string) bool { // CheckUniqueEmail 校验email是否唯一 func (r *SysUserImpl) CheckUniqueEmail(email, userId string) bool { uniqueId := r.sysUserRepository.CheckUniqueUser(model.SysUser{ - Email: email, + Email: email, + UserType: "System", + UserSource: "#", }) if uniqueId == userId { return true diff --git a/src/modules/system/system.go b/src/modules/system/system.go index 85f070ee..a74a00ec 100644 --- a/src/modules/system/system.go +++ b/src/modules/system/system.go @@ -472,6 +472,35 @@ func Setup(router *gin.Engine) { controller.NewSysLogLogin.Export, ) } + + // 第三方认证-配置认证源 + sysLoginSource := controller.NewSysLoginSource + sysLoginSourceGroup := router.Group("/system/login-source") + { + sysLoginSourceGroup.GET("/list", + middleware.PreAuthorize(map[string][]string{"hasRoles": {"admin"}, "hasPerms": {"system:loginSource:list"}}), + sysLoginSource.List, + ) + sysLoginSourceGroup.GET("/:id", + middleware.PreAuthorize(map[string][]string{"hasRoles": {"admin"}, "hasPerms": {"system:loginSource:query"}}), + sysLoginSource.Info, + ) + sysLoginSourceGroup.POST("", + middleware.PreAuthorize(map[string][]string{"hasRoles": {"admin"}, "hasPerms": {"system:loginSource:add"}}), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sysLoginSource", collectlogs.BUSINESS_TYPE_INSERT)), + sysLoginSource.Add, + ) + sysLoginSourceGroup.PUT("", + middleware.PreAuthorize(map[string][]string{"hasRoles": {"admin"}, "hasPerms": {"system:loginSource:edit"}}), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sysLoginSource", collectlogs.BUSINESS_TYPE_UPDATE)), + sysLoginSource.Edit, + ) + sysLoginSourceGroup.DELETE("/:id", + middleware.PreAuthorize(map[string][]string{"hasRoles": {"admin"}, "hasPerms": {"system:loginSource:remove"}}), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sysLoginSource", collectlogs.BUSINESS_TYPE_DELETE)), + sysLoginSource.Remove, + ) + } } // InitLoad 初始参数