diff --git a/JSD-8431-需求确认书V1.docx b/JSD-8431-需求确认书V1.docx new file mode 100644 index 0000000..31d75af Binary files /dev/null and b/JSD-8431-需求确认书V1.docx differ diff --git a/JSD-8431配置使用文档.docx b/JSD-8431配置使用文档.docx new file mode 100644 index 0000000..a737307 Binary files /dev/null and b/JSD-8431配置使用文档.docx differ diff --git a/README.md b/README.md index a4139ea..1f967f3 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# open-JSD-8431 +# open-JSD-8431 OAuth2单点+用户同步 JSD-8431开源任务材料 \ No newline at end of file diff --git a/lib/commons-beanutils-1.8.0.jar b/lib/commons-beanutils-1.8.0.jar new file mode 100644 index 0000000..caf7ae3 Binary files /dev/null and b/lib/commons-beanutils-1.8.0.jar differ diff --git a/lib/commons-collections-3.2.1.jar b/lib/commons-collections-3.2.1.jar new file mode 100644 index 0000000..c35fa1f Binary files /dev/null and b/lib/commons-collections-3.2.1.jar differ diff --git a/lib/commons-lang-2.5.jar b/lib/commons-lang-2.5.jar new file mode 100644 index 0000000..ae491da Binary files /dev/null and b/lib/commons-lang-2.5.jar differ diff --git a/lib/commons-logging-1.1.1.jar b/lib/commons-logging-1.1.1.jar new file mode 100644 index 0000000..1deef14 Binary files /dev/null and b/lib/commons-logging-1.1.1.jar differ 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/json-lib-2.4-jdk15.jar b/lib/json-lib-2.4-jdk15.jar new file mode 100644 index 0000000..68d4f3b Binary files /dev/null and b/lib/json-lib-2.4-jdk15.jar differ diff --git a/plugin.xml b/plugin.xml new file mode 100644 index 0000000..5df3480 --- /dev/null +++ b/plugin.xml @@ -0,0 +1,25 @@ + + + com.fr.plugin.hdmu.sso + + yes + 1.2.4 + 10.0 + 2018-07-31 + mqh + + + com.fr.plugin.hdmu + + com.fanruan.api + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/hdmu/LocaleFinder.java b/src/main/java/com/fr/plugin/hdmu/LocaleFinder.java new file mode 100644 index 0000000..fafbddc --- /dev/null +++ b/src/main/java/com/fr/plugin/hdmu/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.hdmu; + + 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.hdmu.config.SsoConfig.PLUGIN_ID; + + /** + *
+ * + * + * @author Louis + * @since 1.0.0 + */ + @EnableMetrics + public class LocaleFinder extends AbstractLocaleFinder { + + @Override + @Focus(id = PLUGIN_ID, text = "Plugin-hdmu", source = Original.PLUGIN) + public String find() { + return "com/fr/plugin/hdmu/locale/lang"; + } + + @Override + public int currentAPILevel() { + return CURRENT_LEVEL; + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/hdmu/PluginMonitor.java b/src/main/java/com/fr/plugin/hdmu/PluginMonitor.java new file mode 100644 index 0000000..617b212 --- /dev/null +++ b/src/main/java/com/fr/plugin/hdmu/PluginMonitor.java @@ -0,0 +1,50 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: PluginMonitor + * Author: Louis + * Date: 2021/3/30 15:10 + */ + package com.fr.plugin.hdmu; + + import com.fanruan.api.log.LogKit; + import com.fr.plugin.context.PluginContext; + import com.fr.plugin.hdmu.config.SsoConfig; + import com.fr.plugin.hdmu.helper.SsoUserScheduleHelper; + import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor; + + import static com.fr.plugin.hdmu.helper.SsoUserScheduleHelper.SSO_USER_SCHEDULE_SYN_MEMBER_GROUP; + import static com.fr.plugin.hdmu.helper.SsoUserScheduleHelper.SSO_USER_SCHEDULE_SYN_MEMBER_JOB_NAME; + + + /** + *
+ * + * + * @author Louis + * @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/hdmu/bean/SsoUserJobConstructor.java b/src/main/java/com/fr/plugin/hdmu/bean/SsoUserJobConstructor.java new file mode 100644 index 0000000..1f1ebb9 --- /dev/null +++ b/src/main/java/com/fr/plugin/hdmu/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.hdmu.bean; + + import com.fr.scheduler.job.FineScheduleJob; + + /** + *
+ * + * + * @author Louis + * @since 1.0.0 + */ + public class SsoUserJobConstructor { + private String cron; + private String jobName; + private String jobGroup; + private String triggerName; + private String triggerGroup; + private Class 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 var1) { + this.setJobClazz(var1); + return this; + } + + public Class getJobClazz() { + return this.jobClazz; + } + + public void setJobClazz(Class var1) { + this.jobClazz = var1; + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/hdmu/config/SsoConfig.java b/src/main/java/com/fr/plugin/hdmu/config/SsoConfig.java new file mode 100644 index 0000000..5d3fae5 --- /dev/null +++ b/src/main/java/com/fr/plugin/hdmu/config/SsoConfig.java @@ -0,0 +1,123 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: SsoConfig + * Author: Louis + * Date: 2021/3/30 9:38 + */ + package com.fr.plugin.hdmu.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 Louis + * @since 1.0.0 + */ + @Visualization(category = "Plugin-hdmu_Group") + public class SsoConfig extends DefaultConfiguration { + public static final String PLUGIN_ID = "com.fr.plugin.hdmu.sso"; + public static final String BASE_URI = "https://127.0.0"; + public static final String URI_IAM = "https://xxx"; + // 每天中午十二点触发 + public static final String CRON_CONDITION = "0 0 12 * * ?"; + public static final String ROOT_DEP_ID = "ROOT"; + + private static volatile SsoConfig config = null; + + @Focus(id = PLUGIN_ID, text = "Plugin-hdmu", source = Original.PLUGIN) + public static SsoConfig getInstance() { + if (config == null) { + config = ConfigContext.getConfigInstance(SsoConfig.class); + } + return config; + } + + @Identifier(value = "clientId", name = "Plugin-hdmu_Config_ClientId", description = "Plugin-hdmu_Config_ClientId_Description", status = Status.SHOW) + private Conf clientId = Holders.simple(StringKit.EMPTY); + @Identifier(value = "clientSecret", name = "Plugin-hdmu_Config_ClientSecret", description = "Plugin-hdmu_Config_ClientSecret_Description", status = Status.SHOW) + private Conf clientSecret = Holders.simple(StringKit.EMPTY); + @Identifier(value = "uriBase", name = "Plugin-hdmu_Config_UriBase", description = "Plugin-hdmu_Config_UriBase_Description", status = Status.SHOW) + private Conf uriBase = Holders.simple(BASE_URI); + @Identifier(value = "frUri", name = "Plugin-hdmu_Config_FrUri", description = "Plugin-hdmu_Config_FrUri_Description", status = Status.SHOW) + private Conf frUri = Holders.simple(StringKit.EMPTY); + @Identifier(value = "appID", name = "Plugin-hdmu_Config_AppID", description = "Plugin-hdmu_Config_AppID_Description", status = Status.SHOW) + private Conf appID = Holders.simple(StringKit.EMPTY); + @Identifier(value = "cronCondition", name = "Plugin-hdmu_Config_CronCondition", description = "Plugin-hdmu_Config_CronCondition_Description", status = Status.SHOW) + private Conf cronCondition = Holders.simple(CRON_CONDITION); + @Identifier(value = "uriIam", name = "Plugin-hdmu_Config_UriIam", description = "Plugin-hdmu_Config_UriIam_Description", status = Status.SHOW) + private Conf uriIam = Holders.simple(URI_IAM); + @Identifier(value = "appIamKey", name = "Plugin-hdmu_Config_AppIamKey", description = "Plugin-hdmu_Config_AppIamKey_Description", status = Status.SHOW) + private Conf appIamKey = Holders.simple(StringKit.EMPTY); + + 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 getUriBase() { + return uriBase.get(); + } + + public void setUriBase(String uriBase) { + this.uriBase.set(uriBase); + } + + public String getFrUri() { + return frUri.get(); + } + + public void setFrUri(String frUri) { + this.frUri.set(frUri); + } + + 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 getUriIam() { + return uriIam.get(); + } + + public void setUriIam(String uriIam) { + this.uriIam.set(uriIam); + } + + public String getAppIamKey() { + return appIamKey.get(); + } + + public void setAppIamKey(String appIamKey) { + this.appIamKey.set(appIamKey); + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/hdmu/helper/SsoUserScheduleHelper.java b/src/main/java/com/fr/plugin/hdmu/helper/SsoUserScheduleHelper.java new file mode 100644 index 0000000..89ac3b9 --- /dev/null +++ b/src/main/java/com/fr/plugin/hdmu/helper/SsoUserScheduleHelper.java @@ -0,0 +1,77 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: SsoUserScheduleHelper + * Author: Louis + * Date: 2021/4/21 15:52 + */ + package com.fr.plugin.hdmu.helper; + + import com.fr.plugin.hdmu.bean.SsoUserJobConstructor; + import com.fr.plugin.hdmu.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 Louis + * @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 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/hdmu/job/SsoUserSyncMemberJob.java b/src/main/java/com/fr/plugin/hdmu/job/SsoUserSyncMemberJob.java new file mode 100644 index 0000000..9fb3ea5 --- /dev/null +++ b/src/main/java/com/fr/plugin/hdmu/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.hdmu.job; + + import com.fanruan.api.log.LogKit; + import com.fr.cluster.core.ClusterNode; + import com.fr.plugin.hdmu.user.SsoUserManager; + import com.fr.scheduler.job.FineScheduleJob; + import com.fr.third.v2.org.quartz.JobExecutionContext; + + /** + *
+ * + * + * @author Louis + * @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/hdmu/kit/DepartmentServiceKit.java b/src/main/java/com/fr/plugin/hdmu/kit/DepartmentServiceKit.java new file mode 100644 index 0000000..60b3a37 --- /dev/null +++ b/src/main/java/com/fr/plugin/hdmu/kit/DepartmentServiceKit.java @@ -0,0 +1,87 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: DepartmentServiceKit + * Author: Louis + * Date: 2021/5/14 9:38 + */ + package com.fr.plugin.hdmu.kit; + + 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.webservice.exception.general.DuplicatedNameException; + import com.fr.decision.webservice.v10.user.DepartmentService; + import com.fr.general.ComparatorUtils; + import com.fr.plugin.hdmu.config.SsoConfig; + 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 static com.fr.decision.authority.base.AuthorityConstants.DECISION_DEP_ROOT; + + /** + *
+ * + * + * @author Louis + * @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; + } + + /** + * 根部门与FR根部门转换 + * + * @param parentId + * @return + */ + public String changeRootId(String parentId) { + if (StringKit.isBlank(parentId) || StringKit.equals(parentId, SsoConfig.ROOT_DEP_ID)) { + return DECISION_DEP_ROOT; + } + return parentId; + } + + 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); + } + + 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(); + } + } + + 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); + if (!ComparatorUtils.equals(department.getName(), depName)) { + this.checkDuplicatedDepartmentName(department.getParentId(), depName); + department.setName(depName); + department.setParentId(pId); + AuthorityContext.getInstance().getDepartmentController().update(department); + } + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/hdmu/kit/PositionServiceKit.java b/src/main/java/com/fr/plugin/hdmu/kit/PositionServiceKit.java new file mode 100644 index 0000000..b874fe3 --- /dev/null +++ b/src/main/java/com/fr/plugin/hdmu/kit/PositionServiceKit.java @@ -0,0 +1,54 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: PositionServiceKit + * Author: Louis + * Date: 2021/8/18 15:38 + */ + package com.fr.plugin.hdmu.kit; + + import com.fr.decision.authority.AuthorityContext; + import com.fr.decision.authority.base.constant.SoftRoleType; + import com.fr.decision.authority.base.constant.type.operation.ManualOperationType; + import com.fr.decision.authority.data.Post; + import com.fr.decision.record.OperateMessage; + import com.fr.decision.webservice.v10.user.PositionService; + import com.fr.intelli.record.MetricRegistry; + 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; + + /** + *
+ * + * + * @author Louis + * @since 1.0.0 + */ + public class PositionServiceKit extends PositionService { + private static volatile PositionServiceKit positionServiceKit = null; + + public PositionServiceKit() { + } + + public static PositionServiceKit getInstance() { + if (positionServiceKit == null) { + positionServiceKit = new PositionServiceKit(); + } + return positionServiceKit; + } + + public String addPosition(String id, String name, String desc) throws Exception { + Post post = (new Post()).id(id).name(name).creationType(ManualOperationType.KEY).lastOperationType(ManualOperationType.KEY).enable(true).description(desc); + AuthorityContext.getInstance().getPostController().add(post); + this.deleteSoftData(post.getName()); + MetricRegistry.getMetric().submit(OperateMessage.build("Dec-Module-User_Manager", "Dec-Post", name, "Dec-Log_Add")); + return post.getId(); + } + + private void deleteSoftData(String var1) throws Exception { + QueryCondition var2 = QueryFactory.create().addRestriction(RestrictionFactory.and(new Restriction[]{RestrictionFactory.eq("deletedName", var1), RestrictionFactory.eq("type", SoftRoleType.POST)})); + AuthorityContext.getInstance().getSoftDataController().remove(var2); + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/hdmu/kit/UserServiceKit.java b/src/main/java/com/fr/plugin/hdmu/kit/UserServiceKit.java new file mode 100644 index 0000000..a0bcfba --- /dev/null +++ b/src/main/java/com/fr/plugin/hdmu/kit/UserServiceKit.java @@ -0,0 +1,156 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: UserServiceKit + * Author: Louis + * Date: 2021/5/14 8:28 + */ + package com.fr.plugin.hdmu.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.User; + 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.v10.user.PositionService; + import com.fr.decision.webservice.v10.user.UserService; + import com.fr.json.JSONObject; + + import java.util.ArrayList; + import java.util.List; + + import static com.fr.plugin.hdmu.user.SsoUserManager.JOB_CODE; + import static com.fr.plugin.hdmu.user.SsoUserManager.ORG_CODE; + + /** + *
+ * + * + * @author Louis + * @since 1.0.0 + */ + public class UserServiceKit extends UserService { + public static final String USER_NAME = "uid"; + public static final String REAL_NAME = "userName"; + public static final String ENABLE = "status"; + public static final String EMAIL = "email"; + public static final String MOBILE = "mobile"; + public static final String PASSWORD = "appPwd"; + 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(USER_NAME)); + userBean.setRealName(account.getString(REAL_NAME)); + userBean.setEnable(StringKit.equals(account.getJSONArray("userJobAttr").getJSONObject(0).getString(ENABLE), "1")); + userBean.setEmail(account.getString(EMAIL)); + userBean.setMobile(account.getString(MOBILE)); + userBean.setPassword(TransmissionTool.defaultEncrypt(account.getString(PASSWORD))); + String departmentId; + String position; + try { + departmentId = account.getString(ORG_CODE); + position = account.getString(JOB_CODE); + } catch (Exception e) { + departmentId = StringKit.EMPTY; + position = StringKit.EMPTY; + } + if (StringKit.isNotBlank(departmentId)) { + List departmentPostIds = createDepartmentPostIds(departmentId, position); + userBean.setDepartmentPostIds(departmentPostIds); + } + return userBean; + } + + /** + * 转为部门职务组合 + * + * @param departmentPostId + * @param positionId + * @return + * @throws Exception + */ + private List createDepartmentPostIds(String departmentPostId, String positionId) throws Exception { + List departmentPostIds = new ArrayList<>(); + if (StringKit.isBlank(departmentPostId) || StringKit.equals(departmentPostId, "null")) { + return departmentPostIds; + } + if (StringKit.isNotBlank(positionId)) { + String positionName = PositionServiceKit.getInstance().getPostNameById(positionId); + List departmentPostBeanList = PositionService.getInstance().getPositionsUnderParentDepartment(getAdminUserId(), departmentPostId, positionName); + if (departmentPostBeanList == null || departmentPostBeanList.isEmpty()) { + try { + AuthorityContext.getInstance().getPostController().addPostToDepartment(positionId, departmentPostId); + } catch (Exception e) { + LogKit.info("sso-UserServiceKit-createDepartmentPostIds-addPostToDepartmentFailed-position:{}, departmentId:{}", positionId + positionName, departmentPostId); + LogKit.error(e.getMessage(), e); + } + } + departmentPostId = departmentPostId + "@@@" + positionId; + } + departmentPostIds.add(departmentPostId); + return departmentPostIds; + } + + /** + * 获取管理员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"; + } + + @Override + public void editUser(UserBean userBean) throws Exception { + super.editUser(userBean); + this.forbidUser(userBean.getId(), userBean.isEnable()); + this.updateUserDepartmentPost(this.getAdminUserId(), userBean); + } + + public UserBean updateUserBean(JSONObject account) throws Exception { + User user = UserService.getInstance().getUserByUserName(account.getString(USER_NAME)); + if (user == null) { + return null; + } + UserBean userBean = new UserBean(); + userBean.setId(user.getId()); + userBean.setUsername(user.getUserName()); + userBean.setRealName(account.getString(REAL_NAME)); + userBean.setEnable(StringKit.equals(account.getJSONArray("userJobAttr").getJSONObject(0).getString(ENABLE), "1")); + userBean.setEmail(account.getString(EMAIL)); + userBean.setMobile(account.getString(MOBILE)); + userBean.setPassword(TransmissionTool.defaultEncrypt(account.getString(PASSWORD))); + String departmentId; + String position; + try { + departmentId = account.getString(ORG_CODE); + position = account.getString(JOB_CODE); + } catch (Exception e) { + departmentId = StringKit.EMPTY; + position = StringKit.EMPTY; + } + if (StringKit.isNotBlank(departmentId)) { + List departmentPostIds = createDepartmentPostIds(departmentId, position); + userBean.setDepartmentPostIds(departmentPostIds); + } + return userBean; + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/hdmu/request/HttpAuthorizeBridge.java b/src/main/java/com/fr/plugin/hdmu/request/HttpAuthorizeBridge.java new file mode 100644 index 0000000..123ed8b --- /dev/null +++ b/src/main/java/com/fr/plugin/hdmu/request/HttpAuthorizeBridge.java @@ -0,0 +1,32 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: HttpAuthorizeBridge + * Author: Louis + * Date: 2021/8/24 13:55 + */ + package com.fr.plugin.hdmu.request; + + import com.fanruan.api.util.StringKit; + import com.fr.decision.fun.impl.AbstractHttpAuthorizeProvider; + import com.fr.security.SecurityToolbox; + + /** + *
+ * + * + * @author Louis + * @since 1.0.0 + */ + public class HttpAuthorizeBridge extends AbstractHttpAuthorizeProvider { + @Override + public Scope scope() { + return Scope.REPLACE; + } + + @Override + public boolean authorize(String inputUsername, String inputPassword, String savedPassword, String hashPassword) { + String encryptPwd = SecurityToolbox.sha256(SecurityToolbox.sha256(inputPassword)); + return StringKit.equalsIgnoreCase(encryptPwd, savedPassword); + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/hdmu/request/OAuthLogin.java b/src/main/java/com/fr/plugin/hdmu/request/OAuthLogin.java new file mode 100644 index 0000000..2bf50e3 --- /dev/null +++ b/src/main/java/com/fr/plugin/hdmu/request/OAuthLogin.java @@ -0,0 +1,220 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: OAuthLogin + * Author: Louis + * Date: 2021/3/30 22:09 + */ + package com.fr.plugin.hdmu.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.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.hdmu.config.SsoConfig; + import com.fr.plugin.hdmu.utils.HttpRequestUtil; + 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.net.URISyntaxException; + import java.util.HashMap; + import java.util.Map; + + /** + *
+ * + * + * @author Louis + * @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 SYSTEM_HEALTH = "/system/health"; + public static final String USER_SYN = "/syn"; + + public static final String CODE_URL = "/profile/oauth2/authorize"; + public static final String TOKEN_URL = "/profile/oauth2/accessToken"; + public static final String USER_URL = "/profile/oauth2/profile"; + public static final String CODE = "code"; + public static final String STATE = "sso"; + + private SsoConfig config; + + /** + * 过滤器名称 + * + * @return + */ + @Override + public String filterName() { + return "hdmuFilter"; + } + + /** + * 过滤规则 + * + * @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; + if (pathInfo.startsWith(REMOTE_DESIGN) || pathInfo.startsWith(LOGIN_OTHER) + || StringKit.equals(LOGIN_PATH, pathInfo) || pathInfo.startsWith(USER_SYN) + || pathInfo.startsWith(RESOURCES_PATH) || pathInfo.startsWith(LOGOUT_PATH) + || pathInfo.startsWith(SYSTEM_INFO) || pathInfo.startsWith(MATERIALS_MIN_JS_MAP) || pathInfo.startsWith(SYSTEM_HEALTH) + || pathInfo.startsWith(USER_LANGUAGE) || pathInfo.startsWith(FILE_PATH)) { + return true; + } + // 已登录 + if (LoginService.getInstance().isLogged(req)) { + return true; + } + String code = NetworkKit.getHTTPRequestParameter(req, CODE); + String state = NetworkKit.getHTTPRequestParameter(req, "state"); + LogKit.info("hdmu-OAuthLogin-operation-code:{}", code); + if (StringKit.isBlank(code)) { + res.sendRedirect(getLoginUrl()); + return false; + } + if (!StringKit.equalsIgnoreCase(state, STATE)) { + return true; + } + String accessToken = getAccessToken(code); + if (StringKit.isEmpty(accessToken)) { + res.sendRedirect(getLoginUrl()); + 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 Exception { + String userParam = HttpRequestUtil.getUserParam(this.config.getClientId(), this.config.getClientSecret(), accessToken); + String userRes = HttpRequestUtil.getResult(this.config.getUriBase() + USER_URL, userParam); + LogKit.info("hdmu-OAuthLogin-getUsername-userRes:{}", userRes); + return new JSONObject(userRes).getString("id"); + } + + /** + * 获取access_token + * + * @param code + * @return + * @throws Exception + */ + private String getAccessToken(String code) throws Exception { + String tokenParams = HttpRequestUtil.getAccessTokenParam(this.config.getClientId(), this.config.getClientSecret(), + this.config.getFrUri(), code); + String res = HttpRequestUtil.getResult(this.config.getUriBase() + TOKEN_URL, tokenParams); + LogKit.info("hdmu-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() { + 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()); + params.put("oauth_timestamp", String.valueOf(System.currentTimeMillis())); + params.put("state", STATE); + String loginUrl = buildUrl(url, params); + LogKit.info("hdmu-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.error("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/hdmu/user/SsoUserManager.java b/src/main/java/com/fr/plugin/hdmu/user/SsoUserManager.java new file mode 100644 index 0000000..64aef6b --- /dev/null +++ b/src/main/java/com/fr/plugin/hdmu/user/SsoUserManager.java @@ -0,0 +1,315 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: SsoUserManager + * Author: Louis + * Date: 2021/4/21 16:18 + */ + package com.fr.plugin.hdmu.user; + + import com.fanruan.api.decision.user.UserKit; + import com.fanruan.api.log.LogKit; + import com.fanruan.api.util.StringKit; + import com.fr.decision.authority.AuthorityContext; + import com.fr.decision.authority.data.Department; + import com.fr.decision.authority.data.Post; + 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.hdmu.config.SsoConfig; + import com.fr.plugin.hdmu.kit.DepartmentServiceKit; + import com.fr.plugin.hdmu.kit.PositionServiceKit; + import com.fr.plugin.hdmu.kit.UserServiceKit; + import com.fr.plugin.hdmu.utils.HttpRequestUtil; + + import java.io.IOException; + import java.util.Map; + + import static com.fr.plugin.hdmu.kit.UserServiceKit.USER_NAME; + import static com.fr.plugin.hdmu.utils.HttpRequestUtil.radomString; + + /** + *
+ * + * + * @author Louis + * @since 1.0.0 + */ + public final class SsoUserManager { + public static final String ORG_LIST_ALL = "/idm-api/dataSync/queryPagingOrgInfo"; + public static final String POSITION_LIST_ALL = "/idm-api/dataSync/queryPagingJobInfo"; + public static final String ACCOUNT_LIST = "/idm-api/dataSync/queryIncrePagingAccountInfo"; + public static final String UPDATE_IAM_ACCOUNT_STATUS = "/idm-api/dataSync/updateIamAccountStatus"; + public static final String ORG_UPDATE_STATUS = "updateStatus"; + public static final String ORG_CODE = "orgCode"; + public static final String PARENT_CODE = "parentCode"; + public static final String ORG_NAME = "orgName"; + public static final String JOB_CODE = "jobCode"; + public static final String JOB_NAME = "jobName"; + public static final String REQUEST_LOG_ID = "requestLogId"; + 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("hdmu-SsoUserManager-synDepartments-start"); + departmentSynLoop(); + LogKit.info("hdmu-SsoUserManager-synDepartments-end"); + LogKit.info("hdmu-SsoUserManager-synPositions-start"); + positionSynLoop(); + LogKit.info("hdmu-SsoUserManager-synPositions-end"); + LogKit.info("hdmu-SsoUserManager-synUsers-start"); + //每次同步1千重复20次 + for (int i = 0; i < 20; i++) { + userSynLoop(); + } + LogKit.info("hdmu-SsoUserManager-synUsers-end"); + } + + private void userSynLoop() { + JSONArray userList = getUserList(); + if (userList.isEmpty()) { + return; + } + // 同步用户信息 + JSONArray requestLogIds = JSONArray.create(); + String requestLogId; + for (int i = 0; i < userList.size(); i++) { + try { + JSONObject userJo = userList.optJSONObject(i); + requestLogId = userJo.getString(REQUEST_LOG_ID); + if (StringKit.isBlank(requestLogId)) { + continue; + } + userSynOperation(userJo); + requestLogIds.add((new JSONObject()).put(REQUEST_LOG_ID, requestLogId)); + } catch (Exception e) { + LogKit.error(e.getMessage(), e); + } + } + // 更新回调数据 + if (requestLogIds.isEmpty()) { + return; + } + updateIamAccountStatus(requestLogIds); + } + + /** + * 更新回调接口账户状态 + * + * @param requestLogIds + * @throws Exception + */ + private void updateIamAccountStatus(JSONArray requestLogIds) { + try { + JSONObject params = getAuthParams(); + params.put("requestlog_str", requestLogIds.encode()); + String response = HttpRequestUtil.post(this.config.getUriIam() + UPDATE_IAM_ACCOUNT_STATUS, params.encode()); + LogKit.info("hdmu-SsoUserManager-updateIamAccountStatus-response:{}", response); + } catch (Exception e) { + LogKit.error(e.getMessage(), e); + } + } + + /** + * 用户新增和更新操作 + * + * @param userJo + */ + private void userSynOperation(JSONObject userJo) throws Exception { + UserBean userBean; + if (UserKit.existUsername(userJo.getString(USER_NAME))) { + userBean = UserServiceKit.getInstance().updateUserBean(userJo); + if (userBean == null) { + return; + } + UserServiceKit.getInstance().editUser(userBean); + } else { + userBean = UserServiceKit.getInstance().createUserBean(userJo); + try { + UserService.getInstance().addUser(userBean); + } catch (Exception e) { + LogKit.error("hdmu-SsoUserManager-userSynOperation-Username:{}, RealName:{}, Mobile:{}, Email:{}", + userBean.getUsername(), userBean.getRealName(), userBean.getMobile(), userBean.getEmail()); + LogKit.error(e.getMessage(), e); + } + } + } + + /** + * 通过接口获取用户列表 + * + * @return + */ + private JSONArray getUserList() { + try { + JSONObject params = getAuthParams(); + params.put("pageSize", "1000"); + params.put("pageIndex", "1"); + LogKit.info("hdmu-SsoUserManager-getUserList-params:{}", params.encode()); + String response = HttpRequestUtil.post(this.config.getUriIam() + ACCOUNT_LIST, params.encode()); + LogKit.info("hdmu-SsoUserManager-getUserList-response:{}", response); + JSONObject responseJo = new JSONObject(response); + if (StringKit.equals(responseJo.getString("code"), "200")) { + return responseJo.getJSONArray("result"); + } + return JSONArray.create(); + } catch (Exception e) { + LogKit.error(e.getMessage(), e); + return JSONArray.create(); + } + } + + /** + * 按部门遍历子部门并同步人员信息 + * + * @throws Exception + */ + private void departmentSynLoop() throws Exception { + 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("hdmu-SsoUserManager-departmentSynOperation-departmentJo:{}", departmentJo.encode()); + String departmentId = departmentJo.getString(ORG_CODE); + if (StringKit.equals(departmentJo.getString(ORG_UPDATE_STATUS), "1")) { + String parentId = departmentJo.getString(PARENT_CODE); + parentId = DepartmentServiceKit.getInstance().changeRootId(parentId); + String depName = departmentJo.getString(ORG_NAME); + 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(ORG_UPDATE_STATUS), "0")) { + DepartmentServiceKit.getInstance().deleteDepartment(departmentId); + } + } + + /** + * 通过接口获取部门列表 + * + * @return + * @throws IOException + */ + private JSONArray getDepartmentList() throws Exception { + JSONObject params = getAuthParams(); + String response = HttpRequestUtil.post(this.config.getUriIam() + ORG_LIST_ALL, params.encode()); + LogKit.info("hdmu-SsoUserManager-getDepartmentList-response:{}", response); + JSONObject responseJo = new JSONObject(response); + if (StringKit.equals(responseJo.getString("code"), "200")) { + return responseJo.getJSONArray("result"); + } + return JSONArray.create(); + } + + /** + * 岗位信息同步 + * + * @throws Exception + */ + private void positionSynLoop() throws Exception { + JSONArray positionList = getPositionList(); + for (int i = 0; i < positionList.size(); i++) { + try { + positionSynOperation(positionList.optJSONObject(i)); + } catch (Exception e) { + LogKit.error(e.getMessage(), e); + } + } + } + + private void positionSynOperation(JSONObject positionJo) throws Exception { + LogKit.info("hdmu-SsoUserManager-positionSynOperation-positionJo:{}", positionJo.encode()); + String positionId = positionJo.getString(JOB_CODE); + String positionName = positionJo.getString(JOB_NAME); + if (StringKit.equals(positionJo.getString(ORG_UPDATE_STATUS), "0")) { + PositionServiceKit.getInstance().deletePosition(positionId); + return; + } + if (StringKit.equals(positionJo.getString(ORG_UPDATE_STATUS), "1")) { + Post post = AuthorityContext.getInstance().getPostController().getById(positionId); + if (post == null) { + PositionServiceKit.getInstance().addPosition(positionId, positionName, positionName); + } else { + PositionServiceKit.getInstance().updatePosition(positionId, positionName, positionName); + } + } + } + + /** + * 通过接口获取岗位列表 + * + * @return + * @throws IOException + */ + private JSONArray getPositionList() throws Exception { + JSONObject params = getAuthParams(); + String response = HttpRequestUtil.post(this.config.getUriIam() + POSITION_LIST_ALL, params.encode()); + LogKit.info("hdmu-SsoUserManager-getPositionList-response:{}", response); + JSONObject responseJo = new JSONObject(response); + if (StringKit.equals(responseJo.getString("code"), "200")) { + return responseJo.getJSONArray("result"); + } + return JSONArray.create(); + } + + /** + * 产生IAM sign + * + * @return + */ + private String getIamSign(String nonceStr, String timestamp) { + Map params = HttpRequestUtil.getCommonAuthParamClient(this.config.getClientId(), this.config.getClientSecret(), nonceStr, timestamp); + return HttpRequestUtil.getSign(params, this.config.getAppIamKey() + this.config.getClientSecret()); + } + + /** + * 请求认证参数集合 + * + * @return + */ + private JSONObject getAuthParams() { + JSONObject params = JSONObject.create(); + String nonceStr = radomString(); + String timestamp = String.valueOf(System.currentTimeMillis()); + params.put("client_id", this.config.getClientId()); + params.put("client_secret", this.config.getClientSecret()); + params.put("nonce_str", nonceStr); + params.put("timestamp", timestamp); + params.put("sign", getIamSign(nonceStr, timestamp)); + return params; + } + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/hdmu/utils/AESOperator.java b/src/main/java/com/fr/plugin/hdmu/utils/AESOperator.java new file mode 100644 index 0000000..c17af86 --- /dev/null +++ b/src/main/java/com/fr/plugin/hdmu/utils/AESOperator.java @@ -0,0 +1,114 @@ + /* + * Copyright (C), 2018-2021 + * Project: starter + * FileName: AESOperator + * Author: Louis + * Date: 2021/8/6 14:31 + */ + package com.fr.plugin.hdmu.utils; + + import com.fr.base.Base64; + + import javax.crypto.Cipher; + import javax.crypto.spec.IvParameterSpec; + import javax.crypto.spec.SecretKeySpec; + + /** + *
+ * + * + * @author Louis + * @since 1.0.0 + */ + public class AESOperator { + + private String sKey = "xxx";//key,可自行修改 + private String ivParameter = "xxx";//偏移量,可自行修改 + private static AESOperator instance = null; + + private AESOperator() { + + } + + public static AESOperator getInstance() { + if (instance == null) + instance = new AESOperator(); + return instance; + } + + public static String Encrypt(String encData, String secretKey, String vector) throws Exception { + + if (secretKey == null) { + return null; + } + if (secretKey.length() != 16) { + return null; + } + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + byte[] raw = secretKey.getBytes(); + SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); + IvParameterSpec iv = new IvParameterSpec(vector.getBytes());// 使用CBC模式,需要一个向量iv,可增加加密算法的强度 + cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv); + byte[] encrypted = cipher.doFinal(encData.getBytes("utf-8")); + return Base64.encode(encrypted);// 此处使用BASE64做转码。 + } + + + // 加密 + public String encrypt(String sSrc) throws Exception { + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + byte[] raw = sKey.getBytes(); + SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); + IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes());// 使用CBC模式,需要一个向量iv,可增加加密算法的强度 + cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv); + byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8")); + return Base64.encode(encrypted);// 此处使用BASE64做转码。 + } + + // 解密 + public String decrypt(String sSrc) throws Exception { + try { + byte[] raw = sKey.getBytes("ASCII"); + SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes()); + cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv); + byte[] encrypted1 = Base64.decode(sSrc);// 先用base64解密 + byte[] original = cipher.doFinal(encrypted1); + String originalString = new String(original, "utf-8"); + return originalString; + } catch (Exception ex) { + return null; + } + } + + public String decrypt(String sSrc, String key, String ivs) throws Exception { + try { + byte[] raw = key.getBytes("ASCII"); + SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + IvParameterSpec iv = new IvParameterSpec(ivs.getBytes()); + cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv); + byte[] encrypted1 = Base64.decode(sSrc);// 先用base64解密 + byte[] original = cipher.doFinal(encrypted1); + String originalString = new String(original, "utf-8"); + return originalString; + } catch (Exception ex) { + return null; + } + } + + public static String encodeBytes(byte[] bytes) { + StringBuffer strBuf = new StringBuffer(); + + for (int i = 0; i < bytes.length; i++) { + strBuf.append((char) (((bytes[i] >> 4) & 0xF) + ((int) 'a'))); + strBuf.append((char) (((bytes[i]) & 0xF) + ((int) 'a'))); + } + + return strBuf.toString(); + } + + + + } \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/hdmu/utils/HttpRequestUtil.java b/src/main/java/com/fr/plugin/hdmu/utils/HttpRequestUtil.java new file mode 100644 index 0000000..3079020 --- /dev/null +++ b/src/main/java/com/fr/plugin/hdmu/utils/HttpRequestUtil.java @@ -0,0 +1,487 @@ +package com.fr.plugin.hdmu.utils; + +import com.fanruan.api.util.StringKit; +import com.fr.plugin.hdmu.config.SsoConfig; +import com.fr.third.org.apache.commons.codec.digest.DigestUtils; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSession; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.util.*; + +public class HttpRequestUtil { + public static final String CODE = "code"; + public static final String REFRESH_TOKEN = "refresh_token"; + public static final String AUTHORIZATION_CODE = "authorization_code"; + public static final String APP_SECRET_KEY = "*******"; // 密钥,向IAM申请 + + + static class miTM implements javax.net.ssl.TrustManager, + javax.net.ssl.X509TrustManager { + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return null; + } + + public boolean isServerTrusted( + java.security.cert.X509Certificate[] certs) { + return true; + } + + public boolean isClientTrusted( + java.security.cert.X509Certificate[] certs) { + return true; + } + + public void checkServerTrusted( + java.security.cert.X509Certificate[] certs, String authType) + throws java.security.cert.CertificateException { + return; + } + + public void checkClientTrusted( + java.security.cert.X509Certificate[] certs, String authType) + throws java.security.cert.CertificateException { + return; + } + } + + + /** + * 根据请求的URL是https还是http请求数据 + * + * @param sendUrl + * @param param + * @return + * @throws Exception + */ + public static String getResult(String sendUrl, String param) + throws Exception { + if (sendUrl.startsWith("https")) { + return getResultByHttps(sendUrl, param); + } + return getResultByHttp(sendUrl, param); + } + + private static String getResultByHttps(String sendUrl, String param) + throws NoSuchAlgorithmException, KeyManagementException, + IOException { + javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1]; + javax.net.ssl.TrustManager tm = new miTM(); + trustAllCerts[0] = tm; + // javax.net.ssl.SSLContext sc = + // javax.net.ssl.SSLContext.getInstance("SSL"); + javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext + .getInstance("SSLv3"); + + sc.init(null, trustAllCerts, null); + javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc + .getSocketFactory()); + + HostnameVerifier ignoreHostnameVerifier = new HostnameVerifier() { + public boolean verify(String arg0, SSLSession arg1) { + return true; + } + }; + + HttpsURLConnection.setDefaultHostnameVerifier(ignoreHostnameVerifier); + + OutputStream out = null; + BufferedReader reader = null; + String result = ""; + URL url = null; + HttpsURLConnection conn = null; + try { + url = new URL(sendUrl); + conn = (HttpsURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-type", + "application/x-www-form-urlencoded"); + // 必须设置false,否则会自动redirect到重定向后的地址 + conn.setInstanceFollowRedirects(false); + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setRequestProperty("Charset", "UTF-8"); + conn.setRequestProperty("Connection", "Keep-Alive"); + conn.setConnectTimeout(15000); + conn.setReadTimeout(15000); + conn.connect(); + out = conn.getOutputStream(); + out.write(param.getBytes()); + InputStream input = conn.getInputStream(); + reader = new BufferedReader(new InputStreamReader(input, "UTF-8")); + String line = ""; + StringBuffer sb = new StringBuffer(); + while ((line = reader.readLine()) != null) { + sb.append(line); + } + result = sb.toString(); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } finally { + if (conn != null) { + conn.disconnect(); + } + if (out != null) { + out.close(); + } + if (reader != null) { + reader.close(); + } + } + return result; + } + + private static String getResultByHttp(String sendUrl, String param) + throws NoSuchAlgorithmException, KeyManagementException, + IOException { + + HttpURLConnection conn = null; + OutputStream out = null; + BufferedReader reader = null; + String result = ""; + try { + + URL url = new URL(sendUrl); + conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setRequestProperty("Charset", "UTF-8"); + conn.setRequestProperty("Connection", "Keep-Alive"); + conn.setConnectTimeout(15000); + conn.setReadTimeout(150000); + conn.connect(); + out = conn.getOutputStream(); + out.write(param.getBytes()); + out.flush(); + out.close(); + InputStream input = conn.getInputStream(); + reader = new BufferedReader(new InputStreamReader(input, "UTF-8")); + String line; + StringBuffer sb = new StringBuffer(); + while ((line = reader.readLine()) != null) { + sb.append(line); + } + result = sb.toString(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (reader != null) { + reader.close(); + } + out.close(); + conn.disconnect(); + } + + return result; + } + + public static String getSign(Map params, String secret) { + String sign = ""; + StringBuilder sb = new StringBuilder(); + //排序 + Set keyset = params.keySet(); + TreeSet sortSet = new TreeSet(); + sortSet.addAll(keyset); + Iterator it = sortSet.iterator(); + //加密字符串 + while (it.hasNext()) { + String key = it.next(); + String value = params.get(key); + sb.append(key).append(value); + } + sb.append("appkey").append(secret); + try { + sign = DigestUtils.md5Hex(sb.toString()).toUpperCase(); + } catch (Exception e) { + } + return sign; + } + + /** + * 组装获取用户api参数,含签名 + * + * @param client_ID + * @param client_secret + * @param token + * @return + */ + public static String getUserParam(String client_ID, String client_secret, String token) { + String nonce_str = radomString(); +// String appkey = HttpRequestUtil.APP_SECRET_KEY; + String appkey = SsoConfig.getInstance().getAppID(); + long timestamp = System.currentTimeMillis(); + + Map params = new HashMap(); + + params.put("client_id", client_ID); + params.put("client_secret", client_secret); + params.put("nonce_str", nonce_str); + params.put("oauth_timestamp", String.valueOf(timestamp)); + if (token.contains("access_token=")) { + int strStartIndex = token.indexOf("access_token="); + int strEndIndex = token.indexOf("&expires"); + String access_token = token.substring(strStartIndex, strEndIndex).substring("access_token=".length()); + params.put("access_token", access_token); + + } else { + params.put("access_token", token); + } + String sign = getSign(params, appkey + client_secret); + StringBuffer tokenParam = new StringBuffer(); + for (String key : params.keySet()) { + if (tokenParam.length() == 0) { + tokenParam.append(key).append("=").append(params.get(key)); + } else { + tokenParam.append("&").append(key).append("=").append(params.get(key)); + } + + } + tokenParam.append("&sign=").append(sign); + return tokenParam.toString(); + } + + /** + * 组装检查心跳API参数含签名 + * + * @param client_ID + * @param client_secret + * @return + */ + public static String getIAMServiceParam(String client_ID, String client_secret) { + String nonce_str = radomString(); +// String appkey = HttpRequestUtil.APP_SECRET_KEY; + String appkey = SsoConfig.getInstance().getAppID(); + long timestamp = System.currentTimeMillis(); + + Map params = new HashMap(); + + params.put("client_id", client_ID); + params.put("client_secret", client_secret); + params.put("nonce_str", nonce_str); + params.put("oauth_timestamp", String.valueOf(timestamp)); + String sign = getSign(params, appkey + client_secret); + StringBuffer tokenParam = new StringBuffer(); + for (String key : params.keySet()) { + if (tokenParam.length() == 0) { + tokenParam.append(key).append("=").append(params.get(key)); + } else { + tokenParam.append("&").append(key).append("=").append(params.get(key)); + } + + } + tokenParam.append("&sign=").append(sign); + return tokenParam.toString(); + } + + public static String radomString() { + String result = ""; + for (int i = 0; i < 10; i++) { + int intVal = (int) (Math.random() * 26 + 97); + result = result + (char) intVal; + } + return result; + } + + /** + * 组装获取token api参数 含签名 + * + * @param client_ID + * @param client_secret + * @param redirect_uri + * @param code + * @return + */ + public static String getAccessTokenParam(String client_ID, String client_secret, String redirect_uri, String code) { + String nonce_str = radomString(); +// String appkey = HttpRequestUtil.APP_SECRET_KEY; + String appkey = SsoConfig.getInstance().getAppID(); + long timestamp = System.currentTimeMillis(); + + Map params = new HashMap(); + + params.put("client_id", client_ID); + params.put("client_secret", client_secret); + params.put("nonce_str", nonce_str); + params.put("oauth_timestamp", String.valueOf(timestamp)); + params.put("code", code); + params.put("redirect_uri", redirect_uri); + params.put("grant_type", "authorization_code"); + String sign = getSign(params, appkey + client_secret); + StringBuffer tokenParam = new StringBuffer(); + for (String key : params.keySet()) { + if (tokenParam.length() == 0) { + tokenParam.append(key).append("=").append(params.get(key)); + } else { + tokenParam.append("&").append(key).append("=").append(params.get(key)); + } + + } + tokenParam.append("&sign=").append(sign); + return tokenParam.toString(); + } + + + public static Map getCommonAuthParamClient(String client_ID, String client_secret, String nonce_str, String timestamp) { + + Map params = new HashMap(); + params.put("client_id", client_ID); + params.put("client_secret", client_secret); + params.put("nonce_str", nonce_str); + params.put("timestamp", timestamp); + return params; + } + + + public static String postGeneralUrl(String generalUrl, String contentType, + String params, String encoding, String hander) throws Exception { + URL url = new URL(generalUrl); + // 打开和URL之间的连接 + HttpURLConnection connection = null; + String result = ""; + OutputStream out = null; + BufferedReader in = null; + try { + connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + // 设置通用的请求属性 + connection.setRequestProperty("Content-Type", contentType); + connection.setRequestProperty("Connection", "Keep-Alive"); + connection.setUseCaches(false); + connection.setDoOutput(true); + connection.setDoInput(true); + connection.setConnectTimeout(5000); + if (hander != null) { + if (hander.equals("1")) { + connection.setRequestProperty("SOAPAction", ""); + } else { + connection.setRequestProperty("Authorization", hander); + } + + } + + // 得到请求的输出流对象 + out = connection.getOutputStream(); + out.write(params.getBytes(encoding)); + out.flush(); + out.close(); + + // 建立实际的连接 + connection.connect(); + in = new BufferedReader(new InputStreamReader(connection + .getInputStream(), encoding)); + result = ""; + String getLine; + while ((getLine = in.readLine()) != null) { + result += getLine; + } + in.close(); + } catch (Exception e) { + return e.getMessage(); + } finally { + if (connection != null) { + connection.disconnect(); + } + if (out != null) { + out.close(); + } + if (in != null) { + in.close(); + } + } + return result; + } + + public static String postGeneralUrlByHttps(String generalUrl, String contentType, + String params, String encoding, String hander) throws Exception { + URL url = new URL(generalUrl); + javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1]; + javax.net.ssl.TrustManager tm = new miTM(); + trustAllCerts[0] = tm; + // javax.net.ssl.SSLContext sc = + // javax.net.ssl.SSLContext.getInstance("SSL"); + javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext + .getInstance("SSLv3"); + + sc.init(null, trustAllCerts, null); + javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc + .getSocketFactory()); + + HostnameVerifier ignoreHostnameVerifier = new HostnameVerifier() { + public boolean verify(String arg0, SSLSession arg1) { + return true; + } + }; + + HttpsURLConnection.setDefaultHostnameVerifier(ignoreHostnameVerifier); + + OutputStream out = null; + BufferedReader reader = null; + String result = ""; + HttpsURLConnection conn = null; + try { + conn = (HttpsURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-type", contentType); + // 必须设置false,否则会自动redirect到重定向后的地址 + conn.setInstanceFollowRedirects(false); + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setRequestProperty("Charset", encoding); + conn.setRequestProperty("Connection", "Keep-Alive"); + conn.setConnectTimeout(5000); + if (hander != null) { + if (hander.equals("1")) { + conn.setRequestProperty("SOAPAction", ""); + } else { + conn.setRequestProperty("Authorization", hander); + } + + } + conn.connect(); + out = conn.getOutputStream(); + out.write(params.getBytes("UTF-8")); + InputStream input = conn.getInputStream(); + reader = new BufferedReader(new InputStreamReader(input, encoding)); + String line = ""; + StringBuffer sb = new StringBuffer(); + while ((line = reader.readLine()) != null) { + sb.append(line); + } + result = sb.toString(); + } catch (Exception e) { + return e.getMessage(); + } finally { + if (conn != null) { + conn.disconnect(); + } + if (out != null) { + out.close(); + } + if (reader != null) { + reader.close(); + } + } + return result; + } + + public static String post(String requestUrl, String params) throws Exception { + String url = requestUrl; + if (url.startsWith("https")) { + return HttpRequestUtil.postGeneralUrlByHttps(url, "application/json", params, "UTF-8", null); + + } + return HttpRequestUtil.postGeneralUrl(url, "application/json", params, "UTF-8", null); + } + + + +} diff --git a/src/main/resources/com/fr/plugin/hdmu/locale/lang.properties b/src/main/resources/com/fr/plugin/hdmu/locale/lang.properties new file mode 100644 index 0000000..372b6e3 --- /dev/null +++ b/src/main/resources/com/fr/plugin/hdmu/locale/lang.properties @@ -0,0 +1,18 @@ +Plugin-hdmu=Sso Plugin +Plugin-hdmu_Group=Sso Plugin +Plugin-hdmu_Config_ClientId=Client Id +Plugin-hdmu_Config_ClientId_Description=Client Id +Plugin-hdmu_Config_ClientSecret=Client Secret +Plugin-hdmu_Config_ClientSecret_Description=Client Secret +Plugin-hdmu_Config_UriBase=Uri Base +Plugin-hdmu_Config_UriBase_Description=Uri Base +Plugin-hdmu_Config_FrUri=FR Uri +Plugin-hdmu_Config_FrUri_Description=FR Uri +Plugin-hdmu_Config_CronCondition=Cron Condition +Plugin-hdmu_Config_CronCondition_Description=Cron Condition +Plugin-hdmu_Config_AppID=SSO App ID +Plugin-hdmu_Config_AppID_Description=SSO App ID +Plugin-hdmu_Config_UriIam=Uri Iam +Plugin-hdmu_Config_UriIam_Description=Uri Iam +Plugin-hdmu_Config_AppIamKey=IAM\u7533\u8BF7\u88AB\u63A8App ID +Plugin-hdmu_Config_AppIamKey_Description=idm\u5E94\u7528\u914D\u7F6E\u7533\u8BF7\u7684\u88AB\u63A8App ID \ No newline at end of file diff --git a/src/main/resources/com/fr/plugin/hdmu/locale/lang_zh_CN.properties b/src/main/resources/com/fr/plugin/hdmu/locale/lang_zh_CN.properties new file mode 100644 index 0000000..afef9c0 --- /dev/null +++ b/src/main/resources/com/fr/plugin/hdmu/locale/lang_zh_CN.properties @@ -0,0 +1,18 @@ +Plugin-hdmu=\u5355\u70B9\u767B\u9646\u63D2\u4EF6 +Plugin-hdmu_Group=\u5355\u70B9\u767B\u9646\u63D2\u4EF6 +Plugin-hdmu_Config_ClientId=\u5E94\u7528\u6CE8\u518CID +Plugin-hdmu_Config_ClientId_Description=\u5E94\u7528\u6CE8\u518CID +Plugin-hdmu_Config_ClientSecret=\u5E94\u7528\u6CE8\u518C\u5BC6\u7801 +Plugin-hdmu_Config_ClientSecret_Description=\u5E94\u7528\u6CE8\u518C\u5BC6\u7801 +Plugin-hdmu_Config_UriBase=\u5355\u70B9\u63A5\u53E3 +Plugin-hdmu_Config_UriBase_Description=\u5355\u70B9\u63A5\u53E3 +Plugin-hdmu_Config_FrUri=\u5E06\u8F6F\u7CFB\u7EDFurl +Plugin-hdmu_Config_FrUri_Description=\u5E06\u8F6F\u7CFB\u7EDFurl +Plugin-hdmu_Config_CronCondition=\u5B9A\u65F6\u4EFB\u52A1\u8868\u8FBE\u5F0F +Plugin-hdmu_Config_CronCondition_Description=\u5B9A\u65F6\u4EFB\u52A1\u8868\u8FBE\u5F0F +Plugin-hdmu_Config_AppID=\u5355\u70B9\u767B\u9646App Key +Plugin-hdmu_Config_AppID_Description=\u5355\u70B9\u767B\u9646App Key +Plugin-hdmu_Config_UriIam=IAM\u540C\u6B65\u63A5\u53E3 +Plugin-hdmu_Config_UriIam_Description=IAM\u540C\u6B65\u63A5\u53E3 +Plugin-hdmu_Config_AppIamKey=IAM\u7533\u8BF7\u88AB\u63A8App Key +Plugin-hdmu_Config_AppIamKey_Description=idm\u5E94\u7528\u914D\u7F6E\u7533\u8BF7\u7684\u88AB\u63A8App Key \ No newline at end of file