diff --git a/JSD-7508配置使用文档.docx b/JSD-7508配置使用文档.docx
new file mode 100644
index 0000000..2f60c05
Binary files /dev/null and b/JSD-7508配置使用文档.docx differ
diff --git a/JSD-7508需求确认书(对内).docx b/JSD-7508需求确认书(对内).docx
new file mode 100644
index 0000000..c5a68ed
Binary files /dev/null and b/JSD-7508需求确认书(对内).docx differ
diff --git a/README.md b/README.md
index fc268ff..fc1e2c7 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
# open-JSD-7508
-JSD-7508 OAuth2 + 组织&用户同步
\ No newline at end of file
+JSD-7508 OAuth2 + 组织&用户同步\
+免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\
+仅作为开发者学习参考使用!禁止用于任何商业用途!\
+为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系hugh处理。
\ No newline at end of file
diff --git a/lib/finekit-10.0.jar b/lib/finekit-10.0.jar
new file mode 100644
index 0000000..f4482fc
Binary files /dev/null and b/lib/finekit-10.0.jar differ
diff --git a/lib/java-jwt-3.16.0.jar b/lib/java-jwt-3.16.0.jar
new file mode 100644
index 0000000..a4e61fb
Binary files /dev/null and b/lib/java-jwt-3.16.0.jar differ
diff --git a/plugin.xml b/plugin.xml
new file mode 100644
index 0000000..d6d5263
--- /dev/null
+++ b/plugin.xml
@@ -0,0 +1,25 @@
+
+
+ com.fr.plugin.j7508.sso.auth
+
+ yes
+ 1.1.3
+ 10.0
+ 2018-07-31
+ fr.open
+
+
+ com.fr.plugin.j7508.sso
+
+ com.fanruan.api
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/j7508/sso/LocaleFinder.java b/src/main/java/com/fr/plugin/j7508/sso/LocaleFinder.java
new file mode 100644
index 0000000..cadaf9d
--- /dev/null
+++ b/src/main/java/com/fr/plugin/j7508/sso/LocaleFinder.java
@@ -0,0 +1,37 @@
+ /*
+ * Copyright (C), 2018-2020
+ * Project: starter
+ * FileName: LocaleFinder
+ * Author: Louis
+ * Date: 2020/8/31 22:19
+ */
+ package com.fr.plugin.j7508.sso;
+
+ import com.fr.intelli.record.Focus;
+import com.fr.intelli.record.Original;
+import com.fr.record.analyzer.EnableMetrics;
+import com.fr.stable.fun.impl.AbstractLocaleFinder;
+
+import static com.fr.plugin.j7508.sso.config.SsoConfig.PLUGIN_ID;
+
+ /**
+ *
+ *
+ *
+ * @author fr.open
+ * @since 1.0.0
+ */
+ @EnableMetrics
+ public class LocaleFinder extends AbstractLocaleFinder {
+
+ @Override
+ @Focus(id = PLUGIN_ID, text = "Plugin-J7508-Sso", source = Original.PLUGIN)
+ public String find() {
+ return "com/fr/plugin/j7508/sso/locale/lang";
+ }
+
+ @Override
+ public int currentAPILevel() {
+ return CURRENT_LEVEL;
+ }
+ }
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/j7508/sso/PluginMonitor.java b/src/main/java/com/fr/plugin/j7508/sso/PluginMonitor.java
new file mode 100644
index 0000000..9c68190
--- /dev/null
+++ b/src/main/java/com/fr/plugin/j7508/sso/PluginMonitor.java
@@ -0,0 +1,49 @@
+ /*
+ * Copyright (C), 2018-2021
+ * Project: starter
+ * FileName: PluginMonitor
+ * Author: Louis
+ * Date: 2021/3/30 15:10
+ */
+ package com.fr.plugin.j7508.sso;
+
+ import com.fanruan.api.log.LogKit;
+import com.fr.plugin.context.PluginContext;
+import com.fr.plugin.j7508.sso.config.SsoConfig;
+import com.fr.plugin.j7508.sso.helper.SsoUserScheduleHelper;
+import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor;
+
+ import static com.fr.plugin.j7508.sso.helper.SsoUserScheduleHelper.SSO_USER_SCHEDULE_SYN_MEMBER_GROUP;
+ import static com.fr.plugin.j7508.sso.helper.SsoUserScheduleHelper.SSO_USER_SCHEDULE_SYN_MEMBER_JOB_NAME;
+
+ /**
+ *
+ *
+ *
+ * @author fr.open
+ * @since 1.0.0
+ */
+ public class PluginMonitor extends AbstractPluginLifecycleMonitor {
+ public PluginMonitor() {
+ }
+
+ @Override
+ public void afterRun(PluginContext pluginContext) {
+ SsoConfig.getInstance();
+ this.reStartSchedule();
+ }
+
+ @Override
+ public void beforeStop(PluginContext pluginContext) {
+ SsoUserScheduleHelper.getInstance().stopSchedule(SSO_USER_SCHEDULE_SYN_MEMBER_JOB_NAME, SSO_USER_SCHEDULE_SYN_MEMBER_GROUP);
+ }
+
+ private void reStartSchedule() {
+ try {
+ String cronCondition = SsoConfig.getInstance().getCronCondition();
+ SsoUserScheduleHelper.getInstance().startSynMemberSchedule(cronCondition);
+ } catch (Exception e) {
+ LogKit.error(e.getMessage(), e);
+ }
+ }
+ }
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/j7508/sso/bean/DataResponse.java b/src/main/java/com/fr/plugin/j7508/sso/bean/DataResponse.java
new file mode 100644
index 0000000..d360b13
--- /dev/null
+++ b/src/main/java/com/fr/plugin/j7508/sso/bean/DataResponse.java
@@ -0,0 +1,99 @@
+ /*
+ * Copyright (C), 2018-2021
+ * Project: starter
+ * FileName: DataResponse
+ * Author: Louis
+ * Date: 2021/3/19 11:46
+ */
+ package com.fr.plugin.j7508.sso.bean;
+
+ import com.fanruan.api.util.StringKit;
+import com.fr.decision.webservice.Response;
+import com.fr.third.fasterxml.jackson.annotation.JsonInclude;
+
+ /**
+ *
+ *
+ *
+ * @author fr.open
+ * @since 1.0.0
+ */
+ @JsonInclude(JsonInclude.Include.NON_DEFAULT)
+ public class DataResponse extends Response {
+ private static final long serialVersionUID = -6046189959382243612L;
+ private String timestamp;
+ private String code;
+ private String msg;
+
+ public DataResponse() {
+ }
+
+ private static DataResponse create() {
+ return new DataResponse();
+ }
+
+ /**
+ * 相应success结果
+ *
+ * @return
+ */
+ public static DataResponse success() {
+ return create().code("0").timeStamp(String.valueOf(System.currentTimeMillis())).message("success");
+ }
+
+
+ /**
+ * 报错结果
+ *
+ * @param code
+ * @param message
+ * @return
+ */
+ public static DataResponse error(String code, String message) {
+ return create().code(code).message(message).data(StringKit.EMPTY);
+ }
+
+ public DataResponse timeStamp(String timeStamp) {
+ this.timestamp = timeStamp;
+ return this;
+ }
+
+ public DataResponse code(String code) {
+ this.code = code;
+ return this;
+ }
+
+ public DataResponse message(String message) {
+ this.msg = message;
+ return this;
+ }
+
+ public DataResponse data(Object data) {
+ this.setData(data);
+ return this;
+ }
+
+ public String getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(String timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public String getMsg() {
+ return msg;
+ }
+
+ public void setMsg(String msg) {
+ this.msg = msg;
+ }
+ }
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/j7508/sso/bean/SsoUserJobConstructor.java b/src/main/java/com/fr/plugin/j7508/sso/bean/SsoUserJobConstructor.java
new file mode 100644
index 0000000..b483583
--- /dev/null
+++ b/src/main/java/com/fr/plugin/j7508/sso/bean/SsoUserJobConstructor.java
@@ -0,0 +1,107 @@
+ /*
+ * Copyright (C), 2018-2021
+ * Project: starter
+ * FileName: SsoUserJobConstructor
+ * Author: Louis
+ * Date: 2021/4/21 15:58
+ */
+ package com.fr.plugin.j7508.sso.bean;
+
+ import com.fr.scheduler.job.FineScheduleJob;
+
+ /**
+ *
+ *
+ *
+ * @author fr.open
+ * @since 1.0.0
+ */
+ public class SsoUserJobConstructor {
+ private String cron;
+ private String jobName;
+ private String jobGroup;
+ private String triggerName;
+ private String triggerGroup;
+ private Class extends FineScheduleJob> jobClazz;
+
+ public SsoUserJobConstructor() {
+ }
+
+ public SsoUserJobConstructor cron(String var1) {
+ this.setCron(var1);
+ return this;
+ }
+
+ public String getCron() {
+ return this.cron;
+ }
+
+ public void setCron(String var1) {
+ this.cron = var1;
+ }
+
+ public SsoUserJobConstructor jobName(String var1) {
+ this.setJobName(var1);
+ return this;
+ }
+
+ public String getJobName() {
+ return this.jobName;
+ }
+
+ public void setJobName(String var1) {
+ this.jobName = var1;
+ }
+
+ public SsoUserJobConstructor jobGroup(String var1) {
+ this.setJobGroup(var1);
+ return this;
+ }
+
+ public String getJobGroup() {
+ return this.jobGroup;
+ }
+
+ public void setJobGroup(String var1) {
+ this.jobGroup = var1;
+ }
+
+ public SsoUserJobConstructor triggerName(String var1) {
+ this.setTriggerName(var1);
+ return this;
+ }
+
+ public String getTriggerName() {
+ return this.triggerName;
+ }
+
+ public void setTriggerName(String var1) {
+ this.triggerName = var1;
+ }
+
+ public SsoUserJobConstructor triggerGroup(String var1) {
+ this.setTriggerGroup(var1);
+ return this;
+ }
+
+ public String getTriggerGroup() {
+ return this.triggerGroup;
+ }
+
+ public void setTriggerGroup(String var1) {
+ this.triggerGroup = var1;
+ }
+
+ public SsoUserJobConstructor jobClazz(Class extends FineScheduleJob> var1) {
+ this.setJobClazz(var1);
+ return this;
+ }
+
+ public Class extends FineScheduleJob> getJobClazz() {
+ return this.jobClazz;
+ }
+
+ public void setJobClazz(Class extends FineScheduleJob> var1) {
+ this.jobClazz = var1;
+ }
+ }
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/j7508/sso/config/SsoConfig.java b/src/main/java/com/fr/plugin/j7508/sso/config/SsoConfig.java
new file mode 100644
index 0000000..9fb96e2
--- /dev/null
+++ b/src/main/java/com/fr/plugin/j7508/sso/config/SsoConfig.java
@@ -0,0 +1,122 @@
+ /*
+ * Copyright (C), 2018-2021
+ * Project: starter
+ * FileName: OneAccessConfig
+ * Author: Louis
+ * Date: 2021/3/30 9:38
+ */
+ package com.fr.plugin.j7508.sso.config;
+
+ import com.fanruan.api.util.StringKit;
+ import com.fr.config.*;
+import com.fr.config.holder.Conf;
+import com.fr.config.holder.factory.Holders;
+import com.fr.intelli.record.Focus;
+import com.fr.intelli.record.Original;
+
+ /**
+ *
+ *
+ *
+ * @author fr.open
+ * @since 1.0.0
+ */
+ @Visualization(category = "Plugin-J7508-Sso_Group")
+ public class SsoConfig extends DefaultConfiguration {
+ public static final String PLUGIN_ID = "com.fr.plugin.j7508.sso.auth";
+ public static final String BASE_URI = "xxxx";
+ public static final String ESB_URI = "xxxx";
+ // 每天中午十二点触发
+ public static final String CRON_CONDITION = "0 0 12 * * ?";
+
+ private static volatile SsoConfig config = null;
+
+ @Focus(id = PLUGIN_ID, text = "Plugin-J7508-Sso", source = Original.PLUGIN)
+ public static SsoConfig getInstance() {
+ if (config == null) {
+ config = ConfigContext.getConfigInstance(SsoConfig.class);
+ }
+ return config;
+ }
+
+ @Identifier(value = "frUri", name = "Plugin-J7508-Sso_Config_FrUri", description = "Plugin-J7508-Sso_Config_FrUri_Description", status = Status.SHOW)
+ private Conf frUri = Holders.simple(StringKit.EMPTY);
+ @Identifier(value = "uriBase", name = "Plugin-J7508-Sso_Config_UriBase", description = "Plugin-J7508-Sso_Config_UriBase_Description", status = Status.SHOW)
+ private Conf uriBase = Holders.simple(BASE_URI);
+ @Identifier(value = "esbUri", name = "Plugin-J7508-Sso_Config_EsbUri", description = "Plugin-J7508-Sso_Config_EsbUri_Description", status = Status.SHOW)
+ private Conf esbUri = Holders.simple(ESB_URI);
+ @Identifier(value = "clientId", name = "Plugin-J7508-Sso_Config_ClientId", description = "Plugin-J7508-Sso_Config_ClientId_Description", status = Status.SHOW)
+ private Conf clientId = Holders.simple(StringKit.EMPTY);
+ @Identifier(value = "clientSecret", name = "Plugin-J7508-Sso_Config_ClientSecret", description = "Plugin-J7508-Sso_Config_ClientSecret_Description", status = Status.SHOW)
+ private Conf clientSecret = Holders.simple(StringKit.EMPTY);
+ @Identifier(value = "cronCondition", name = "Plugin-J7508-Sso_Config_CronCondition", description = "Plugin-J7508-Sso_Config_CronCondition_Description", status = Status.SHOW)
+ private Conf cronCondition = Holders.simple(CRON_CONDITION);
+ @Identifier(value = "appID", name = "Plugin-J7508-Sso_Config_AppID", description = "Plugin-J7508-Sso_Config_AppID_Description", status = Status.SHOW)
+ private Conf appID = Holders.simple(StringKit.EMPTY);
+ @Identifier(value = "appSecret", name = "Plugin-J7508-Sso_Config_AppSecret", description = "Plugin-J7508-Sso_Config_AppSecret_Description", status = Status.SHOW)
+ private Conf appSecret = Holders.simple(StringKit.EMPTY);
+
+ public String getFrUri() {
+ return frUri.get();
+ }
+
+ public void setFrUri(String frUri) {
+ this.frUri.set(frUri);
+ }
+
+ public String getUriBase() {
+ return uriBase.get();
+ }
+
+ public void setUriBase(String uriBase) {
+ this.uriBase.set(uriBase);
+ }
+
+ public String getEsbUri() {
+ return esbUri.get();
+ }
+
+ public void setEsbUri(String esbUri) {
+ this.esbUri.set(esbUri);
+ }
+
+ public String getClientId() {
+ return clientId.get();
+ }
+
+ public void setClientId(String clientId) {
+ this.clientId.set(clientId);
+ }
+
+ public String getClientSecret() {
+ return clientSecret.get();
+ }
+
+ public void setClientSecret(String clientSecret) {
+ this.clientSecret.set(clientSecret);
+ }
+
+ public String getCronCondition() {
+ return cronCondition.get();
+ }
+
+ public void setCronCondition(String cronCondition) {
+ this.cronCondition.set(cronCondition);
+ }
+
+ public String getAppID() {
+ return appID.get();
+ }
+
+ public void setAppID(String appID) {
+ this.appID.set(appID);
+ }
+
+ public String getAppSecret() {
+ return appSecret.get();
+ }
+
+ public void setAppSecret(String appSecret) {
+ this.appSecret.set(appSecret);
+ }
+ }
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/j7508/sso/helper/SsoUserScheduleHelper.java b/src/main/java/com/fr/plugin/j7508/sso/helper/SsoUserScheduleHelper.java
new file mode 100644
index 0000000..0a11f1a
--- /dev/null
+++ b/src/main/java/com/fr/plugin/j7508/sso/helper/SsoUserScheduleHelper.java
@@ -0,0 +1,77 @@
+ /*
+ * Copyright (C), 2018-2021
+ * Project: starter
+ * FileName: DingTalkScheduleHelper
+ * Author: Louis
+ * Date: 2021/4/21 15:52
+ */
+ package com.fr.plugin.j7508.sso.helper;
+
+ import com.fr.plugin.j7508.sso.bean.SsoUserJobConstructor;
+ import com.fr.plugin.j7508.sso.job.SsoUserSyncMemberJob;
+ import com.fr.scheduler.ScheduleJobManager;
+ import com.fr.third.v2.org.quartz.CronScheduleBuilder;
+ import com.fr.third.v2.org.quartz.TriggerBuilder;
+
+ import java.util.ArrayList;
+ import java.util.HashMap;
+ import java.util.TimeZone;
+
+ /**
+ *
+ *
+ *
+ * @author fr.open
+ * @since 1.0.0
+ */
+ public class SsoUserScheduleHelper {
+ public static final String SSO_USER_SCHEDULE_SYN_MEMBER_JOB_NAME = "MqhSsoUserSynDepMemberJob";
+ public static final String SSO_USER_SCHEDULE_SYN_MEMBER_TRIGGER_NAME = "MqhSsoUserSynDepMemberTrigger";
+ public static final String SSO_USER_SCHEDULE_SYN_MEMBER_GROUP = "MqhSsoUserSynDepMemberGroup";
+ public static final String SSO_USER_SCHEDULE_SYN_MEMBER_TRIGGER_GROUP = "MqhSsoUserSynDepMemberTriggerGroup";
+
+ private SsoUserScheduleHelper() {
+ }
+
+ public static SsoUserScheduleHelper getInstance() {
+ return SsoUserScheduleHelper.HOLDER.INSTANCE;
+ }
+
+ public void startSynMemberSchedule(String cronCondition) throws Exception {
+ SsoUserJobConstructor jobConstructor = (new SsoUserJobConstructor())
+ .cron(cronCondition).jobName(SSO_USER_SCHEDULE_SYN_MEMBER_JOB_NAME)
+ .jobGroup(SSO_USER_SCHEDULE_SYN_MEMBER_GROUP).triggerName(SSO_USER_SCHEDULE_SYN_MEMBER_TRIGGER_NAME)
+ .triggerGroup(SSO_USER_SCHEDULE_SYN_MEMBER_TRIGGER_GROUP).jobClazz(SsoUserSyncMemberJob.class);
+ this.startSchedule(jobConstructor);
+ }
+
+ public void startSchedule(SsoUserJobConstructor var1) throws Exception {
+ if (var1 != null) {
+ String var2 = var1.getCron();
+ String var3 = var1.getTriggerName();
+ String var4 = var1.getTriggerGroup();
+ String var5 = var1.getJobName();
+ String var6 = var1.getJobGroup();
+ Class var7 = var1.getJobClazz();
+ TriggerBuilder var8 = TriggerBuilder.newTrigger();
+ var8.withIdentity(var3, var4);
+ var8.withSchedule(CronScheduleBuilder.cronSchedule(var2).withMisfireHandlingInstructionFireAndProceed().inTimeZone(TimeZone.getTimeZone(TimeZone.getDefault().getID()))).startNow();
+ var8.forJob(var5, var6);
+ ArrayList var9 = new ArrayList();
+ var9.add(var8.build());
+ ScheduleJobManager.getInstance().removeJob(var5, var6);
+ ScheduleJobManager.getInstance().addJob(var5, var6, "jobDescription", var7, var9, new HashMap());
+ }
+ }
+
+ public void stopSchedule(String var1, String var2) {
+ ScheduleJobManager.getInstance().removeJob(var1, var2);
+ }
+
+ public static class HOLDER {
+ private static final SsoUserScheduleHelper INSTANCE = new SsoUserScheduleHelper();
+
+ public HOLDER() {
+ }
+ }
+ }
diff --git a/src/main/java/com/fr/plugin/j7508/sso/job/SsoUserSyncMemberJob.java b/src/main/java/com/fr/plugin/j7508/sso/job/SsoUserSyncMemberJob.java
new file mode 100644
index 0000000..b4414c2
--- /dev/null
+++ b/src/main/java/com/fr/plugin/j7508/sso/job/SsoUserSyncMemberJob.java
@@ -0,0 +1,34 @@
+ /*
+ * Copyright (C), 2018-2021
+ * Project: starter
+ * FileName: SsoUserSyncMemberJob
+ * Author: Louis
+ * Date: 2021/4/21 16:02
+ */
+ package com.fr.plugin.j7508.sso.job;
+
+ import com.fanruan.api.log.LogKit;
+ import com.fr.cluster.core.ClusterNode;
+ import com.fr.plugin.j7508.sso.user.SsoUserManager;
+ import com.fr.scheduler.job.FineScheduleJob;
+ import com.fr.third.v2.org.quartz.JobExecutionContext;
+
+ /**
+ *
+ *
+ *
+ * @author fr.open
+ * @since 1.0.0
+ */
+ public class SsoUserSyncMemberJob extends FineScheduleJob {
+ public SsoUserSyncMemberJob() {
+ }
+
+ public void run(JobExecutionContext jobExecutionContext, ClusterNode clusterNode) {
+ try {
+ SsoUserManager.getInstance().synSSODepartments();
+ } catch (Exception e) {
+ LogKit.error(e.getMessage(), e);
+ }
+ }
+ }
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/j7508/sso/kit/DepartmentServiceKit.java b/src/main/java/com/fr/plugin/j7508/sso/kit/DepartmentServiceKit.java
new file mode 100644
index 0000000..d93a636
--- /dev/null
+++ b/src/main/java/com/fr/plugin/j7508/sso/kit/DepartmentServiceKit.java
@@ -0,0 +1,96 @@
+ /*
+ * Copyright (C), 2018-2021
+ * Project: starter
+ * FileName: DepartmentServiceKit
+ * Author: Louis
+ * Date: 2021/5/14 9:38
+ */
+ package com.fr.plugin.j7508.sso.kit;
+
+ import com.fanruan.api.i18n.I18nKit;
+ import com.fanruan.api.util.StringKit;
+ import com.fr.decision.authority.AuthorityContext;
+ import com.fr.decision.authority.base.constant.type.operation.ManualOperationType;
+ import com.fr.decision.authority.data.Department;
+ import com.fr.decision.record.OperateMessage;
+ import com.fr.decision.webservice.exception.general.DuplicatedNameException;
+ import com.fr.decision.webservice.v10.user.DepartmentService;
+ import com.fr.general.ComparatorUtils;
+ import com.fr.intelli.record.MetricRegistry;
+ import com.fr.stable.StableUtils;
+ import com.fr.stable.query.QueryFactory;
+ import com.fr.stable.query.condition.QueryCondition;
+ import com.fr.stable.query.restriction.Restriction;
+ import com.fr.stable.query.restriction.RestrictionFactory;
+
+ import java.util.ArrayList;
+ import java.util.Collections;
+ import java.util.List;
+
+ import static com.fr.decision.authority.base.AuthorityConstants.DECISION_DEP_ROOT;
+
+ /**
+ *
+ *
+ *
+ * @author fr.open
+ * @since 1.0.0
+ */
+ public class DepartmentServiceKit extends DepartmentService {
+ private static volatile DepartmentServiceKit departmentServiceKit = null;
+
+ public DepartmentServiceKit() {
+ }
+
+ public static DepartmentServiceKit getInstance() {
+ if (departmentServiceKit == null) {
+ departmentServiceKit = new DepartmentServiceKit();
+ }
+ return departmentServiceKit;
+ }
+
+ public void addDepartment(String id, String pId, String depName) throws Exception {
+ if (StringKit.equals(pId, DECISION_DEP_ROOT)) {
+ pId = null;
+ }
+ this.checkDuplicatedDepartmentName(pId, depName);
+ Department department = (new Department()).id(id).name(depName).parentId(pId).creationType(ManualOperationType.KEY).lastOperationType(ManualOperationType.KEY).enable(true);
+ AuthorityContext.getInstance().getDepartmentController().add(department);
+ MetricRegistry.getMetric().submit(OperateMessage.build("Dec-Module-User_Manager", "Dec-Department", this.getDepartmentFullPath(pId, depName, "/"), "Dec-Log_Add"));
+ }
+
+ private void checkDuplicatedDepartmentName(String parentId, String depName) throws Exception {
+ QueryCondition condition = QueryFactory.create().addRestriction(RestrictionFactory.and(new Restriction[]{RestrictionFactory.eq("name", depName), RestrictionFactory.eq("parentId", parentId)}));
+ Department sameNameDep = AuthorityContext.getInstance().getDepartmentController().findOne(condition);
+ if (sameNameDep != null) {
+ throw new DuplicatedNameException();
+ }
+ }
+
+ private String getDepartmentFullPath(String pId, String depName, String splitter) throws Exception {
+ List paths = new ArrayList<>();
+ paths.add(depName);
+ while (!ComparatorUtils.equals(pId, DECISION_DEP_ROOT) && pId != null) {
+ Department parentDepartment = AuthorityContext.getInstance().getDepartmentController().getById(pId);
+ paths.add(parentDepartment.getName());
+ pId = parentDepartment.getParentId();
+ }
+ Collections.reverse(paths);
+ return StableUtils.join(paths.toArray(new String[0]), splitter);
+ }
+
+ public void editDepartment(String departmentId, String depName, String pId) throws Exception {
+ if (StringKit.equals(pId, DECISION_DEP_ROOT)) {
+ pId = null;
+ }
+ Department department = AuthorityContext.getInstance().getDepartmentController().getById(departmentId);
+ String departmentFullPath = DepartmentService.getInstance().getDepartmentFullPath(departmentId);
+ if (!ComparatorUtils.equals(department.getName(), depName)) {
+ this.checkDuplicatedDepartmentName(department.getParentId(), depName);
+ department.setName(depName);
+ department.setParentId(pId);
+ AuthorityContext.getInstance().getDepartmentController().update(department);
+ }
+ MetricRegistry.getMetric().submit(OperateMessage.build("Dec-Module-User_Manager", "Dec-Department", DepartmentService.getInstance().getDepartmentFullPath(departmentId), "Dec-Log_Update", I18nKit.getLocText("Fine-Dec_Department") + ":" + departmentFullPath));
+ }
+ }
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/j7508/sso/kit/UserServiceKit.java b/src/main/java/com/fr/plugin/j7508/sso/kit/UserServiceKit.java
new file mode 100644
index 0000000..6275d1c
--- /dev/null
+++ b/src/main/java/com/fr/plugin/j7508/sso/kit/UserServiceKit.java
@@ -0,0 +1,169 @@
+ /*
+ * Copyright (C), 2018-2021
+ * Project: starter
+ * FileName: UserServiceKit
+ * Author: Louis
+ * Date: 2021/5/14 8:28
+ */
+ package com.fr.plugin.j7508.sso.kit;
+
+import com.fanruan.api.log.LogKit;
+import com.fanruan.api.util.StringKit;
+import com.fr.decision.authority.AuthorityContext;
+import com.fr.decision.authority.data.Post;
+import com.fr.decision.authority.data.User;
+import com.fr.decision.authority.data.personnel.DepRole;
+import com.fr.decision.privilege.TransmissionTool;
+import com.fr.decision.webservice.bean.user.DepartmentPostBean;
+import com.fr.decision.webservice.bean.user.UserBean;
+import com.fr.decision.webservice.utils.UserSourceFactory;
+import com.fr.decision.webservice.utils.WebServiceUtils;
+import com.fr.decision.webservice.v10.user.PositionService;
+import com.fr.decision.webservice.v10.user.UserService;
+ import com.fr.json.JSONObject;
+ import com.fr.stable.StringUtils;
+import com.fr.stable.collections.CollectionUtils;
+import com.fr.stable.query.QueryFactory;
+import com.fr.stable.query.restriction.RestrictionFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+ /**
+ *
+ *
+ *
+ * @author fr.open
+ * @since 1.0.0
+ */
+ public class UserServiceKit extends UserService {
+ private static volatile UserServiceKit userServiceKit = null;
+
+ public UserServiceKit() {
+ }
+
+ public static UserServiceKit getInstance() {
+ if (userServiceKit == null) {
+ userServiceKit = new UserServiceKit();
+ }
+ return userServiceKit;
+ }
+
+ public UserBean createUserBean(JSONObject account) throws Exception {
+ UserBean userBean = new UserBean();
+ userBean.setUsername(account.getString("uid"));
+ userBean.setRealName(account.getString("userName"));
+ userBean.setEnable(StringKit.equals(account.getString("status"), "1"));
+ userBean.setEmail(account.getString("email"));
+ userBean.setMobile(account.getString("mobile"));
+ userBean.setPassword(TransmissionTool.defaultEncrypt(account.getString("uid") + "123456"));
+ if (StringKit.isNotBlank(account.getString("orgCode"))) {
+ List departmentPostIds = createDepartmentPostIds(account.getString("orgCode"), account.getString("jobTitle"));
+ userBean.setDepartmentPostIds(departmentPostIds);
+ }
+ return userBean;
+ }
+
+ /**
+ * 转为部门职务组合
+ *
+ * @param departmentPostId
+ * @param title
+ * @return
+ * @throws Exception
+ */
+ private List createDepartmentPostIds(String departmentPostId, String title) throws Exception {
+ List departmentPostIds = new ArrayList<>();
+ if (StringKit.isBlank(departmentPostId) || StringKit.equals(departmentPostId, "null")) {
+ return departmentPostIds;
+ }
+ String positionId = positionSynOperation(title, departmentPostId);
+ if (StringKit.isNotBlank(positionId)) {
+ departmentPostId = departmentPostId + "@@@" + positionId;
+ }
+ departmentPostIds.add(departmentPostId);
+ return departmentPostIds;
+ }
+
+ /**
+ * 职务同步操作
+ *
+ * @param title
+ * @return
+ * @throws Exception
+ */
+ private String positionSynOperation(String title, String departmentId) throws Exception {
+ String position = StringKit.isNotBlank(title) ? title : "职员";
+ Post post = AuthorityContext.getInstance().getPostController().findOne(QueryFactory.create().addRestriction(RestrictionFactory.eq("name", position)));
+ String positionId;
+ if (post == null) {
+ positionId = PositionService.getInstance().addPosition(position, position);
+ } else {
+ positionId = post.getId();
+ }
+ List departmentPostBeanList = PositionService.getInstance().getPositionsUnderParentDepartment(getAdminUserId(), departmentId, position);
+ if (departmentPostBeanList == null || departmentPostBeanList.isEmpty()) {
+ try {
+ AuthorityContext.getInstance().getPostController().addPostToDepartment(positionId, departmentId);
+ } catch (Exception e) {
+ LogKit.info("sso-UserServiceKit-positionSynOperation-addPostToDepartmentFailed-position:{}, departmentId:{}", positionId + position, departmentId);
+ LogKit.error(e.getMessage(), e);
+ }
+ }
+ return positionId;
+ }
+
+ /**
+ * 获取管理员id
+ *
+ * @return
+ * @throws Exception
+ */
+ public String getAdminUserId() throws Exception {
+ List adminUserIdList = UserService.getInstance().getAdminUserIdList();
+ if (adminUserIdList.isEmpty()) {
+ return "admin";
+ }
+ return StringKit.isNotBlank(adminUserIdList.get(0)) ? adminUserIdList.get(0) : "admin";
+ }
+
+ public UserBean updateUserBean(JSONObject account) throws Exception {
+ User user = UserService.getInstance().getUserByUserName(account.getString("uid"));
+ if (user == null) {
+ return null;
+ }
+ UserBean userBean = new UserBean();
+ userBean.setId(user.getId());
+ userBean.setUsername(user.getUserName());
+ userBean.setRealName(account.getString("userName"));
+ userBean.setEnable(StringKit.equals(account.getString("status"), "1"));
+ userBean.setEmail(account.getString("email"));
+ userBean.setMobile(account.getString("mobile"));
+ if (StringKit.isNotBlank(account.getString("orgCode"))) {
+ List departmentPostIds = createDepartmentPostIds(account.getString("orgCode"), account.getString("jobTitle"));
+ userBean.setDepartmentPostIds(departmentPostIds);
+ }
+ return userBean;
+ }
+
+ /**
+ * 增加用户部门关联
+ *
+ * @param userBean
+ * @throws Exception
+ */
+ public void addUserDepartment(UserBean userBean) throws Exception {
+ if (CollectionUtils.isEmpty(userBean.getDepartmentPostIds())) {
+ return;
+ }
+ for (String departmentPostId : userBean.getDepartmentPostIds()) {
+ if (StringUtils.isEmpty(departmentPostId)) {
+ continue;
+ }
+ User user = UserService.getInstance().getUserByUserName(userBean.getUsername());
+ DepRole depRole = WebServiceUtils.parseUniqueDepartmentPostId(departmentPostId);
+ UserSourceFactory.getInstance().checkSource(user, AuthorityContext.getInstance().getDepartmentController().getById(depRole.getDepartmentId()));
+ AuthorityContext.getInstance().getUserController().addUserToDepartmentAndPost(user.getId(), depRole.getDepartmentId(), depRole.getPostId());
+ }
+ }
+ }
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/j7508/sso/request/OAuthLogin.java b/src/main/java/com/fr/plugin/j7508/sso/request/OAuthLogin.java
new file mode 100644
index 0000000..475e701
--- /dev/null
+++ b/src/main/java/com/fr/plugin/j7508/sso/request/OAuthLogin.java
@@ -0,0 +1,221 @@
+ /*
+ * Copyright (C), 2018-2021
+ * Project: starter
+ * FileName: OAuthLogin
+ * Author: Louis
+ * Date: 2021/3/30 22:09
+ */
+ package com.fr.plugin.j7508.sso.request;
+
+ import com.fanruan.api.decision.login.LoginKit;
+import com.fanruan.api.decision.user.UserKit;
+import com.fanruan.api.log.LogKit;
+import com.fanruan.api.net.NetworkKit;
+import com.fanruan.api.net.http.HttpKit;
+import com.fanruan.api.util.StringKit;
+import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider;
+import com.fr.decision.webservice.utils.DecisionServiceConstants;
+import com.fr.decision.webservice.v10.login.LoginService;
+import com.fr.json.JSONObject;
+import com.fr.plugin.j7508.sso.config.SsoConfig;
+import com.fr.third.org.apache.http.client.utils.URIBuilder;
+
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Map;
+
+ /**
+ *
+ *
+ *
+ * @author fr.open
+ * @since 1.0.0
+ */
+ public class OAuthLogin extends AbstractGlobalRequestFilterProvider {
+ public static final String REMOTE_DESIGN = "/remote/design";
+ public static final String RESOURCES_PATH = "/resources";
+ public static final String FILE_PATH = "/file";
+ public static final String SYSTEM_INFO = "/system/info";
+ public static final String MATERIALS_MIN_JS_MAP = "/materials.min.js.map";
+ public static final String LOGIN_PATH = "/login";
+ public static final String LOGIN_OTHER = "/login/";
+ public static final String LOGOUT_PATH = "/logout";
+ public static final String USER_LANGUAGE = "/v10/user/language";
+ public static final String ACCOUNT_IAMPUSH = "/account/iamPush";
+
+ public static final String CODE_URL = "/esc-sso/oauth2.0/authorize";
+ public static final String TOKEN_URL = "/esc-sso/oauth2.0/accessToken";
+ public static final String USER_URL = "/esc-sso/oauth2.0/profile";
+ public static final String CODE = "code";
+
+ private SsoConfig config;
+
+ /**
+ * 过滤器名称
+ *
+ * @return
+ */
+ @Override
+ public String filterName() {
+ return "J7508Filter";
+ }
+
+ /**
+ * 过滤规则
+ *
+ * @return
+ */
+ @Override
+ public String[] urlPatterns() {
+ return new String[]{"/*"};
+ }
+
+ /**
+ * 过滤器初始化
+ *
+ * @param filterConfig
+ */
+ @Override
+ public void init(FilterConfig filterConfig) {
+ this.config = SsoConfig.getInstance();
+ super.init(filterConfig);
+ }
+
+ /**
+ * 过滤器处理
+ *
+ * @param request
+ * @param response
+ * @param filterChain
+ */
+ @Override
+ public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {
+ try {
+ if (operation(request, response)) {
+ filterChain.doFilter(request, response);
+ }
+ } catch (Exception e) {
+ LogKit.error(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * 用户验证登陆操作
+ *
+ * @param req
+ * @param res
+ * @throws Exception
+ */
+ private boolean operation(HttpServletRequest req, HttpServletResponse res) throws Exception {
+ String pathInfo = (req.getPathInfo() != null) ? req.getPathInfo() : StringKit.EMPTY;
+ LogKit.info("sso-OAuthLogin-operation-pathInfo:{}", pathInfo);
+ if (pathInfo.startsWith(REMOTE_DESIGN) || pathInfo.startsWith(LOGIN_OTHER)
+ || StringKit.equals(LOGIN_PATH, pathInfo) || StringKit.equals(ACCOUNT_IAMPUSH, pathInfo)
+ || pathInfo.startsWith(RESOURCES_PATH) || pathInfo.startsWith(LOGOUT_PATH)
+ || pathInfo.startsWith(SYSTEM_INFO) || pathInfo.startsWith(MATERIALS_MIN_JS_MAP)
+ || pathInfo.startsWith(USER_LANGUAGE) || pathInfo.startsWith(FILE_PATH)) {
+ return true;
+ }
+ // 已登录
+ if (LoginService.getInstance().isLogged(req)) {
+ return true;
+ }
+ String code = NetworkKit.getHTTPRequestParameter(req, CODE);
+ LogKit.info("sso-OAuthLogin-operation-code:{}", code);
+ if (StringKit.isBlank(code)) {
+ res.sendRedirect(getLoginUrl(req));
+ return false;
+ }
+ String accessToken = getAccessToken(code);
+ if (StringKit.isEmpty(accessToken)) {
+ res.sendRedirect(getLoginUrl(req));
+ return false;
+ }
+ String username = getUsername(accessToken);
+ if (StringKit.isEmpty(username) || !UserKit.existUsername(username)) {
+ return true;
+ }
+ String tokenFR = LoginKit.login(req, res, username);
+ req.setAttribute(DecisionServiceConstants.FINE_AUTH_TOKEN_NAME, tokenFR);
+ return true;
+ }
+
+ /**
+ * 通过凭证获得username
+ *
+ * @param accessToken
+ * @return
+ */
+ private String getUsername(String accessToken) throws IOException {
+ Map userInfoParams = new HashMap<>();
+ userInfoParams.put("access_token", accessToken);
+ String userRes = HttpKit.get(this.config.getUriBase() + USER_URL, userInfoParams);
+ LogKit.info("sso-OAuthLogin-getUsername-userRes:{}", userRes);
+ return new JSONObject(userRes).getString("id");
+ }
+
+ /**
+ * 获取access_token
+ *
+ * @param code
+ * @return
+ * @throws Exception
+ */
+ private String getAccessToken(String code) throws Exception {
+ Map params = new HashMap<>();
+ params.put("grant_type", "authorization_code");
+ params.put("oauth_timestamp", String.valueOf(System.currentTimeMillis()));
+ params.put("client_id", this.config.getClientId());
+ params.put("client_secret", this.config.getClientSecret());
+ params.put("code", code);
+ params.put("redirect_uri", this.config.getFrUri());
+ String url = this.config.getUriBase() + TOKEN_URL;
+ String res = HttpKit.post(url, params);
+ LogKit.info("sso-OAuthLogin-getAccessToken-res:{}", res);
+ if (StringKit.isEmpty(res)) {
+ return StringKit.EMPTY;
+ }
+ String token = new JSONObject(res).getString("access_token");
+ if (StringKit.isNotBlank(token)) {
+ return token;
+ }
+ return StringKit.EMPTY;
+ }
+
+ /**
+ * 获取login_url
+ *
+ * @return
+ */
+ private String getLoginUrl(HttpServletRequest request) {
+ String url = SsoConfig.getInstance().getUriBase() + CODE_URL;
+ Map params = new HashMap<>();
+ params.put("client_id", SsoConfig.getInstance().getClientId());
+ params.put("response_type", "code");
+ params.put("redirect_uri", this.config.getFrUri());
+ String loginUrl = buildUrl(url, params);
+ LogKit.info("sso-OAuthLogin-getLoginUrl-loginUrl:{}", loginUrl);
+ return loginUrl;
+ }
+
+ private String buildUrl(String url, Map params) {
+ if (params == null || params.isEmpty()) {
+ return url;
+ }
+ try {
+ URIBuilder builder = new URIBuilder(url);
+ for (Map.Entry entry : params.entrySet()) {
+ builder.setParameter(entry.getKey(), entry.getValue());
+ }
+ return builder.build().toString();
+ } catch (URISyntaxException e) {
+ LogKit.debug("Error to build url, please check the arguments.");
+ return url;
+ }
+ }
+ }
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/j7508/sso/request/UserControllerBridge.java b/src/main/java/com/fr/plugin/j7508/sso/request/UserControllerBridge.java
new file mode 100644
index 0000000..d2db6cd
--- /dev/null
+++ b/src/main/java/com/fr/plugin/j7508/sso/request/UserControllerBridge.java
@@ -0,0 +1,26 @@
+ /*
+ * Copyright (C), 2018-2021
+ * Project: starter
+ * FileName: UserControllerBridge
+ * Author: Louis
+ * Date: 2021/3/29 22:30
+ */
+ package com.fr.plugin.j7508.sso.request;
+
+ import com.fr.decision.fun.impl.AbstractControllerRegisterProvider;
+
+ /**
+ *
+ *
+ *
+ * @author fr.open
+ * @since 1.0.0
+ */
+ public class UserControllerBridge extends AbstractControllerRegisterProvider {
+ @Override
+ public Class[] getControllers() {
+ return new Class[]{
+ UserPushController.class
+ };
+ }
+ }
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/j7508/sso/request/UserPushController.java b/src/main/java/com/fr/plugin/j7508/sso/request/UserPushController.java
new file mode 100644
index 0000000..7e5aa52
--- /dev/null
+++ b/src/main/java/com/fr/plugin/j7508/sso/request/UserPushController.java
@@ -0,0 +1,120 @@
+ /*
+ * Copyright (C), 2018-2021
+ * Project: starter
+ * FileName: UserPushController
+ * Author: Louis
+ * Date: 2021/3/29 22:36
+ */
+ package com.fr.plugin.j7508.sso.request;
+
+ import com.fanruan.api.decision.user.UserKit;
+import com.fanruan.api.log.LogKit;
+ import com.fr.decision.authority.data.User;
+ import com.fr.decision.webservice.annotation.LoginStatusChecker;
+import com.fr.decision.webservice.bean.user.UserBean;
+import com.fr.decision.webservice.v10.user.UserService;
+import com.fr.json.JSONArray;
+import com.fr.json.JSONObject;
+import com.fr.plugin.j7508.sso.bean.DataResponse;
+import com.fr.plugin.j7508.sso.config.SsoConfig;
+import com.fr.plugin.j7508.sso.kit.UserServiceKit;
+import com.fr.third.springframework.stereotype.Controller;
+import com.fr.third.springframework.web.bind.annotation.RequestBody;
+import com.fr.third.springframework.web.bind.annotation.RequestMapping;
+import com.fr.third.springframework.web.bind.annotation.RequestMethod;
+import com.fr.third.springframework.web.bind.annotation.ResponseBody;
+
+import javax.servlet.http.HttpServletResponse;
+
+ /**
+ *
+ *
+ *
+ * @author fr.open
+ * @since 1.0.0
+ */
+ @Controller
+ @RequestMapping("account/iamPush")
+ public class UserPushController {
+ private SsoConfig config;
+ private String adminName;
+
+ public UserPushController() {
+ this.config = SsoConfig.getInstance();
+ }
+
+ @RequestMapping(method = RequestMethod.POST)
+ @ResponseBody
+ @LoginStatusChecker(required = false)
+ public DataResponse doAction(@RequestBody(required = false) String bodyContent, HttpServletResponse res) {
+ try {
+ LogKit.info("sso-UserPushController-doAction-bodyContent:{}", bodyContent);
+ JSONObject bodyJson = new JSONObject(bodyContent);
+ JSONArray accounts = bodyJson.getJSONArray("data");
+ this.adminName = UserService.getInstance().getAdminUserNameList().get(0);
+ setHeader(res);
+ operation(accounts);
+ return DataResponse.success();
+ } catch (Exception e) {
+ LogKit.error(e.getMessage(), e);
+ return DataResponse.error("1", "error");
+ }
+ }
+
+ /**
+ * 企业应用业务事件处理
+ *
+ * @param accounts
+ * @return
+ */
+ private void operation(JSONArray accounts) throws Exception {
+ for (int i = 0; i < accounts.size(); i++) {
+ JSONObject account = accounts.getJSONObject(i);
+ userSynOperation(account);
+ }
+ }
+
+ /**
+ * 用户同步操作
+ *
+ * @param account
+ * @throws Exception
+ */
+ private void userSynOperation(JSONObject account) throws Exception {
+ String userId = account.getString("uid");
+ UserBean userBean;
+ if (UserKit.existUsername(userId)) {
+ userBean = UserServiceKit.getInstance().updateUserBean(account);
+ if (userBean == null) {
+ return;
+ }
+ UserService.getInstance().editUser(userBean);
+ UserService.getInstance().forbidUser(userBean.getId(), userBean.isEnable());
+ UserService.getInstance().updateUserDepartmentPost(UserServiceKit.getInstance().getAdminUserId(), userBean);
+ } else {
+ userBean = UserServiceKit.getInstance().createUserBean(account);
+ try {
+ UserService.getInstance().addUser(userBean);
+ User user = UserService.getInstance().getUserByUserName(userBean.getUsername());
+ UserService.getInstance().forbidUser(user.getId(), userBean.isEnable());
+ } catch (Exception e) {
+ LogKit.error("sso-UserPushController-userSynOperation-Username:{}, RealName:{}, Mobile:{}, Email:{}",
+ userBean.getUsername(), userBean.getRealName(), userBean.getMobile(), userBean.getEmail());
+ LogKit.error(e.getMessage(), e);
+ }
+ }
+ }
+
+ /**
+ * 解决跨域访问问题
+ *
+ * @param res
+ */
+ private void setHeader(HttpServletResponse res) {
+ // 跨域设置header
+ res.setHeader("Access-Control-Allow-Origin", "*");
+ res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
+ res.setHeader("Access-Control-Max-Age", "3600");
+ res.setHeader("Access-Control-Allow-Headers", "x-requested-with");
+ }
+ }
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/j7508/sso/user/SsoUserManager.java b/src/main/java/com/fr/plugin/j7508/sso/user/SsoUserManager.java
new file mode 100644
index 0000000..24afe0f
--- /dev/null
+++ b/src/main/java/com/fr/plugin/j7508/sso/user/SsoUserManager.java
@@ -0,0 +1,158 @@
+ /*
+ * Copyright (C), 2018-2021
+ * Project: starter
+ * FileName: SsoUserManager
+ * Author: Louis
+ * Date: 2021/4/21 16:18
+ */
+ package com.fr.plugin.j7508.sso.user;
+
+ import com.auth0.jwt.JWT;
+ import com.auth0.jwt.JWTCreator;
+ import com.auth0.jwt.algorithms.Algorithm;
+ import com.fanruan.api.log.LogKit;
+ import com.fanruan.api.net.http.HttpKit;
+ import com.fanruan.api.util.StringKit;
+ import com.fr.decision.authority.AuthorityContext;
+ import com.fr.decision.authority.data.Department;
+ import com.fr.decision.base.util.UUIDUtil;
+ import com.fr.json.JSONArray;
+ import com.fr.json.JSONObject;
+ import com.fr.plugin.j7508.sso.config.SsoConfig;
+ import com.fr.plugin.j7508.sso.kit.DepartmentServiceKit;
+ import com.fr.plugin.j7508.sso.utils.SignatureUtil;
+ import com.fr.third.org.apache.http.entity.StringEntity;
+
+ import java.io.IOException;
+ import java.util.HashMap;
+ import java.util.Map;
+ import java.util.UUID;
+
+ import static com.fr.decision.authority.base.AuthorityConstants.DECISION_DEP_ROOT;
+
+ /**
+ *
+ *
+ *
+ * @author fr.open
+ * @since 1.0.0
+ */
+ public final class SsoUserManager {
+ public static final String ORG_LIST_ALL = "/esb/organization/listAll/api";
+ private SsoConfig config;
+
+ public SsoUserManager() {
+ this.config = SsoConfig.getInstance();
+ }
+
+ private static class HOLDER {
+ private static final SsoUserManager INSTANCE = new SsoUserManager();
+ }
+ public static SsoUserManager getInstance() {
+ return HOLDER.INSTANCE;
+ }
+
+ /**
+ * 同步更新部门
+ *
+ * @throws Exception
+ */
+ public synchronized void synSSODepartments() throws Exception {
+ LogKit.info("sso-SsoUserManager-synSSODepartments-start");
+ // 同步部门和用户信息
+ departmentSynLoop();
+ LogKit.info("sso-SsoUserManager-synSSODepartments-end");
+ }
+
+ /**
+ * 按部门遍历子部门并同步人员信息
+ *
+ * @throws Exception
+ */
+ private void departmentSynLoop() throws IOException {
+ JSONArray departmentList = getDepartmentList();
+ // 同步部门信息
+ for (int i = 0; i < departmentList.size(); i++) {
+ try {
+ departmentSynOperation(departmentList.optJSONObject(i));
+ } catch (Exception e) {
+ LogKit.error(e.getMessage(), e);
+ }
+ }
+ }
+
+ /**
+ * 部门组织的新增更新操作
+ *
+ * @param departmentJo
+ * @throws Exception
+ */
+ private void departmentSynOperation(JSONObject departmentJo) throws Exception {
+ LogKit.info("sso-SsoUserManager-departmentSynOperation-departmentJo:{}", departmentJo.encode());
+ String departmentId = departmentJo.getString("orgCode");
+ if(StringKit.equals(departmentJo.getString("status"),"1")) {
+ String parentId = departmentJo.getString("parentCode");
+ if (StringKit.isBlank(parentId)) { parentId = DECISION_DEP_ROOT; }
+ String depName = departmentJo.getString("orgName");
+ Department department = AuthorityContext.getInstance().getDepartmentController().getById(departmentId);
+ if (department == null) {
+ DepartmentServiceKit.getInstance().addDepartment(departmentId, parentId, depName);
+ } else {
+ DepartmentServiceKit.getInstance().editDepartment(department.getId(), depName, parentId);
+ }
+ }
+ if (StringKit.equals(departmentJo.getString("status"), "0")) {
+ DepartmentServiceKit.getInstance().deleteDepartment(departmentId);
+ }
+ }
+
+ /**
+ * 通过接口获取部门列表
+ *
+ * @return
+ * @throws IOException
+ */
+ private JSONArray getDepartmentList() throws IOException {
+ Map headers = new HashMap<>();
+ headers.put("Content-Type", "application/json;charset=UTF-8");
+ headers.put("requestId", UUIDUtil.generate());
+ headers.put("sourceSystem", "BI");
+ headers.put("serviceName", "S_0004_syncOrgnizeAll_S");
+ JSONObject params = JSONObject.create();
+ params.put("size", "3000");
+ params.put("page", "1");
+ params.put("startTime", StringKit.EMPTY);
+ StringEntity stringEntity = new StringEntity(params.encode(), "UTF-8");
+ String response = HttpKit.executeAndParse(com.fanruan.api.net.http.rs.HttpRequest.custom()
+ .url(this.config.getEsbUri() + ORG_LIST_ALL).post(stringEntity).headers(headers).build());
+ LogKit.info("sso-SsoUserManager-getDepartmentList-response:{}", response);
+ JSONObject responseJo = new JSONObject(response);
+ if (StringKit.equals(responseJo.getString("code"), "0")) {
+ return responseJo.getJSONObject("data").getJSONArray("list");
+ }
+ return JSONArray.create();
+ }
+
+ /**
+ * 产生JWT token
+ *
+ * @return
+ */
+ private String getJWTToken() {
+ Map map = new HashMap<>();
+ map.put("timestamp", System.currentTimeMillis() + "");
+ map.put("noncestr", UUID.randomUUID().toString());
+ map.put("secretKey", this.config.getAppSecret());
+ String sign = SignatureUtil.getSign(map);
+ JWTCreator.Builder builder = JWT.create().withAudience(this.config.getAppID());
+ map.remove("secretKey");
+ for (Map.Entry entry : map.entrySet()) {
+ builder.withClaim(entry.getKey(), entry.getValue());
+ }
+ String token = builder.sign(Algorithm.HMAC256(sign));
+ if (StringKit.isNotBlank(token)) {
+ return token;
+ }
+ return StringKit.EMPTY;
+ }
+ }
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/j7508/sso/utils/SignatureUtil.java b/src/main/java/com/fr/plugin/j7508/sso/utils/SignatureUtil.java
new file mode 100644
index 0000000..a7d4183
--- /dev/null
+++ b/src/main/java/com/fr/plugin/j7508/sso/utils/SignatureUtil.java
@@ -0,0 +1,43 @@
+package com.fr.plugin.j7508.sso.utils;
+
+import com.fanruan.api.util.StringKit;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+public class SignatureUtil {
+ public static String getSign(Map sortedParams) {
+ StringBuilder content = new StringBuilder();
+ List keys = new ArrayList<>(sortedParams.keySet());
+ Collections.sort(keys);
+ int index = 0;
+ Iterator var4 = keys.iterator();
+ while (var4.hasNext()) {
+ String key = var4.next();
+ String value = sortedParams.get(key);
+ if (areNotEmpty(new String[] { key, value })) {
+ content.append((index == 0) ? "" : "&").append(key).append("=").append(value);
+ index++;
+ }
+ }
+ return content.toString();
+ }
+
+ public static boolean areNotEmpty(String... values) {
+ boolean result = true;
+ if (values != null && values.length != 0) {
+ String[] var2 = values;
+ int var3 = values.length;
+ for (int var4 = 0; var4 < var3; var4++) {
+ String value = var2[var4];
+ result &= StringKit.isNotEmpty(value);
+ }
+ } else {
+ result = false;
+ }
+ return result;
+ }
+}
diff --git a/src/main/resources/com/fr/plugin/j7508/sso/locale/lang.properties b/src/main/resources/com/fr/plugin/j7508/sso/locale/lang.properties
new file mode 100644
index 0000000..619b427
--- /dev/null
+++ b/src/main/resources/com/fr/plugin/j7508/sso/locale/lang.properties
@@ -0,0 +1,18 @@
+Plugin-J7508-Sso=Sso Plugin
+Plugin-J7508-Sso_Group=Sso Plugin
+Plugin-J7508-Sso_Config_FrUri=Fr Uri
+Plugin-J7508-Sso_Config_FrUri_Description=Fr Uri
+Plugin-J7508-Sso_Config_UriBase=Base Uri
+Plugin-J7508-Sso_Config_UriBase_Description=Base Uri
+Plugin-J7508-Sso_Config_EsbUri=Esb Uri
+Plugin-J7508-Sso_Config_EsbUri_Description=Esb Uri
+Plugin-J7508-Sso_Config_ClientId=Client Id
+Plugin-J7508-Sso_Config_ClientId_Description=Client Id
+Plugin-J7508-Sso_Config_ClientSecret=Client Secret
+Plugin-J7508-Sso_Config_ClientSecret_Description=Client Secret
+Plugin-J7508-Sso_Config_CronCondition=Cron Condition
+Plugin-J7508-Sso_Config_CronCondition_Description=Cron Condition
+Plugin-J7508-Sso_Config_AppID=App ID
+Plugin-J7508-Sso_Config_AppID_Description=App ID
+Plugin-J7508-Sso_Config_AppSecret=App Secret
+Plugin-J7508-Sso_Config_AppSecret_Description=App Secret
\ No newline at end of file
diff --git a/src/main/resources/com/fr/plugin/j7508/sso/locale/lang_zh_CN.properties b/src/main/resources/com/fr/plugin/j7508/sso/locale/lang_zh_CN.properties
new file mode 100644
index 0000000..8b1ec8d
--- /dev/null
+++ b/src/main/resources/com/fr/plugin/j7508/sso/locale/lang_zh_CN.properties
@@ -0,0 +1,18 @@
+Plugin-J7508-Sso=\u5355\u70B9\u767B\u9646\u63D2\u4EF6
+Plugin-J7508-Sso_Group=\u5355\u70B9\u767B\u9646\u63D2\u4EF6
+Plugin-J7508-Sso_Config_FrUri=\u51B3\u7B56\u7CFB\u7EDFURL
+Plugin-J7508-Sso_Config_FrUri_Description=\u51B3\u7B56\u7CFB\u7EDFURL
+Plugin-J7508-Sso_Config_UriBase=\u767B\u9646\u8BA4\u8BC1\u63A5\u53E3
+Plugin-J7508-Sso_Config_UriBase_Description=\u767B\u9646\u8BA4\u8BC1\u63A5\u53E3
+Plugin-J7508-Sso_Config_EsbUri=\u7EC4\u7EC7\u4FE1\u606F\u63A5\u53E3
+Plugin-J7508-Sso_Config_EsbUri_Description=\u7EC4\u7EC7\u4FE1\u606F\u63A5\u53E3
+Plugin-J7508-Sso_Config_ClientId=\u5E94\u7528\u6CE8\u518CID
+Plugin-J7508-Sso_Config_ClientId_Description=\u5E94\u7528\u6CE8\u518CID
+Plugin-J7508-Sso_Config_ClientSecret=\u5E94\u7528\u6CE8\u518C\u5BC6\u7801
+Plugin-J7508-Sso_Config_ClientSecret_Description=\u5E94\u7528\u6CE8\u518C\u5BC6\u7801
+Plugin-J7508-Sso_Config_CronCondition=Cron\u8868\u8FBE\u5F0F
+Plugin-J7508-Sso_Config_CronCondition_Description=Cron\u8868\u8FBE\u5F0F
+Plugin-J7508-Sso_Config_AppID=IAM\u7533\u8BF7\u88AB\u63A8App ID
+Plugin-J7508-Sso_Config_AppID_Description=idm\u5E94\u7528\u914D\u7F6E\u7533\u8BF7\u7684\u88AB\u63A8App ID
+Plugin-J7508-Sso_Config_AppSecret=IAM\u7533\u8BF7\u88AB\u63A8App Secret
+Plugin-J7508-Sso_Config_AppSecret_Description=idm\u5E94\u7528\u914D\u7F6E\u7533\u8BF7\u7684\u88AB\u63A8App Secret
\ No newline at end of file