Jianye.Wang
2 years ago
38 changed files with 3211 additions and 1 deletions
@ -1,3 +1,10 @@
|
||||
# com.fr.plugin.decision.integration |
||||
|
||||
登录集成插件 |
||||
登录集成插件 |
||||
|
||||
# 问题记录 |
||||
Refused to execute script from ‘XXXX’ because its MIME type (‘text/html’) is not executable, and strict MIME type checking is enabled. 响应头中增加了X-Content-Type-Options:nosniff字段,导致跨域接口异常。 |
||||
解决方案:响应头中新增 content-type: application/javascript; charset=utf-8 (https://www.freesion.com/article/64191377003/) |
||||
|
||||
# 插件说明 |
||||
https://www.showdoc.com.cn/1435897295186406/7012059782236943 |
@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
||||
<plugin> |
||||
<id>com.fr.plugin.decision.integration</id> |
||||
<name><![CDATA[登录集成插件]]></name> |
||||
<active>yes</active> |
||||
<hidden>no</hidden> |
||||
<version>1.0.20</version> |
||||
<env-version>10.0~</env-version> |
||||
<jartime>2019-1-31</jartime> |
||||
<vendor>JianYe.Wang</vendor> |
||||
<description><![CDATA[登录集成插件]]></description> |
||||
<change-notes> |
||||
<![CDATA[ |
||||
[2021-06-01]<br/>1.0.0:调整插件结构<br/> |
||||
[2021-06-08]<br/>1.0.1:优化插件配置项<br/> |
||||
[2021-07-07]<br/>1.0.2:跨域登录接口新增响应头content-type规避nosniff的限制<br/> |
||||
[2021-08-03]<br/>1.0.3:创建用户时部门为空<br/> |
||||
[2021-08-18]<br/>1.0.4:去除角色id的传递,统一通过角色名来匹配<br/> |
||||
[2021-08-24]<br/>1.0.5:角色添加逻辑异常修复<br/> |
||||
[2021-10-15]<br/>1.0.8:新增URL参数单点登录校验<br/> |
||||
[2021-11-15]<br/>1.0.12:去除管理员账号的权限处理<br/> |
||||
[2021-12-06]<br/>1.0.13/15:添加用户类型配置参数<br/> |
||||
[2021-12-10]<br/>1.0.14:移动端单点场景时重定向至携带fine_auth_token的地址<br/> |
||||
[2022-01-04]<br/>1.0.16:移动端跨域登录与RequestSsoFilter移动端重定向的冲突/部门创建支持名称拼接<br/> |
||||
[2022-02-22]<br/>1.0.17:将启动设计器按钮添加平台中/代码接口优化<br/> |
||||
[2022-03-23]<br/>1.0.18:新增接口,单点场景可直接访问固定地址打开URL来唤醒设计器;key默认值设置为uuid<br/> |
||||
[2022-04-01]<br/>1.0.19:调整WebResourceProvider接口;新增配置远程权限控制是否开启;调整用户平台类型添加逻辑<br/> |
||||
[2022-04-11]<br/>1.0.20:去除自定义登录页配置选项<br/> |
||||
]]> |
||||
</change-notes> |
||||
<function-recorder class="com.fr.plugin.decision.integration.ControllerBridgeImpl"/> |
||||
<lifecycle-monitor class="com.fr.plugin.decision.integration.LifecycleMonitorImpl"/> |
||||
<extra-decision> |
||||
<ControllerRegisterProvider class="com.fr.plugin.decision.integration.ControllerBridgeImpl"/> |
||||
<EmbedRequestFilterProvider class="com.fr.plugin.decision.integration.filter.RemoteFilter"/> |
||||
<EmbedRequestFilterProvider class="com.fr.plugin.decision.integration.filter.TplParaCheckFilter"/> |
||||
<EmbedRequestFilterProvider class="com.fr.plugin.decision.integration.filter.RequestSsoFilter"/> |
||||
<WebResourceProvider class="com.fr.plugin.decision.integration.resource.PluginConfigWebResourceImpl"/> |
||||
<WebResourceProvider class="com.fr.plugin.decision.integration.resource.WebStartWebResourceImpl"/> |
||||
</extra-decision> |
||||
</plugin> |
@ -0,0 +1,23 @@
|
||||
package com.fr.plugin.decision.integration; |
||||
|
||||
import com.fr.decision.fun.impl.AbstractControllerRegisterProvider; |
||||
import com.fr.plugin.context.PluginContexts; |
||||
import com.fr.plugin.decision.integration.controller.IntegratedController; |
||||
import com.fr.plugin.decision.integration.service.IntegrateAuthService; |
||||
import com.fr.plugin.transform.ExecuteFunctionRecord; |
||||
import com.fr.plugin.transform.FunctionRecorder; |
||||
import com.fr.stable.fun.Authorize; |
||||
|
||||
@Authorize(callSignKey = "com.fr.plugin.decision.integration") |
||||
@FunctionRecorder |
||||
public class ControllerBridgeImpl extends AbstractControllerRegisterProvider { |
||||
@ExecuteFunctionRecord |
||||
@Override |
||||
public Class<?>[] getControllers() { |
||||
if (PluginContexts.currentContext().isAvailable()) { |
||||
return new Class[]{IntegratedController.class}; |
||||
} else { |
||||
return new Class[0]; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,24 @@
|
||||
package com.fr.plugin.decision.integration; |
||||
|
||||
import com.fr.plugin.context.PluginContext; |
||||
import com.fr.plugin.decision.integration.config.IntegrateConf; |
||||
import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor; |
||||
|
||||
/** |
||||
* @Author JianYe.Wang |
||||
* @Data 2022/2/22 15:54 |
||||
* @Description TODO |
||||
* @Version 10.0 |
||||
**/ |
||||
public class LifecycleMonitorImpl extends AbstractPluginLifecycleMonitor { |
||||
|
||||
@Override |
||||
public void afterRun(PluginContext pluginContext) { |
||||
IntegrateConf.getInstance(); |
||||
} |
||||
|
||||
@Override |
||||
public void beforeStop(PluginContext pluginContext) { |
||||
|
||||
} |
||||
} |
@ -0,0 +1,54 @@
|
||||
package com.fr.plugin.decision.integration.bean; |
||||
|
||||
import com.fr.decision.webservice.bean.BaseBean; |
||||
|
||||
@Deprecated |
||||
public class TplInfoBean extends BaseBean { |
||||
|
||||
private String menuId; |
||||
private String title; |
||||
private String url; |
||||
private String pmenuId; |
||||
|
||||
public TplInfoBean() { |
||||
} |
||||
|
||||
public TplInfoBean(String menuId, String title, String url, String pmenuId) { |
||||
this.menuId = menuId; |
||||
this.title = title; |
||||
this.url = url; |
||||
this.pmenuId = pmenuId; |
||||
} |
||||
|
||||
public String getMenuId() { |
||||
return menuId; |
||||
} |
||||
|
||||
public void setMenuId(String menuId) { |
||||
this.menuId = menuId; |
||||
} |
||||
|
||||
public String getTitle() { |
||||
return title; |
||||
} |
||||
|
||||
public void setTitle(String title) { |
||||
this.title = title; |
||||
} |
||||
|
||||
public String getUrl() { |
||||
return url; |
||||
} |
||||
|
||||
public void setUrl(String url) { |
||||
this.url = url; |
||||
} |
||||
|
||||
public String getPmenuId() { |
||||
return pmenuId; |
||||
} |
||||
|
||||
public void setPmenuId(String pmenuId) { |
||||
this.pmenuId = pmenuId; |
||||
} |
||||
} |
@ -0,0 +1,25 @@
|
||||
package com.fr.plugin.decision.integration.bean.user; |
||||
|
||||
import com.fr.decision.webservice.bean.BaseBean; |
||||
|
||||
public class NamedBean extends BaseBean { |
||||
|
||||
private String name; |
||||
private String id; |
||||
|
||||
public String getName() { |
||||
return name; |
||||
} |
||||
|
||||
public void setName(String name) { |
||||
this.name = name; |
||||
} |
||||
|
||||
public String getId() { |
||||
return id; |
||||
} |
||||
|
||||
public void setId(String id) { |
||||
this.id = id; |
||||
} |
||||
} |
@ -0,0 +1,45 @@
|
||||
package com.fr.plugin.decision.integration.bean.user; |
||||
|
||||
import com.fr.decision.webservice.bean.BaseBean; |
||||
|
||||
import java.util.List; |
||||
|
||||
public class UserInfoBean extends BaseBean { |
||||
|
||||
private String username; |
||||
private NamedBean department; |
||||
private List<String> roles; |
||||
private List<Integer> platformType; |
||||
|
||||
public String getUsername() { |
||||
return username; |
||||
} |
||||
|
||||
public void setUsername(String username) { |
||||
this.username = username; |
||||
} |
||||
|
||||
public NamedBean getDepartment() { |
||||
return department; |
||||
} |
||||
|
||||
public void setDepartment(NamedBean department) { |
||||
this.department = department; |
||||
} |
||||
|
||||
public List<String> getRoles() { |
||||
return roles; |
||||
} |
||||
|
||||
public void setRoles(List<String> roles) { |
||||
this.roles = roles; |
||||
} |
||||
|
||||
public List<Integer> getPlatformType() { |
||||
return platformType; |
||||
} |
||||
|
||||
public void setPlatformType(List<Integer> platformType) { |
||||
this.platformType = platformType; |
||||
} |
||||
} |
@ -0,0 +1,273 @@
|
||||
package com.fr.plugin.decision.integration.config; |
||||
|
||||
import com.fr.cert.token.Jwts; |
||||
import com.fr.cert.token.SignatureAlgorithm; |
||||
import com.fr.config.ConfigContext; |
||||
import com.fr.config.DefaultConfiguration; |
||||
import com.fr.config.Identifier; |
||||
import com.fr.config.holder.Conf; |
||||
import com.fr.config.holder.factory.Holders; |
||||
import com.fr.config.utils.ValueReader; |
||||
import com.fr.config.utils.ValueWriter; |
||||
import com.fr.decision.base.util.UUIDUtil; |
||||
import com.fr.json.JSONObject; |
||||
import com.fr.plugin.decision.integration.config.strategy.CreateDepartmentStrategy; |
||||
import com.fr.plugin.decision.integration.config.strategy.CreatePwdStrategy; |
||||
import com.fr.plugin.decision.integration.config.strategy.user.impl.ContainDepRoleStrategy; |
||||
import com.fr.plugin.decision.integration.config.strategy.user.impl.OnlyUserStrategy; |
||||
import com.fr.plugin.decision.integration.config.strategy.user.CreateUserStrategy; |
||||
import com.fr.plugin.decision.integration.utils.AESUtils; |
||||
import com.fr.plugin.decision.integration.utils.Constants; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.third.fasterxml.jackson.annotation.JsonIgnoreProperties; |
||||
|
||||
import java.util.Base64; |
||||
import java.util.Date; |
||||
import java.util.HashMap; |
||||
|
||||
@JsonIgnoreProperties({"id", "data", "classInfo", "nameSpace"}) |
||||
public class IntegrateConf extends DefaultConfiguration { |
||||
private static volatile IntegrateConf configuration = null; |
||||
|
||||
public static IntegrateConf getInstance() { |
||||
if (null == configuration) { |
||||
configuration = ConfigContext.getConfigInstance(IntegrateConf.class); |
||||
} |
||||
return configuration; |
||||
} |
||||
|
||||
@Identifier("jwtKey") |
||||
private Conf<String> jwtKey = Holders.simple(UUIDUtil.generate()); |
||||
|
||||
@Identifier("createUserTurnOn") |
||||
private Conf<Boolean> createUserTurnOn = Holders.simple(false); |
||||
|
||||
@Identifier("userStrategy") |
||||
private Conf<CreateUserStrategy> userStrategy = Holders.obj(new OnlyUserStrategy(), CreateUserStrategy.class); |
||||
|
||||
@Identifier("paraCheckTurnOn") |
||||
private Conf<Boolean> paraCheckTurnOn = Holders.simple(false); |
||||
|
||||
@Identifier("paraCheckUrl") |
||||
private Conf<String> paraCheckUrl = Holders.simple(StringUtils.EMPTY); |
||||
|
||||
@Identifier("remoteTokenAuth") |
||||
private Conf<Boolean> remoteTokenAuth = Holders.simple(true); |
||||
|
||||
@Identifier("aesEncryptSubject") |
||||
private Conf<Boolean> aesEncryptSubject = Holders.simple(false); |
||||
|
||||
@Identifier("aesEncryptKey") |
||||
private Conf<String> aesEncryptKey = Holders.simple(StringUtils.EMPTY); |
||||
|
||||
@Identifier("portalURLTurnOn") |
||||
private Conf<Boolean> portalURLTurnOn = Holders.simple(false); |
||||
|
||||
@Identifier("portalURL") |
||||
private Conf<String> portalURL = Holders.simple(StringUtils.EMPTY); |
||||
|
||||
@Identifier("crossDomain") |
||||
private Conf<Boolean> crossDomain = Holders.simple(false); |
||||
|
||||
@Identifier("webStartDesigner") |
||||
private Conf<Boolean> webStartDesigner = Holders.simple(false); |
||||
|
||||
@Identifier("downloadUrl32") |
||||
private Conf<String> downloadUrl32 = Holders.simple(""); |
||||
|
||||
@Identifier("downloadUrl64") |
||||
private Conf<String> downloadUrl64 = Holders.simple(""); |
||||
|
||||
@Identifier("decisionUrl") |
||||
private Conf<String> decisionUrl = Holders.simple(StringUtils.EMPTY); |
||||
|
||||
@Identifier("remoteFolder") |
||||
private Conf<Boolean> remoteFolder = Holders.simple(false); |
||||
|
||||
public String getJwtKey() { |
||||
return jwtKey.get(); |
||||
} |
||||
|
||||
public void setJwtKey(String jwtKey) { |
||||
this.jwtKey.set(jwtKey); |
||||
} |
||||
|
||||
public Boolean getCreateUserTurnOn() { |
||||
return createUserTurnOn.get(); |
||||
} |
||||
|
||||
public void setCreateUserTurnOn(Boolean createUserTurnOn) { |
||||
this.createUserTurnOn.set(createUserTurnOn); |
||||
} |
||||
|
||||
public CreateUserStrategy getUserStrategy() { |
||||
return userStrategy.get(); |
||||
} |
||||
|
||||
public void setUserStrategy(CreateUserStrategy userStrategy) { |
||||
this.userStrategy.set(userStrategy); |
||||
} |
||||
|
||||
public Boolean getParaCheckTurnOn() { |
||||
return paraCheckTurnOn.get(); |
||||
} |
||||
|
||||
public void setParaCheckTurnOn(Boolean paraCheckTurnOn) { |
||||
this.paraCheckTurnOn.set(paraCheckTurnOn); |
||||
} |
||||
|
||||
public String getParaCheckUrl() { |
||||
return paraCheckUrl.get(); |
||||
} |
||||
|
||||
public void setParaCheckUrl(String paraCheckUrl) { |
||||
this.paraCheckUrl.set(paraCheckUrl); |
||||
} |
||||
|
||||
public Boolean getRemoteTokenAuth() { |
||||
return remoteTokenAuth.get(); |
||||
} |
||||
|
||||
public void setRemoteTokenAuth(Boolean remoteTokenAuth) { |
||||
this.remoteTokenAuth.set(remoteTokenAuth); |
||||
} |
||||
|
||||
public Boolean getAesEncryptSubject() { |
||||
return aesEncryptSubject.get(); |
||||
} |
||||
|
||||
public void setAesEncryptSubject(Boolean aesEncryptSubject) { |
||||
this.aesEncryptSubject.set(aesEncryptSubject); |
||||
} |
||||
|
||||
public String getAesEncryptKey() { |
||||
return aesEncryptKey.get(); |
||||
} |
||||
|
||||
public void setAesEncryptKey(String aesEncryptKey) { |
||||
this.aesEncryptKey.set(aesEncryptKey); |
||||
} |
||||
|
||||
public Boolean getPortalURLTurnOn() { |
||||
return portalURLTurnOn.get(); |
||||
} |
||||
|
||||
public void setPortalURLTurnOn(Boolean portalURLTurnOn) { |
||||
this.portalURLTurnOn.set(portalURLTurnOn); |
||||
} |
||||
|
||||
public String getPortalURL() { |
||||
return portalURL.get(); |
||||
} |
||||
|
||||
public void setPortalURL(String portalURL) { |
||||
this.portalURL.set(portalURL); |
||||
} |
||||
|
||||
public Boolean getCrossDomain() { |
||||
return crossDomain.get(); |
||||
} |
||||
|
||||
public void setCrossDomain(Boolean crossDomain) { |
||||
this.crossDomain.set(crossDomain); |
||||
} |
||||
|
||||
public Boolean getWebStartDesigner() { |
||||
return webStartDesigner.get(); |
||||
} |
||||
|
||||
public void setWebStartDesigner(Boolean webStartDesigner) { |
||||
this.webStartDesigner.set(webStartDesigner); |
||||
} |
||||
|
||||
public String getDownloadUrl32() { |
||||
return downloadUrl32.get(); |
||||
} |
||||
|
||||
public void setDownloadUrl32(String downloadUrl32) { |
||||
this.downloadUrl32.set(downloadUrl32); |
||||
} |
||||
|
||||
public String getDownloadUrl64() { |
||||
return downloadUrl64.get(); |
||||
} |
||||
|
||||
public void setDownloadUrl64(String downloadUrl64) { |
||||
this.downloadUrl64.set(downloadUrl64); |
||||
} |
||||
|
||||
public String getDecisionUrl() { |
||||
return decisionUrl.get(); |
||||
} |
||||
|
||||
public void setDecisionUrl(String decisionUrl) { |
||||
this.decisionUrl.set(decisionUrl); |
||||
} |
||||
|
||||
public Boolean getRemoteFolder() { |
||||
return remoteFolder.get(); |
||||
} |
||||
|
||||
public void setRemoteFolder(Boolean remoteFolder) { |
||||
this.remoteFolder.set(remoteFolder); |
||||
} |
||||
|
||||
@Override |
||||
protected void initialize() { |
||||
ValueWriter.registerWriter(CreateDepartmentStrategy.class, new ValueWriter<CreateDepartmentStrategy>() { |
||||
@Override |
||||
public String writeObject(CreateDepartmentStrategy createDepEnum) { |
||||
return String.valueOf(createDepEnum.toInteger()); |
||||
} |
||||
}); |
||||
ValueReader.registerReader(CreateDepartmentStrategy.class, new ValueReader<CreateDepartmentStrategy>() { |
||||
public CreateDepartmentStrategy covert(String value) { |
||||
return CreateDepartmentStrategy.parse(Integer.parseInt(value)); |
||||
} |
||||
}); |
||||
ValueWriter.registerWriter(CreatePwdStrategy.class, new ValueWriter<CreatePwdStrategy>() { |
||||
@Override |
||||
public String writeObject(CreatePwdStrategy createDepEnum) { |
||||
return String.valueOf(createDepEnum.toInteger()); |
||||
} |
||||
}); |
||||
ValueReader.registerReader(CreatePwdStrategy.class, new ValueReader<CreatePwdStrategy>() { |
||||
public CreatePwdStrategy covert(String value) { |
||||
return CreatePwdStrategy.parse(Integer.parseInt(value)); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
public HashMap getWebStartedInfo(String username) throws Exception { |
||||
HashMap<String, String> info = new HashMap<>(3); |
||||
info.put("url", "fanruan://" + getDecisionUrl() + "?GWToken?" + getTokenByUserName(username)); |
||||
info.put("download64", getDownloadUrl64()); |
||||
info.put("download32", getDownloadUrl32()); |
||||
return info; |
||||
} |
||||
|
||||
public String getWebStartURL(String username, String path) throws Exception { |
||||
StringBuffer buffer = new StringBuffer(); |
||||
buffer.append("<script>window.open('") |
||||
.append("fanruan://").append(getDecisionUrl()).append("?GWToken?").append(getTokenByUserName(username)) |
||||
.append(StringUtils.isEmpty(path)? "": ("?" + path)) |
||||
.append("');(window.top==window)&&window.close();</script>"); |
||||
return buffer.toString(); |
||||
} |
||||
|
||||
private String getTokenByUserName(String username) throws Exception { |
||||
String subject = username; |
||||
if (getUserStrategy() instanceof ContainDepRoleStrategy) { |
||||
subject = JSONObject.create().put("username", username).toString(); |
||||
} |
||||
if (getAesEncryptSubject()) { |
||||
subject = Base64.getEncoder().encodeToString(AESUtils.aesEncryptToBytes(subject, getAesEncryptKey())); |
||||
} |
||||
Date date = new Date(); |
||||
return Jwts.builder() |
||||
.setSubject(subject) |
||||
.setExpiration(new Date(date.getTime() + Constants.EXPIRED_TIME)) |
||||
.signWith(SignatureAlgorithm.HS256, getJwtKey()) |
||||
.compact(); |
||||
} |
||||
} |
@ -0,0 +1,50 @@
|
||||
package com.fr.plugin.decision.integration.config.strategy; |
||||
|
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.third.fasterxml.jackson.annotation.JsonCreator; |
||||
import com.fr.third.fasterxml.jackson.annotation.JsonValue; |
||||
|
||||
/** |
||||
* @Author JianYe.Wang |
||||
* @Data 10:14 |
||||
* @Description TODO |
||||
* @Version 10.0 |
||||
**/ |
||||
|
||||
/** |
||||
* "department": { |
||||
* "name": "beijing", |
||||
* "id": "02" |
||||
* } |
||||
*/ |
||||
public enum CreateDepartmentStrategy { |
||||
/** |
||||
* 根据id长度, 01 011 012 |
||||
*/ |
||||
DEP_ID_LENGTH(0), |
||||
/** |
||||
* 根据name拼接 中国|北京市|朝阳区 |
||||
*/ |
||||
DEP_NAME_GROUP(1); |
||||
|
||||
private int type; |
||||
|
||||
CreateDepartmentStrategy(int type) { |
||||
this.type = type; |
||||
} |
||||
|
||||
@JsonValue |
||||
public int toInteger() { |
||||
return this.type; |
||||
} |
||||
|
||||
@JsonCreator |
||||
public static CreateDepartmentStrategy parse(int value) { |
||||
for (CreateDepartmentStrategy type : CreateDepartmentStrategy.values()) { |
||||
if (ComparatorUtils.equals(value, type.toInteger())) { |
||||
return type; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
} |
@ -0,0 +1,37 @@
|
||||
package com.fr.plugin.decision.integration.config.strategy; |
||||
|
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.third.fasterxml.jackson.annotation.JsonCreator; |
||||
import com.fr.third.fasterxml.jackson.annotation.JsonValue; |
||||
|
||||
/** |
||||
* @Author JianYe.Wang |
||||
* @Data 21-06-07 10:07 |
||||
* @Description TODO |
||||
* @Version 10.0 |
||||
**/ |
||||
public enum CreatePwdStrategy { |
||||
SAME_USER(0), RANDOM(1); |
||||
|
||||
private int type; |
||||
|
||||
CreatePwdStrategy(int type) { |
||||
this.type = type; |
||||
} |
||||
|
||||
@JsonValue |
||||
public int toInteger() { |
||||
return this.type; |
||||
} |
||||
|
||||
@JsonCreator |
||||
public static CreatePwdStrategy parse(int value) { |
||||
for (CreatePwdStrategy type : CreatePwdStrategy.values()) { |
||||
if (ComparatorUtils.equals(value, type.toInteger())) { |
||||
return type; |
||||
} |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
} |
@ -0,0 +1,38 @@
|
||||
package com.fr.plugin.decision.integration.config.strategy.user; |
||||
|
||||
import com.fr.config.Identifier; |
||||
import com.fr.config.holder.Conf; |
||||
import com.fr.config.holder.factory.Holders; |
||||
import com.fr.config.utils.UniqueKey; |
||||
import com.fr.plugin.decision.integration.config.strategy.CreatePwdStrategy; |
||||
import com.fr.plugin.decision.integration.config.strategy.user.impl.ContainDepRoleStrategy; |
||||
import com.fr.plugin.decision.integration.config.strategy.user.impl.OnlyUserStrategy; |
||||
import com.fr.third.fasterxml.jackson.annotation.JsonIgnoreProperties; |
||||
import com.fr.third.fasterxml.jackson.annotation.JsonSubTypes; |
||||
import com.fr.third.fasterxml.jackson.annotation.JsonTypeInfo; |
||||
|
||||
/** |
||||
* @Author JianYe.Wang |
||||
* @Data 21-6-7 10:01 |
||||
* @Description TODO |
||||
* @Version 10.0 |
||||
**/ |
||||
@JsonIgnoreProperties({"id", "data", "classInfo", "nameSpace"}) |
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "userType") |
||||
@JsonSubTypes({ |
||||
@JsonSubTypes.Type(value = OnlyUserStrategy.class, name = "onlyUser"), |
||||
@JsonSubTypes.Type(value = ContainDepRoleStrategy.class, name = "containDepRole") |
||||
}) |
||||
public abstract class CreateUserStrategy extends UniqueKey { |
||||
|
||||
@Identifier("pwdStrategy") |
||||
private Conf<CreatePwdStrategy> pwdStrategy = Holders.simple(CreatePwdStrategy.SAME_USER); |
||||
|
||||
public CreatePwdStrategy getPwdStrategy() { |
||||
return pwdStrategy.get(); |
||||
} |
||||
|
||||
public void setPwdStrategy(CreatePwdStrategy pwdStrategy) { |
||||
this.pwdStrategy.set(pwdStrategy); |
||||
} |
||||
} |
@ -0,0 +1,53 @@
|
||||
package com.fr.plugin.decision.integration.config.strategy.user.impl; |
||||
|
||||
import com.fr.config.Identifier; |
||||
import com.fr.config.holder.Conf; |
||||
import com.fr.config.holder.factory.Holders; |
||||
import com.fr.plugin.decision.integration.config.strategy.CreateDepartmentStrategy; |
||||
import com.fr.plugin.decision.integration.config.strategy.user.CreateUserStrategy; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.third.fasterxml.jackson.annotation.JsonTypeName; |
||||
|
||||
/** |
||||
* @Author JianYe.Wang |
||||
* @Data 10:13 |
||||
* @Description TODO |
||||
* @Version 10.0 |
||||
**/ |
||||
@JsonTypeName("containDepRole") |
||||
public class ContainDepRoleStrategy extends CreateUserStrategy { |
||||
|
||||
@Identifier("depStrategy") |
||||
private Conf<CreateDepartmentStrategy> depStrategy = Holders.simple(CreateDepartmentStrategy.DEP_ID_LENGTH); |
||||
|
||||
@Identifier("specialRootId") |
||||
private Conf<String> specialRootId = Holders.simple(StringUtils.EMPTY); |
||||
|
||||
// 分隔符, CreateDepEnum.DEP_NAME_GROUP 会用到
|
||||
@Identifier("separator") |
||||
private Conf<String> separator = Holders.simple(StringUtils.EMPTY); |
||||
|
||||
public CreateDepartmentStrategy getDepStrategy() { |
||||
return depStrategy.get(); |
||||
} |
||||
|
||||
public void setDepStrategy(CreateDepartmentStrategy depStrategy) { |
||||
this.depStrategy.set(depStrategy); |
||||
} |
||||
|
||||
public String getSpecialRootId() { |
||||
return specialRootId.get(); |
||||
} |
||||
|
||||
public void setSpecialRootId(String specialRootId) { |
||||
this.specialRootId.set(specialRootId); |
||||
} |
||||
|
||||
public String getSeparator() { |
||||
return separator.get(); |
||||
} |
||||
|
||||
public void setSeparator(String separator) { |
||||
this.separator.set(separator); |
||||
} |
||||
} |
@ -0,0 +1,15 @@
|
||||
package com.fr.plugin.decision.integration.config.strategy.user.impl; |
||||
|
||||
import com.fr.plugin.decision.integration.config.strategy.user.CreateUserStrategy; |
||||
import com.fr.third.fasterxml.jackson.annotation.JsonTypeName; |
||||
|
||||
/** |
||||
* @Author JianYe.Wang |
||||
* @Data 21-6-7 10:12 |
||||
* @Description TODO |
||||
* @Version 10.0 |
||||
**/ |
||||
@JsonTypeName("onlyUser") |
||||
public class OnlyUserStrategy extends CreateUserStrategy { |
||||
|
||||
} |
@ -0,0 +1,224 @@
|
||||
package com.fr.plugin.decision.integration.controller; |
||||
|
||||
import com.fr.base.ServerConfig; |
||||
import com.fr.decision.authority.data.User; |
||||
import com.fr.decision.webservice.CrossDomainResponse; |
||||
import com.fr.decision.webservice.Response; |
||||
import com.fr.decision.webservice.annotation.LoginStatusChecker; |
||||
import com.fr.decision.webservice.v10.login.LoginService; |
||||
import com.fr.decision.webservice.v10.login.TokenResource; |
||||
import com.fr.decision.webservice.v10.user.UserService; |
||||
import com.fr.io.utils.ResourceIOUtils; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.plugin.decision.integration.config.IntegrateConf; |
||||
import com.fr.plugin.decision.integration.service.IntegrateAuthService; |
||||
import com.fr.plugin.decision.integration.service.IntegrateCustomService; |
||||
import com.fr.plugin.decision.integration.utils.CommonUtils; |
||||
import com.fr.plugin.decision.integration.utils.Constants; |
||||
import com.fr.stable.StableUtils; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.third.fasterxml.jackson.databind.ObjectMapper; |
||||
import com.fr.third.springframework.stereotype.Controller; |
||||
import com.fr.third.springframework.web.bind.annotation.*; |
||||
import com.fr.web.utils.WebUtils; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
|
||||
@Controller |
||||
@RequestMapping({"/third/auth"}) |
||||
@LoginStatusChecker(required = false) |
||||
public class IntegratedController { |
||||
|
||||
private ObjectMapper mapper = new ObjectMapper(); |
||||
|
||||
/** |
||||
* 建议用于后台换取 fine_auth_token |
||||
* @param request |
||||
* @param response |
||||
* @param body 请求体 |
||||
* @param third_token 请求参数 |
||||
* @return fine_auth_token |
||||
* @throws Exception |
||||
*/ |
||||
@RequestMapping("/login") |
||||
@ResponseBody |
||||
public Response loginByToken(HttpServletRequest request, HttpServletResponse response, @RequestBody(required = false) Map body, @RequestParam(required = false, value = Constants.TOKEN_NAME) String third_token) throws Exception { |
||||
String token = third_token; |
||||
if (StringUtils.isBlank(third_token)) { |
||||
token = (String) body.get(Constants.TOKEN_NAME); |
||||
} |
||||
String username = IntegrateAuthService.getInstance().getUserNameFromToken(token); |
||||
return Response.ok(LoginService.getInstance().login(request, response, username)); |
||||
} |
||||
|
||||
/** |
||||
* 用于前台跨域请求 |
||||
* @param request |
||||
* @param response |
||||
* @param third_token |
||||
* @param callback |
||||
* @return |
||||
* @throws Exception |
||||
*/ |
||||
@RequestMapping( |
||||
value = {"/cross/login"}, |
||||
method = {RequestMethod.GET}, |
||||
produces = "application/javascript; charset=utf-8" |
||||
) |
||||
@ResponseBody |
||||
public String crossLoginByToken(HttpServletRequest request, |
||||
HttpServletResponse response, |
||||
@RequestParam(Constants.TOKEN_NAME) String third_token, |
||||
@RequestParam(value = "callback", required = false, defaultValue = "callback") String callback |
||||
) throws Exception { |
||||
String username = IntegrateAuthService.getInstance().getUserNameFromToken(third_token); |
||||
return CrossDomainResponse.create().callbackFuncName(callback) |
||||
.parameter("accessToken", LoginService.getInstance().login(request, response, username)) |
||||
.parameter("url", IntegrateCustomService.getInstance().generateDefaultHomePageUrl(request)) |
||||
.parameter("status", "success") |
||||
.createCrossDomainResponse(); |
||||
} |
||||
|
||||
/** |
||||
* URL设计器启动需要用的接口 |
||||
*/ |
||||
|
||||
/** |
||||
* 解析获取 token 对应的用户名 |
||||
* @param third_token |
||||
* @return |
||||
*/ |
||||
@RequestMapping( |
||||
value = {"/username"} |
||||
) |
||||
@ResponseBody |
||||
public String getUsernameFromToken(@RequestParam(Constants.TOKEN_NAME) String third_token) throws Exception { |
||||
return IntegrateAuthService.getInstance().getUserNameFromToken(third_token); |
||||
} |
||||
|
||||
/** |
||||
* 获取用户对应的token,用于web唤醒设计器传入token |
||||
*/ |
||||
@RequestMapping( |
||||
value = {"/username/token"} |
||||
) |
||||
@ResponseBody |
||||
@LoginStatusChecker |
||||
public Response getThirdTokenByUsername(HttpServletRequest request) throws Exception { |
||||
String username = LoginService.getInstance().getCurrentUserNameFromRequest(request); |
||||
return Response.ok(IntegrateConf.getInstance().getWebStartedInfo(username)); |
||||
} |
||||
|
||||
/** |
||||
* 登录状态下 |
||||
*/ |
||||
@RequestMapping( |
||||
value = {"/designer/start"} |
||||
) |
||||
@ResponseBody |
||||
//@LoginStatusChecker(tokenResource = TokenResource.COOKIE)
|
||||
public String openDesignerStartUrl(HttpServletRequest request, |
||||
HttpServletResponse response, |
||||
@RequestParam(value = "path", required = false) String path) throws Exception { |
||||
String username = LoginService.getInstance().getCurrentUserNameFromRequestCookie(request); |
||||
if (StringUtils.isEmpty(username)) return StringUtils.EMPTY; |
||||
response.setContentType("text/html; charset=GB2312"); |
||||
return IntegrateConf.getInstance().getWebStartURL(username, path); |
||||
} |
||||
|
||||
/** |
||||
* 插件配置读取、保存 |
||||
*/ |
||||
@RequestMapping( |
||||
value = {"/conf"}, |
||||
method = RequestMethod.GET |
||||
) |
||||
@ResponseBody |
||||
@LoginStatusChecker |
||||
public Response getIntegrateConfig(HttpServletRequest request, HttpServletResponse response) throws Exception { |
||||
String userId = UserService.getInstance().getCurrentUserIdFromCookie(request); |
||||
if (UserService.getInstance().isAdmin(userId)) { |
||||
response.setContentType("application/json;charset=" + ServerConfig.getInstance().getServerCharset()); |
||||
mapper.writeValue(response.getOutputStream(), IntegrateConf.getInstance()); |
||||
} |
||||
|
||||
return Response.error("getIntegrateConf", "仅管理员用户可见"); |
||||
} |
||||
|
||||
@RequestMapping( |
||||
value = {"/conf"}, |
||||
method = RequestMethod.POST |
||||
) |
||||
@ResponseBody |
||||
@LoginStatusChecker |
||||
public Response updateIntegrateConfig(HttpServletRequest request) throws IOException { |
||||
IntegrateConf conf = mapper.readValue(request.getInputStream(), IntegrateConf.class); |
||||
IntegrateAuthService.getInstance().updateIntegrateConf(conf); |
||||
return Response.success(); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 插件历史接口,做兼容使用 |
||||
*/ |
||||
|
||||
@RequestMapping( |
||||
value = {"/tpl/paste"} |
||||
) |
||||
@ResponseBody |
||||
@Deprecated |
||||
public Response pasteTemplate(@RequestParam(Constants.TOKEN_NAME) String third_token, @RequestParam("tplPath") String tplPath) throws Exception { |
||||
String username = IntegrateAuthService.getInstance().getUserNameFromToken(third_token); |
||||
if (StringUtils.isBlank(username)) |
||||
return Response.error("pasteTemplate", "TOKEN解析异常"); |
||||
|
||||
if (StringUtils.isBlank(tplPath) || !ResourceIOUtils.exist(StableUtils.pathJoin("reportlets", tplPath))) |
||||
return Response.error("pasteTemplate", "模板文件不存在"); |
||||
|
||||
ResourceIOUtils.copy( |
||||
StableUtils.pathJoin("reportlets", tplPath), |
||||
StableUtils.pathJoin("reportlets", username, tplPath.substring(tplPath.lastIndexOf("/"))) |
||||
); |
||||
return Response.success(); |
||||
} |
||||
|
||||
@RequestMapping( |
||||
value = {"/tpl/remote/list"} |
||||
) |
||||
@ResponseBody |
||||
@Deprecated |
||||
public Response getUserRemoteTplList(HttpServletRequest request, @RequestParam(Constants.TOKEN_NAME) String third_token) throws Exception { |
||||
String username = IntegrateAuthService.getInstance().getUserNameFromToken(third_token); |
||||
if (StringUtils.isBlank(username)) |
||||
return Response.error("UserRemoteTplList", "TOKEN解析异常"); |
||||
|
||||
User user = UserService.getInstance().getUserByUserName(username); |
||||
return Response.ok(IntegrateCustomService.getInstance().getRemoteTplListByUserId(user.getId(), WebUtils.createServletURL(request))); |
||||
} |
||||
|
||||
/** |
||||
* token 换取帆软token,主要用于后台请求 |
||||
*/ |
||||
@RequestMapping({"/token"}) |
||||
@ResponseBody |
||||
@Deprecated |
||||
public String tokenExchangeFineAuthToken(HttpServletRequest request, HttpServletResponse response, @RequestBody Map body) throws Exception { |
||||
String username = IntegrateAuthService.getInstance().getUserNameFromToken((String) body.get(Constants.TOKEN_NAME)); |
||||
return LoginService.getInstance().login(request, response, username); |
||||
} |
||||
|
||||
/** |
||||
* 处理下异常返回值统一格式返回 |
||||
* @param ex |
||||
* @return |
||||
*/ |
||||
@ExceptionHandler(Exception.class) |
||||
@ResponseBody |
||||
public Response exceptionRespond(Exception ex) { |
||||
FineLoggerFactory.getLogger().error(ex.getMessage(), ex); |
||||
return CommonUtils.formatException(ex); |
||||
} |
||||
} |
@ -0,0 +1,7 @@
|
||||
package com.fr.plugin.decision.integration.exception; |
||||
|
||||
public class JwtKeyNullException extends ThirdAuthException { |
||||
public JwtKeyNullException() { |
||||
super("The value of jwt key is null!"); |
||||
} |
||||
} |
@ -0,0 +1,14 @@
|
||||
package com.fr.plugin.decision.integration.exception; |
||||
|
||||
/** |
||||
* @Author JianYe.Wang |
||||
* @Data 2021/7/7 14:22 |
||||
* @Description TODO |
||||
* @Version 10.0 |
||||
**/ |
||||
public class JwtSubjectFormatException extends ThirdAuthException { |
||||
|
||||
public JwtSubjectFormatException() { |
||||
super("Jwt key subject format error!"); |
||||
} |
||||
} |
@ -0,0 +1,14 @@
|
||||
package com.fr.plugin.decision.integration.exception; |
||||
|
||||
public class ThirdAuthException extends RuntimeException { |
||||
|
||||
public static final String KEY = "FR decision integration exception: "; |
||||
|
||||
public ThirdAuthException(String message) { |
||||
super(KEY + message); |
||||
} |
||||
|
||||
public ThirdAuthException(String message, Throwable cause) { |
||||
super(KEY + message, cause); |
||||
} |
||||
} |
@ -0,0 +1,7 @@
|
||||
package com.fr.plugin.decision.integration.exception; |
||||
|
||||
public class TokenDecodeExpiredException extends ThirdAuthException { |
||||
public TokenDecodeExpiredException() { |
||||
super("Jwt token decode result is expired!"); |
||||
} |
||||
} |
@ -0,0 +1,14 @@
|
||||
package com.fr.plugin.decision.integration.exception; |
||||
|
||||
/** |
||||
* @Author JianYe.Wang |
||||
* @Data 2021/11/1 9:41 |
||||
* @Description TODO |
||||
* @Version 10.0 |
||||
**/ |
||||
public class TokenNullException extends ThirdAuthException { |
||||
|
||||
public TokenNullException() { |
||||
super("Jwt token is null!"); |
||||
} |
||||
} |
@ -0,0 +1,57 @@
|
||||
package com.fr.plugin.decision.integration.filter; |
||||
|
||||
import com.fr.data.NetworkHelper; |
||||
import com.fr.decision.fun.impl.AbstractEmbedRequestFilterProvider; |
||||
import com.fr.decision.webservice.Response; |
||||
import com.fr.decision.webservice.v10.remote.RemoteDesignStatusService; |
||||
import com.fr.plugin.decision.integration.config.IntegrateConf; |
||||
import com.fr.plugin.decision.integration.service.IntegrateAuthService; |
||||
import com.fr.plugin.decision.integration.utils.LogUtils; |
||||
import com.fr.security.JwtUtils; |
||||
import com.fr.security.SecurityToolbox; |
||||
import com.fr.security.encryption.transmission.TransmissionEncryptors; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.third.fasterxml.jackson.databind.ObjectMapper; |
||||
import com.fr.web.utils.WebUtils; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
|
||||
/** |
||||
* 拦截设计器远程请求, 支持Token认证 |
||||
*/ |
||||
public class RemoteFilter extends AbstractEmbedRequestFilterProvider { |
||||
|
||||
private static final String PATH_TOKEN = "/remote/design/token"; |
||||
private static final String PATH_VERIFY = "/remote/design/verify"; |
||||
|
||||
@Override |
||||
public void filter(HttpServletRequest request, HttpServletResponse response) { |
||||
if (!IntegrateConf.getInstance().getRemoteTokenAuth()) return; |
||||
String username = NetworkHelper.getHTTPRequestParameter(request, "username"); |
||||
String password; |
||||
if (request.getRequestURI().endsWith(PATH_TOKEN)) { |
||||
if (StringUtils.equalsIgnoreCase("get", request.getMethod())) { |
||||
password = NetworkHelper.getHTTPRequestParameter(request, "password"); |
||||
} else { |
||||
password = SecurityToolbox.defaultDecrypt(NetworkHelper.getHTTPRequestParameter(request, "password")); |
||||
} |
||||
} else if (request.getRequestURI().endsWith(PATH_VERIFY)) { |
||||
password = TransmissionEncryptors.getInstance().decrypt(NetworkHelper.getHTTPRequestParameter(request, "password")); |
||||
} else { |
||||
return; |
||||
} |
||||
|
||||
LogUtils.info("RemoteFilter token auth success: {}", username); |
||||
ObjectMapper mapper = new ObjectMapper(); |
||||
try { |
||||
if (StringUtils.isNotBlank(IntegrateAuthService.getInstance().getUserNameFromToken(password))) { |
||||
String token = JwtUtils.createDefaultJWT(username); |
||||
RemoteDesignStatusService.loginStatusService().put(token, username, 1209600000); |
||||
WebUtils.printAsString(response, mapper.writeValueAsString(Response.ok(token))); |
||||
} |
||||
} catch (Exception e) { |
||||
LogUtils.error(e.getMessage(), e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,78 @@
|
||||
package com.fr.plugin.decision.integration.filter; |
||||
|
||||
import com.fr.decision.fun.impl.AbstractEmbedRequestFilterProvider; |
||||
import com.fr.decision.webservice.v10.login.LoginService; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.plugin.decision.integration.config.IntegrateConf; |
||||
import com.fr.plugin.decision.integration.service.IntegrateAuthService; |
||||
import com.fr.plugin.decision.integration.utils.CommonUtils; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.web.utils.WebUtils; |
||||
|
||||
import javax.servlet.ServletException; |
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
import java.io.IOException; |
||||
|
||||
import static org.apache.catalina.filters.CorsFilter.*; |
||||
|
||||
/** |
||||
* @Author JianYe.Wang |
||||
* @Data 2021/10/15 14:44 |
||||
* @Description TODO |
||||
* @Version 10.0 |
||||
**/ |
||||
public class RequestSsoFilter extends AbstractEmbedRequestFilterProvider { |
||||
|
||||
@Override |
||||
public void filter(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { |
||||
try { |
||||
// url 携带 token 单点
|
||||
String token = WebUtils.getHTTPRequestParameter(request, "third_token"); |
||||
if (StringUtils.isNotEmpty(token)) { |
||||
String userName = IntegrateAuthService.getInstance().getUserNameFromToken(token); |
||||
if (CommonUtils.isMobile(request) && !request.getRequestURI().endsWith("/third/auth/cross/login")) { |
||||
String frToken = doLoginFR(request, response, userName); |
||||
String originalURL = WebUtils.getOriginalURL(request).replaceAll("&?third_token=[^&]*", ""); |
||||
response.sendRedirect(originalURL + "&fine_auth_token=" + frToken); |
||||
} else { |
||||
String curUserName = LoginService.getInstance().getCurrentUserNameFromRequestCookie(request); |
||||
if (!LoginService.getInstance().isLogged(request) || !StringUtils.equals(userName, curUserName)) { |
||||
doLoginFR(request, response, userName); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 自定义登录页判断,/login 还保留
|
||||
if (IntegrateConf.getInstance().getPortalURLTurnOn() && request.getRequestURI().endsWith(WebUtils.createServletURL(request)) && !LoginService.getInstance().isLogged(request)) { |
||||
response.sendRedirect(IntegrateConf.getInstance().getPortalURL()); |
||||
return; |
||||
} |
||||
|
||||
// 跨域判断
|
||||
if (IntegrateConf.getInstance().getCrossDomain()) { |
||||
String origin = request.getHeader("Origin"); |
||||
if (StringUtils.isNotEmpty(origin)) { |
||||
response.addHeader(RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, origin); |
||||
String headers = request.getHeader(REQUEST_HEADER_ACCESS_CONTROL_REQUEST_HEADERS); |
||||
if (StringUtils.isNotEmpty(headers)) |
||||
response.addHeader(RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_HEADERS, headers); |
||||
response.addHeader(RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_METHODS, "*"); |
||||
response.addHeader(RESPONSE_HEADER_ACCESS_CONTROL_MAX_AGE, "3600"); |
||||
|
||||
} |
||||
/*if (request.getMethod().equals("OPTIONS")) { |
||||
response.setStatus(HttpServletResponse.SC_OK); |
||||
}*/ |
||||
} |
||||
} catch (Exception e) { |
||||
FineLoggerFactory.getLogger().error(e.getMessage(), e); |
||||
} |
||||
} |
||||
|
||||
private String doLoginFR(HttpServletRequest request, HttpServletResponse response, String username) throws Exception { |
||||
String frToken = LoginService.getInstance().login(request, response, username); |
||||
request.setAttribute("fine_auth_token", frToken); |
||||
return frToken; |
||||
} |
||||
} |
@ -0,0 +1,62 @@
|
||||
package com.fr.plugin.decision.integration.filter; |
||||
|
||||
import com.fr.decision.fun.impl.AbstractEmbedRequestFilterProvider; |
||||
import com.fr.decision.webservice.v10.login.LoginService; |
||||
import com.fr.general.http.HttpRequest; |
||||
import com.fr.general.http.HttpToolbox; |
||||
import com.fr.json.JSONObject; |
||||
import com.fr.plugin.decision.integration.config.IntegrateConf; |
||||
import com.fr.plugin.decision.integration.utils.CommonUtils; |
||||
import com.fr.stable.ArrayUtils; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.third.fasterxml.jackson.databind.ObjectMapper; |
||||
import com.fr.third.org.apache.http.HttpEntity; |
||||
import com.fr.third.org.apache.http.entity.StringEntity; |
||||
import com.fr.web.utils.WebUtils; |
||||
|
||||
import javax.servlet.ServletException; |
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
import java.io.IOException; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
public class TplParaCheckFilter extends AbstractEmbedRequestFilterProvider { |
||||
|
||||
private String[] reportParameterNames = new String[]{"viewlet", "viewlets", "reportlet", "reportlets"}; |
||||
|
||||
@Override |
||||
public void filter(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { |
||||
if (!needCheckParameter(request)) return; |
||||
|
||||
HashMap<String, Object> requestMap = new HashMap<>(); |
||||
for (String parameter : request.getParameterMap().keySet()) { |
||||
if (!ArrayUtils.contains(reportParameterNames, parameter)) |
||||
requestMap.put(parameter, request.getParameter(parameter)); |
||||
} |
||||
requestMap.put("userId", LoginService.getInstance().getCurrentUserNameFromRequestCookie(request)); |
||||
|
||||
try { |
||||
if (doCheckTplParameter(requestMap)) return; |
||||
} catch (Exception e) { |
||||
} |
||||
CommonUtils.showErrorPage(response, "请登录系统访问报表", ""); |
||||
} |
||||
|
||||
/** |
||||
* 请求是否需要校验预览参数 |
||||
**/ |
||||
private boolean needCheckParameter(HttpServletRequest request) { |
||||
return IntegrateConf.getInstance().getParaCheckTurnOn() && |
||||
//LoginService.getInstance().isLogged(request) &&
|
||||
StringUtils.isNotBlank(WebUtils.getReportTitleFromRequest(request)); |
||||
} |
||||
|
||||
private boolean doCheckTplParameter(Map requestMap) throws IOException { |
||||
HashMap headerMap = new HashMap(); |
||||
headerMap.put("Content-Type", "application/json"); |
||||
HttpEntity entity = new StringEntity(new ObjectMapper().writeValueAsString(requestMap), "utf-8"); |
||||
String result = HttpToolbox.executeAndParse(HttpRequest.custom().url(IntegrateConf.getInstance().getParaCheckUrl()).post(entity).headers(headerMap).build()); |
||||
return new JSONObject(result).getBoolean("data"); |
||||
} |
||||
} |
@ -0,0 +1,27 @@
|
||||
package com.fr.plugin.decision.integration.resource; |
||||
|
||||
import com.fr.decision.fun.impl.AbstractWebResourceProvider; |
||||
import com.fr.decision.web.MainComponent; |
||||
import com.fr.plugin.decision.integration.config.IntegrateConf; |
||||
import com.fr.web.struct.Atom; |
||||
import com.fr.web.struct.Component; |
||||
import com.fr.web.struct.Filter; |
||||
import com.fr.web.struct.category.ScriptPath; |
||||
|
||||
public class PluginConfigWebResourceImpl extends AbstractWebResourceProvider { |
||||
|
||||
@Override |
||||
public Atom attach() { |
||||
return MainComponent.KEY; |
||||
} |
||||
|
||||
@Override |
||||
public Atom client() { |
||||
return new Component() { |
||||
@Override |
||||
public ScriptPath script() { |
||||
return ScriptPath.build("com/fr/plugin/decision/integration/web/js/plugin.js"); |
||||
} |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,43 @@
|
||||
package com.fr.plugin.decision.integration.resource; |
||||
|
||||
import com.fr.decision.fun.impl.AbstractWebResourceProvider; |
||||
import com.fr.decision.web.MainComponent; |
||||
import com.fr.plugin.decision.integration.config.IntegrateConf; |
||||
import com.fr.web.struct.Atom; |
||||
import com.fr.web.struct.Component; |
||||
import com.fr.web.struct.Filter; |
||||
import com.fr.web.struct.category.ScriptPath; |
||||
|
||||
/** |
||||
* @Author JianYe.Wang |
||||
* @Data 2022/4/1 15:22 |
||||
* @Description TODO |
||||
* @Version 10.0 |
||||
**/ |
||||
public class WebStartWebResourceImpl extends AbstractWebResourceProvider { |
||||
|
||||
@Override |
||||
public Atom attach() { |
||||
return MainComponent.KEY; |
||||
} |
||||
|
||||
@Override |
||||
public Atom client() { |
||||
return new Component() { |
||||
@Override |
||||
public ScriptPath script() { |
||||
return ScriptPath.build("com/fr/plugin/decision/integration/web/js/web_start.js"); |
||||
} |
||||
|
||||
@Override |
||||
public Filter filter() { |
||||
return new Filter() { |
||||
@Override |
||||
public boolean accept() { |
||||
return IntegrateConf.getInstance().getWebStartDesigner(); |
||||
} |
||||
}; |
||||
} |
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,254 @@
|
||||
package com.fr.plugin.decision.integration.service; |
||||
|
||||
|
||||
import com.fr.cert.token.Claims; |
||||
import com.fr.decision.base.util.UUIDUtil; |
||||
import com.fr.decision.privilege.TransmissionTool; |
||||
import com.fr.decision.webservice.bean.user.UserBean; |
||||
import com.fr.decision.webservice.v10.user.UserService; |
||||
import com.fr.io.utils.ResourceIOUtils; |
||||
import com.fr.plugin.decision.integration.config.strategy.CreatePwdStrategy; |
||||
import com.fr.plugin.decision.integration.bean.user.UserInfoBean; |
||||
import com.fr.plugin.decision.integration.config.IntegrateConf; |
||||
import com.fr.plugin.decision.integration.config.strategy.user.impl.OnlyUserStrategy; |
||||
import com.fr.plugin.decision.integration.exception.JwtKeyNullException; |
||||
import com.fr.plugin.decision.integration.exception.JwtSubjectFormatException; |
||||
import com.fr.plugin.decision.integration.exception.TokenDecodeExpiredException; |
||||
import com.fr.plugin.decision.integration.exception.TokenNullException; |
||||
import com.fr.plugin.decision.integration.utils.*; |
||||
import com.fr.report.ReportContext; |
||||
import com.fr.report.constant.RoleType; |
||||
import com.fr.report.data.RemoteDesignAuthority; |
||||
import com.fr.report.util.RemoteDesignAuthHelper; |
||||
import com.fr.report.util.RemoteUserInfo; |
||||
import com.fr.security.JwtUtils; |
||||
import com.fr.stable.StableUtils; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.third.fasterxml.jackson.databind.ObjectMapper; |
||||
import com.fr.transaction.Configurations; |
||||
import com.fr.transaction.WorkerAdaptor; |
||||
import com.fr.web.service.RemoteDesignAuthorityDataService; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.util.*; |
||||
|
||||
public class IntegrateAuthService { |
||||
|
||||
private volatile static IntegrateAuthService service; |
||||
private static Properties properties = new Properties(); |
||||
private IntegrateConf config = IntegrateConf.getInstance(); |
||||
private ObjectMapper mapper = new ObjectMapper(); |
||||
|
||||
private IntegrateAuthService() { |
||||
} |
||||
|
||||
public static IntegrateAuthService getInstance() { |
||||
if (service == null) { |
||||
synchronized (IntegrateAuthService.class) { |
||||
if (service == null) { |
||||
service = new IntegrateAuthService(); |
||||
} |
||||
} |
||||
} |
||||
return service; |
||||
} |
||||
|
||||
public String getUserNameFromToken(String thirdToken) throws Exception { |
||||
if (StringUtils.isEmpty(thirdToken)) { |
||||
throw new TokenNullException(); |
||||
} |
||||
String userInfo = decodeJwtToken(thirdToken, loadJwtKey()); |
||||
if (config.getAesEncryptSubject()) { |
||||
userInfo = AESUtils.aesDecryptByBytes(Base64.getDecoder().decode(userInfo), config.getAesEncryptKey()); |
||||
} |
||||
|
||||
return addOrUpdateUserInfo(userInfo); |
||||
} |
||||
|
||||
private String loadJwtKey() { |
||||
String key = config.getJwtKey(); |
||||
if (StringUtils.isBlank(key)) { |
||||
key = properties.getProperty("key"); |
||||
} |
||||
|
||||
if (StringUtils.isBlank(key)) { |
||||
throw new JwtKeyNullException(); |
||||
} |
||||
return key; |
||||
} |
||||
|
||||
private String decodeJwtToken(String thirdToken, String key) { |
||||
Claims claims = JwtUtils.parseJWT(thirdToken, key); |
||||
Date date = claims.getExpiration(); |
||||
if (date != null && date.after(new Date())) { |
||||
return claims.getSubject(); |
||||
} |
||||
throw new TokenDecodeExpiredException(); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 校验更新/创建用户信息 |
||||
* |
||||
* @param userInfoStr |
||||
* @return username |
||||
* @throws Exception |
||||
*/ |
||||
private String addOrUpdateUserInfo(String userInfoStr) throws Exception { |
||||
// 未开启创建用户时,直接返回用户名不需要创建用户信息
|
||||
if (!config.getCreateUserTurnOn()) { |
||||
if (CommonUtils.isJsonFormatStr(userInfoStr)) { |
||||
return mapper.readValue(userInfoStr, UserInfoBean.class).getUsername(); |
||||
}; |
||||
return userInfoStr; |
||||
} |
||||
|
||||
// 仅用户名
|
||||
if (config.getUserStrategy() instanceof OnlyUserStrategy) { |
||||
if (CommonUtils.isJsonFormatStr(userInfoStr)) { |
||||
throw new JwtSubjectFormatException(); |
||||
} |
||||
// 用户不存在时基于用户名创建下用户
|
||||
if (!UserUtils.existUsername(userInfoStr)) { |
||||
UserService.getInstance().addUser(buildBaseUserBean(userInfoStr)); |
||||
checkAndCreateRemoteDesignAuth(userInfoStr); |
||||
} |
||||
return userInfoStr; |
||||
} |
||||
|
||||
// 含部门职位
|
||||
UserInfoBean userInfo = mapper.readValue(userInfoStr, UserInfoBean.class); |
||||
// 管理员账号不进行处理
|
||||
if (UserUtils.isAdmin(userInfo.getUsername())) { |
||||
return userInfo.getUsername(); |
||||
} |
||||
UserBean userBean; |
||||
if (!UserUtils.existUsername(userInfo.getUsername())) { |
||||
UserService.getInstance().addUser(buildBaseUserBean(userInfo.getUsername())); |
||||
} |
||||
userBean = UserService.getInstance().getUserAccount(userInfo.getUsername()); |
||||
// 更新部门信息
|
||||
if (null != userInfo.getDepartment()) { |
||||
userBean.setDepartmentPostIds(UserUtils.updateDepTreeAndPost( |
||||
userInfo.getDepartment().getName(), |
||||
userInfo.getDepartment().getId()) |
||||
); |
||||
UserUtils.updateUserDepartmentPost(UserUtils.getAdminUserId(), userBean); |
||||
} |
||||
|
||||
// 更新角色信息
|
||||
if (null != userInfo.getRoles()) { |
||||
ArrayList<String> roles = new ArrayList<>(); |
||||
for (String roleName : userInfo.getRoles()) { |
||||
roles.add(UserUtils.checkAndAddRole(roleName)); |
||||
} |
||||
userBean.setRoleIds(roles.toArray(new String[0])); |
||||
UserService.getInstance().updateUserRoles(UserUtils.getAdminUserId(), userBean); |
||||
} |
||||
|
||||
// 用户平台类型
|
||||
if (null != userInfo.getPlatformType()) { |
||||
UserUtils.updateUserPlatformType(userBean, userInfo.getPlatformType()); |
||||
} |
||||
|
||||
// 更新远程设计权限和目录信息
|
||||
checkAndCreateRemoteDesignAuth(userInfo.getUsername()); |
||||
return userInfo.getUsername(); |
||||
} |
||||
|
||||
|
||||
private UserBean buildBaseUserBean(String username) { |
||||
UserBean userBean = new UserBean(UUIDUtil.generate(), username, username, true); |
||||
String pwd; |
||||
if (config.getUserStrategy().getPwdStrategy() == CreatePwdStrategy.SAME_USER) { |
||||
pwd = username; |
||||
} else { |
||||
pwd = UserUtils.getRandomPassword(8); |
||||
} |
||||
userBean.setPassword(TransmissionTool.defaultEncrypt(pwd)); |
||||
return userBean; |
||||
} |
||||
|
||||
/** |
||||
* 校验如果用户没有自己同名模板跟目录文件夹的远程设计权限,则新建添加一下 |
||||
* |
||||
* @param username |
||||
*/ |
||||
private void checkAndCreateRemoteDesignAuth(String username) throws Exception { |
||||
if (!config.getRemoteFolder()) return; |
||||
RemoteUserInfo remoteUserInfo = RemoteDesignAuthHelper.getUserInfo(username); |
||||
if (remoteUserInfo == null) { |
||||
return; |
||||
} |
||||
String userRemoteFileName = formatUsername(username); |
||||
List<RemoteDesignAuthority> remoteDesignAuthorities = RemoteDesignAuthorityDataService.getInstance().getAuthorities(remoteUserInfo.getUserID()); |
||||
for (RemoteDesignAuthority remoteDesignAuthority : remoteDesignAuthorities) { |
||||
if (remoteDesignAuthority.getPathType() && StringUtils.equals(userRemoteFileName, remoteDesignAuthority.getPath())) { |
||||
return; |
||||
} |
||||
} |
||||
String path = StableUtils.pathJoin("reportlets", userRemoteFileName); |
||||
if (!ResourceIOUtils.isDirectoryExist(path)) { |
||||
ResourceIOUtils.createDirectory(path); |
||||
} |
||||
|
||||
RemoteDesignAuthority authority = new RemoteDesignAuthority(); |
||||
authority.userName(username).userId(remoteUserInfo.getUserID()).path(userRemoteFileName).pathType(true).roleType(RoleType.USER); |
||||
ReportContext.getInstance().getRemoteDesignAuthorityController().add(authority); |
||||
} |
||||
|
||||
private String formatUsername(String username) { |
||||
return username.replaceAll("[\\\\/:*?\"<>|]", StringUtils.EMPTY); |
||||
} |
||||
|
||||
public void updateIntegrateConf(IntegrateConf conf) { |
||||
Configurations.update(new WorkerAdaptor(IntegrateConf.class) { |
||||
@Override |
||||
public void run() { |
||||
IntegrateConf instance = IntegrateConf.getInstance(); |
||||
instance.setDecisionUrl(conf.getDecisionUrl()); |
||||
instance.setJwtKey(conf.getJwtKey()); |
||||
instance.setRemoteTokenAuth(conf.getRemoteTokenAuth()); |
||||
instance.setAesEncryptSubject(conf.getAesEncryptSubject()); |
||||
instance.setAesEncryptKey(conf.getAesEncryptKey()); |
||||
instance.setPortalURLTurnOn(conf.getPortalURLTurnOn()); |
||||
instance.setPortalURL(conf.getPortalURL()); |
||||
instance.setCrossDomain(conf.getCrossDomain()); |
||||
instance.setRemoteFolder(conf.getRemoteFolder()); |
||||
if (conf.getCreateUserTurnOn()) { |
||||
instance.setUserStrategy(conf.getUserStrategy()); |
||||
instance.setCreateUserTurnOn(true); |
||||
} else { |
||||
instance.setCreateUserTurnOn(false); |
||||
} |
||||
|
||||
if (conf.getParaCheckTurnOn()) { |
||||
instance.setParaCheckUrl(conf.getParaCheckUrl()); |
||||
instance.setParaCheckTurnOn(true); |
||||
} else { |
||||
instance.setParaCheckTurnOn(false); |
||||
} |
||||
|
||||
if (conf.getWebStartDesigner()) { |
||||
instance.setDownloadUrl32(conf.getDownloadUrl32()); |
||||
instance.setDownloadUrl64(conf.getDownloadUrl64()); |
||||
instance.setWebStartDesigner(true); |
||||
} else { |
||||
instance.setWebStartDesigner(false); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
|
||||
static { |
||||
// 历史参数获取方式,兼容使用
|
||||
InputStream inputStream = ResourceIOUtils.read("/resources/third_auth.properties"); |
||||
if (null != inputStream) { |
||||
try { |
||||
properties.load(inputStream); |
||||
} catch (IOException ignore) {} |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,98 @@
|
||||
package com.fr.plugin.decision.integration.service; |
||||
|
||||
import com.fr.base.FRContext; |
||||
import com.fr.base.TemplateUtils; |
||||
import com.fr.data.NetworkHelper; |
||||
import com.fr.decision.webservice.v10.user.UserService; |
||||
import com.fr.file.filetree.FileNode; |
||||
import com.fr.file.filetree.FileNodes; |
||||
import com.fr.json.JSONException; |
||||
import com.fr.plugin.decision.integration.bean.TplInfoBean; |
||||
import com.fr.report.DesignAuthority; |
||||
import com.fr.workspace.WorkContext; |
||||
import com.fr.workspace.Workspace; |
||||
import com.fr.workspace.server.authority.AuthorityOperator; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
import java.util.ArrayList; |
||||
|
||||
@Deprecated |
||||
public class IntegrateCustomService { |
||||
|
||||
private static final String FRM_PATH = "/view/form?viewlet="; |
||||
private static final String CPT_PATH = "/view/report?viewlet="; |
||||
|
||||
private volatile static IntegrateCustomService service = null; |
||||
|
||||
public IntegrateCustomService() { |
||||
} |
||||
|
||||
public static IntegrateCustomService getInstance() { |
||||
if (service == null) { |
||||
synchronized (IntegrateAuthService.class) { |
||||
if (service == null) { |
||||
service = new IntegrateCustomService(); |
||||
} |
||||
} |
||||
} |
||||
return service; |
||||
} |
||||
|
||||
public String generateDefaultHomePageUrl(HttpServletRequest request) throws Exception { |
||||
String originalURL = NetworkHelper.getOriginalURL(request); |
||||
String requestURI = request.getRequestURI(); |
||||
return TemplateUtils.render(originalURL.replace(requestURI, "${fineServletURL}")); |
||||
} |
||||
|
||||
public ArrayList getRemoteTplListByUserId(String userId, String servletName) { |
||||
Workspace workspace = WorkContext.getCurrent(); |
||||
FileNodes root = FRContext.getFileNodes(); |
||||
ArrayList fileNodes = new ArrayList(); |
||||
|
||||
fileNodes.add(getNodeItem("reportlets", "", true, servletName)); |
||||
if (UserService.getInstance().isAdmin(userId)) { |
||||
getFileNode(fileNodes, root, "reportlets", servletName); |
||||
} else { |
||||
DesignAuthority auth = (workspace.get(AuthorityOperator.class)).getAuthorities(userId)[0]; |
||||
for (DesignAuthority.Item item : auth.getItems()) { |
||||
String path = item.getPath(); |
||||
boolean type = item.getType(); |
||||
fileNodes.add(getNodeItem("reportlets/" + path, "reportlets", type, servletName)); |
||||
if (type) { |
||||
getFileNode(fileNodes, root, "reportlets/" + path, servletName); |
||||
} |
||||
} |
||||
} |
||||
return fileNodes; |
||||
} |
||||
|
||||
private void getFileNode(ArrayList nodeItem, FileNodes root, String path, String servletName) throws JSONException { |
||||
FileNode[] fNodes = root.list(path, false); |
||||
for (int i = 0; i < fNodes.length; i++) { |
||||
FileNode fileNode = fNodes[i]; |
||||
String fileNodePath = fileNode.getEnvPath(); |
||||
nodeItem.add(getNodeItem(fileNodePath, path, fileNode.isDirectory(), servletName)); |
||||
if (fileNode.isDirectory()) { |
||||
getFileNode(nodeItem, root, fileNodePath, servletName); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private TplInfoBean getNodeItem(String path, String pId, boolean isDirectory, String servletName) { |
||||
boolean isCpt = false; |
||||
String menuId; |
||||
if (path.contains(".cpt")) { |
||||
isCpt = true; |
||||
menuId = path.replace(".cpt", ""); |
||||
} else { |
||||
menuId = path.replace(".frm", ""); |
||||
} |
||||
if (!isDirectory) { |
||||
menuId = new StringBuffer().append(menuId).append("_f").toString(); |
||||
} |
||||
path = path.replace("reportlets/", ""); |
||||
String nodeName = menuId.replaceAll(pId + "/", ""); |
||||
|
||||
return new TplInfoBean(menuId, nodeName, isDirectory ? "" : isCpt ? servletName + CPT_PATH + path : servletName + FRM_PATH + path, pId); |
||||
} |
||||
} |
@ -0,0 +1,68 @@
|
||||
package com.fr.plugin.decision.integration.utils; |
||||
|
||||
import com.fr.base.Base64; |
||||
|
||||
import javax.crypto.Cipher; |
||||
import javax.crypto.KeyGenerator; |
||||
import javax.crypto.Mac; |
||||
import javax.crypto.spec.SecretKeySpec; |
||||
|
||||
/** |
||||
* @Author JianYe.Wang |
||||
* @Data 2021/8/16 15:06 |
||||
* @Description TODO |
||||
* @Version 10.0 |
||||
**/ |
||||
public class AESUtils { |
||||
|
||||
private static final String AES_ECB_PKCS_5_PADDING = "AES/ECB/PKCS5Padding"; |
||||
private static final String HMAC_SHA_256 = "HmacSHA256"; |
||||
|
||||
/** |
||||
* AES加密 |
||||
* |
||||
* @param content 待加密的内容 |
||||
* @param encryptKey 加密密钥 |
||||
* @return 加密后的byte[] |
||||
*/ |
||||
public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception { |
||||
KeyGenerator kgen = KeyGenerator.getInstance("AES"); |
||||
kgen.init(128); |
||||
Cipher cipher = Cipher.getInstance(AES_ECB_PKCS_5_PADDING); |
||||
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES")); |
||||
return cipher.doFinal(content.getBytes("utf-8")); |
||||
} |
||||
|
||||
/** |
||||
* AES解密 |
||||
* |
||||
* @param encryptBytes 待解密的byte[] |
||||
* @param decryptKey 解密密钥 |
||||
* @return 解密后的String |
||||
*/ |
||||
public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception { |
||||
KeyGenerator kgen = KeyGenerator.getInstance("AES"); |
||||
kgen.init(128); |
||||
|
||||
Cipher cipher = Cipher.getInstance(AES_ECB_PKCS_5_PADDING); |
||||
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES")); |
||||
byte[] decryptBytes = cipher.doFinal(encryptBytes); |
||||
|
||||
return new String(decryptBytes, "utf-8"); |
||||
} |
||||
|
||||
/** |
||||
* HmacSHA256 签名 |
||||
* |
||||
* @param content |
||||
* @param signKey |
||||
* @return base64 encode |
||||
* @throws Exception |
||||
*/ |
||||
public static String hmacSHA256Sign(String content, String signKey) throws Exception { |
||||
Mac sha256Hmac = Mac.getInstance(HMAC_SHA_256); |
||||
SecretKeySpec secret_key = new SecretKeySpec(signKey.getBytes(), HMAC_SHA_256); |
||||
sha256Hmac.init(secret_key); |
||||
return Base64.encode(sha256Hmac.doFinal(content.getBytes())); |
||||
} |
||||
} |
@ -0,0 +1,90 @@
|
||||
package com.fr.plugin.decision.integration.utils; |
||||
|
||||
import com.fr.data.NetworkHelper; |
||||
import com.fr.decision.webservice.Response; |
||||
import com.fr.decision.webservice.utils.WebServiceUtils; |
||||
import com.fr.intelligence.IntelligenceException; |
||||
import com.fr.json.JSONObject; |
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.web.utils.WebUtils; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
import java.io.PrintWriter; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
public class CommonUtils { |
||||
|
||||
public static boolean isJsonFormatStr(String str) { |
||||
if (StringUtils.isNotBlank(str)) { |
||||
str = str.trim(); |
||||
try { |
||||
new JSONObject(str); |
||||
return true; |
||||
} catch (Exception e) { |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
public static void showErrorPage(HttpServletResponse response, String result, String solution) { |
||||
try { |
||||
PrintWriter printWriter = WebUtils.createPrintWriter(response); |
||||
Map<String, Object> map = new HashMap<>(); |
||||
map.put("result", result); |
||||
map.put("solution", solution); |
||||
String page = WebServiceUtils.parseWebPageResourceSafe("com/fr/web/controller/decision/entrance/resources/unavailable.html", map); |
||||
printWriter.write(page); |
||||
printWriter.flush(); |
||||
printWriter.close(); |
||||
} catch (Exception e) { |
||||
LogUtils.error(e.getLocalizedMessage(), e); |
||||
} |
||||
} |
||||
|
||||
public static boolean isMobile(HttpServletRequest req) { |
||||
String[] mobileArray = {"iPhone", "iPad", "android", "windows phone", "xiaomi"}; |
||||
String userAgent = req.getHeader("user-agent"); |
||||
// if (userAgent != null && userAgent.toUpperCase().contains("MOBILE")) {
|
||||
// 华为PAD的chrome浏览器userAgent中不包含mobile
|
||||
if (userAgent != null) { |
||||
for (String mobile : mobileArray) { |
||||
if (userAgent.toLowerCase().contains(mobile.toLowerCase())) { |
||||
return true; |
||||
} |
||||
} |
||||
} |
||||
//pc端企业微信
|
||||
//if (userAgent.contains("wxwork")) return true;
|
||||
FineLoggerFactory.getLogger().debug("isMobile userAgent:{} is:{}", userAgent, NetworkHelper.getDevice(req).isMobile()); |
||||
return NetworkHelper.getDevice(req).isMobile(); |
||||
} |
||||
|
||||
public static Response formatException(Exception ex) { |
||||
String msg = ex.getMessage(); |
||||
if (StringUtils.isBlank(msg)) { |
||||
msg = getStackTraceInfo(ex); |
||||
} |
||||
|
||||
if (ex instanceof IntelligenceException) { |
||||
return Response.error(((IntelligenceException) ex).errorCode(), msg); |
||||
} |
||||
|
||||
return Response.error("", msg); |
||||
} |
||||
|
||||
//从异常中获取具体的堆栈信息
|
||||
private static String getStackTraceInfo(Exception ex) { |
||||
StackTraceElement[] stackElements = ex.getStackTrace(); |
||||
StringBuilder stringBuilder = new StringBuilder("\r\n"); |
||||
if (stackElements != null) { |
||||
for (StackTraceElement stackElement : stackElements) { |
||||
stringBuilder.append(stackElement.getMethodName()).append("\r\n"); |
||||
} |
||||
return stringBuilder.toString(); |
||||
} |
||||
return ex.toString(); |
||||
} |
||||
} |
@ -0,0 +1,18 @@
|
||||
package com.fr.plugin.decision.integration.utils; |
||||
|
||||
/** |
||||
* @Author JianYe.Wang |
||||
* @Data 2021/12/3 14:05 |
||||
* @Description TODO |
||||
* @Version 10.0 |
||||
**/ |
||||
public class Constants { |
||||
|
||||
public static final int HOLD = -1; |
||||
|
||||
// third token名称
|
||||
public static final String TOKEN_NAME = "third_token"; |
||||
// token的默认超期时间
|
||||
public static final long EXPIRED_TIME = 1000 * 60 * 10; |
||||
|
||||
} |
@ -0,0 +1,96 @@
|
||||
package com.fr.plugin.decision.integration.utils; |
||||
|
||||
import com.fr.log.FineLoggerFactory; |
||||
import com.fr.log.FineLoggerProvider; |
||||
import com.fr.plugin.context.PluginContexts; |
||||
import com.fr.stable.StringUtils; |
||||
|
||||
public final class LogUtils { |
||||
private static String LOG_PREFIX = "[平台集成] "; |
||||
private static final String PLUGIN_VERSION; |
||||
private static final FineLoggerProvider LOGGER = FineLoggerFactory.getLogger(); |
||||
|
||||
static { |
||||
// 判断 null
|
||||
String version = PluginContexts.currentContext().getMarker().getVersion(); |
||||
if (StringUtils.isNotBlank(version)) { |
||||
PLUGIN_VERSION = "[v" + version + "] "; |
||||
} else { |
||||
PLUGIN_VERSION = "[unknown version] "; |
||||
} |
||||
|
||||
LOG_PREFIX = LOG_PREFIX + PLUGIN_VERSION; |
||||
} |
||||
|
||||
public static void setPrefix(String prefix) { |
||||
if (prefix != null) { |
||||
LOG_PREFIX = prefix; |
||||
} |
||||
} |
||||
|
||||
public static boolean isDebugEnabled() { |
||||
return LOGGER.isDebugEnabled(); |
||||
} |
||||
|
||||
public static void debug(String s) { |
||||
if (isDebugEnabled()) { |
||||
LOGGER.debug(LOG_PREFIX + s); |
||||
} |
||||
} |
||||
|
||||
public static void debug(String s, Object... objects) { |
||||
if (isDebugEnabled()) { |
||||
LOGGER.debug(LOG_PREFIX + s, objects); |
||||
} |
||||
} |
||||
|
||||
public static void debug(String s, Throwable throwable) { |
||||
if (isDebugEnabled()) { |
||||
LOGGER.debug(LOG_PREFIX + s, throwable); |
||||
} |
||||
} |
||||
|
||||
public static boolean isInfoEnabled() { |
||||
return LOGGER.isInfoEnabled(); |
||||
} |
||||
|
||||
public static void info(String s) { |
||||
LOGGER.info(LOG_PREFIX + s); |
||||
} |
||||
|
||||
public static void info(String s, Object... objects) { |
||||
LOGGER.info(LOG_PREFIX + s, objects); |
||||
} |
||||
|
||||
public static void warn(String s) { |
||||
LOGGER.warn(LOG_PREFIX + s); |
||||
} |
||||
|
||||
public static void warn(String s, Object... objects) { |
||||
LOGGER.warn(LOG_PREFIX + s, objects); |
||||
} |
||||
|
||||
public static void warn(String s, Throwable throwable) { |
||||
LOGGER.warn(LOG_PREFIX + s, throwable); |
||||
} |
||||
|
||||
public static void warn(Throwable throwable, String s, Object... objects) { |
||||
LOGGER.warn(throwable, LOG_PREFIX + s, objects); |
||||
} |
||||
|
||||
public static void error(String s) { |
||||
LOGGER.error(LOG_PREFIX + s); |
||||
} |
||||
|
||||
public static void error(String s, Object... objects) { |
||||
LOGGER.error(LOG_PREFIX + s, objects); |
||||
} |
||||
|
||||
public static void error(String s, Throwable throwable) { |
||||
LOGGER.error(LOG_PREFIX + s, throwable); |
||||
} |
||||
|
||||
public static void error(Throwable throwable, String s, Object... objects) { |
||||
LOGGER.error(throwable, LOG_PREFIX + s, objects); |
||||
} |
||||
} |
@ -0,0 +1,417 @@
|
||||
package com.fr.plugin.decision.integration.utils; |
||||
|
||||
import com.finebi.cbb.utils.StringEscapeUtils; |
||||
import com.fr.decision.authority.AuthorityContext; |
||||
import com.fr.decision.authority.base.constant.type.operation.ManualOperationType; |
||||
import com.fr.decision.authority.controller.UserController; |
||||
import com.fr.decision.authority.data.*; |
||||
import com.fr.decision.authority.data.extra.user.type.PlatformUserKey; |
||||
import com.fr.decision.authority.data.extra.user.type.UserProductTypeKey; |
||||
import com.fr.decision.authority.data.personnel.DepRole; |
||||
import com.fr.decision.authority.entity.CustomRoleEntity; |
||||
import com.fr.decision.base.util.CollectionUtil; |
||||
import com.fr.decision.base.util.UUIDUtil; |
||||
import com.fr.decision.webservice.annotation.RoleCheckerType; |
||||
import com.fr.decision.webservice.bean.user.DepartmentPostBean; |
||||
import com.fr.decision.webservice.bean.user.UserBean; |
||||
import com.fr.decision.webservice.bean.user.UserUpdateBean; |
||||
import com.fr.decision.webservice.exception.user.AddUserProductTypeException; |
||||
import com.fr.decision.webservice.impl.user.type.UserProductType; |
||||
import com.fr.decision.webservice.utils.ControllerFactory; |
||||
import com.fr.decision.webservice.utils.UserSourceFactory; |
||||
import com.fr.decision.webservice.utils.WebServiceUtils; |
||||
import com.fr.decision.webservice.v10.user.DepartmentService; |
||||
import com.fr.decision.webservice.v10.user.PositionService; |
||||
import com.fr.decision.webservice.v10.user.UserService; |
||||
import com.fr.general.ComparatorUtils; |
||||
import com.fr.plugin.decision.integration.config.IntegrateConf; |
||||
import com.fr.plugin.decision.integration.config.strategy.user.impl.ContainDepRoleStrategy; |
||||
import com.fr.stable.ArrayUtils; |
||||
import com.fr.stable.StringUtils; |
||||
import com.fr.stable.db.data.BaseDataRecord; |
||||
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.*; |
||||
|
||||
public class UserUtils { |
||||
|
||||
public static final String POST_DEFAULT_NAME = "职员"; |
||||
public static final String DEP_ROOT_NAME = null; |
||||
|
||||
public static boolean existUsername(String username) throws Exception { |
||||
return UserService.getInstance().getUserByUserName(username) != null; |
||||
} |
||||
|
||||
public static String getAdminUserId() throws Exception { |
||||
return UserService.getInstance().getAdminUserIdList().get(0); |
||||
} |
||||
|
||||
public static boolean isAdmin(String username) throws Exception { |
||||
return UserService.getInstance().getAdminUserNameList().contains(username); |
||||
} |
||||
|
||||
public static List<String> updateDepTreeAndPost(String depName, String depId) throws Exception { |
||||
ArrayList<String> result = new ArrayList<>(); |
||||
ContainDepRoleStrategy depStrategy = (ContainDepRoleStrategy) IntegrateConf.getInstance().getUserStrategy(); |
||||
switch (depStrategy.getDepStrategy()) { |
||||
case DEP_ID_LENGTH: |
||||
generateDepByIdLength(depName, depId); |
||||
break; |
||||
case DEP_NAME_GROUP: |
||||
depId = generateDepByName(depName, depStrategy.getSeparator()); |
||||
break; |
||||
} |
||||
String postId = generateDefaultPosition(depId); |
||||
result.add(WebServiceUtils.createUniquePostId(depId, postId)); |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 添加部门前先计算出最匹配的父节点,添加完之后在更新父节点下子节点的父信息 |
||||
* |
||||
* @param depName |
||||
* @param depId |
||||
* @return |
||||
* @throws Exception |
||||
*/ |
||||
private static String generateDepByIdLength(String depName, String depId) throws Exception { |
||||
Department department = AuthorityContext.getInstance().getDepartmentController().getById(depId); |
||||
if (department == null) { |
||||
String depPId = getMostSimilarDepId(depId); |
||||
if (checkDuplicatedDepartmentName(depPId, depName)) { |
||||
depName = depName + "_" + depId; |
||||
} |
||||
addDepartment(depName, depId, depPId); |
||||
// 更新depPId下子节点的父信息
|
||||
generateUnderParentDepartment(depPId, depId); |
||||
} |
||||
return depId; |
||||
} |
||||
|
||||
/** |
||||
* 根据部门名称拼接来更新部门 |
||||
* |
||||
* @param depNameGroup |
||||
* @return 部门id |
||||
*/ |
||||
private static String generateDepByName(String depNameGroup, String separator) throws Exception { |
||||
String[] depArr = depNameGroup.split(StringEscapeUtils.escapeRegexSpecialWord(separator)); |
||||
String pId = DEP_ROOT_NAME; |
||||
for (String depName : depArr) { |
||||
Department department = getDepartmentByNameAndPid(depName, pId); |
||||
if (department != null) { |
||||
pId = department.getId(); |
||||
} else { |
||||
String depId = UUIDUtil.generate(); |
||||
addDepartment(depName, depId, pId); |
||||
pId = depId; |
||||
} |
||||
} |
||||
return pId; |
||||
} |
||||
|
||||
private static boolean existDepId(String depId) throws Exception { |
||||
return AuthorityContext.getInstance().getDepartmentController().getById(depId) != null; |
||||
} |
||||
|
||||
private static Department getDepartmentByNameAndPid(String depName, String pId) throws Exception { |
||||
return AuthorityContext.getInstance().getDepartmentController().findOne( |
||||
QueryFactory.create().addRestriction(RestrictionFactory.eq(Department.COLUMN_NAME, depName)) |
||||
.addRestriction(RestrictionFactory.eq(Department.COLUMN_PARENT_ID, pId)) |
||||
); |
||||
} |
||||
|
||||
private static boolean 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); |
||||
return sameNameDep != null; |
||||
} |
||||
|
||||
/** |
||||
* 添加部门 |
||||
* |
||||
* @param depName |
||||
* @param depId |
||||
* @param depPId |
||||
* @throws Exception |
||||
*/ |
||||
private static void addDepartment(String depName, String depId, String depPId) throws Exception { |
||||
Department record = (new Department()).id(depId).name(depName).parentId(depPId).creationType(ManualOperationType.KEY).lastOperationType(ManualOperationType.KEY).enable(true); |
||||
AuthorityContext.getInstance().getDepartmentController().add(record); |
||||
} |
||||
|
||||
private static void generateUnderParentDepartment(String depPId, String depId) throws Exception { |
||||
for (DepartmentPostBean departmentPostBean : DepartmentService.getInstance().getDepartmentsUnderParentDepartment(getAdminUserId(), depPId)) { |
||||
if (ComparatorUtils.equals(depId, departmentPostBean.getId())) continue; |
||||
String mostSimilarDepId = getMostSimilarDepId(departmentPostBean.getId()); |
||||
if (!ComparatorUtils.equals(mostSimilarDepId, depPId)) { |
||||
Department record = AuthorityContext.getInstance().getDepartmentController().getById(departmentPostBean.getId()); |
||||
record.setParentId(mostSimilarDepId); |
||||
AuthorityContext.getInstance().getDepartmentController().update(record); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private static List<Department> getAllDepartment() throws Exception { |
||||
return AuthorityContext.getInstance().getDepartmentController().find(QueryFactory.create()); |
||||
} |
||||
|
||||
/** |
||||
* 校验部门下是否有默认 POST_DEFAULT_NAME 职位 |
||||
* |
||||
* @param departmentId |
||||
* @return POST_DEFAULT_NAME 职位的 id |
||||
* @throws Exception |
||||
*/ |
||||
private static String generateDefaultPosition(String departmentId) throws Exception { |
||||
String adminId = UserService.getInstance().getAdminUserIdList().get(0); |
||||
Post[] posts = ControllerFactory.getInstance().getPostController(adminId).getPositionsUnderParentDepartment(adminId, departmentId, null); |
||||
for (Post post : posts) { |
||||
if (ComparatorUtils.equals(post.getName(), POST_DEFAULT_NAME)) { |
||||
return post.getId(); |
||||
} |
||||
} |
||||
String positionId = getDefaultPostId(); |
||||
AuthorityContext.getInstance().getPostController().addPostToDepartment(positionId, departmentId); |
||||
return positionId; |
||||
} |
||||
|
||||
/** |
||||
* 校验是否有 POST_DEFAULT_NAME 职位,没有的话新建个 |
||||
* |
||||
* @return POST_DEFAULT_NAME 职位的 id |
||||
* @throws Exception |
||||
*/ |
||||
private static String getDefaultPostId() throws Exception { |
||||
String adminId = UserService.getInstance().getAdminUserIdList().get(0); |
||||
Post[] posts = ControllerFactory.getInstance().getPostController(adminId).getPositions(adminId, null); |
||||
for (Post post : posts) { |
||||
if (ComparatorUtils.equals(post.getName(), POST_DEFAULT_NAME)) { |
||||
return post.getId(); |
||||
} |
||||
} |
||||
|
||||
return PositionService.getInstance().addPosition(POST_DEFAULT_NAME).getId(); |
||||
} |
||||
|
||||
/** |
||||
* 计算出与 depId 最相似的父节点 |
||||
* |
||||
* @param depId |
||||
* @return |
||||
* @throws Exception |
||||
*/ |
||||
private static String getMostSimilarDepId(String depId) throws Exception { |
||||
int similarLevel = 0; |
||||
String mostSimilarDepId = DEP_ROOT_NAME; |
||||
String specialDepRootId = ((ContainDepRoleStrategy) IntegrateConf.getInstance().getUserStrategy()).getSpecialRootId(); |
||||
if (StringUtils.isNotBlank(specialDepRootId)) { |
||||
if (ComparatorUtils.equals(depId, specialDepRootId)) { |
||||
return mostSimilarDepId; |
||||
} else if (existDepId(specialDepRootId)) { |
||||
mostSimilarDepId = specialDepRootId; |
||||
} |
||||
} |
||||
for (Department department : getAllDepartment()) { |
||||
String currentDepId = department.getId(); |
||||
// 部门id长度大于当前id长度的直接跳过,因为部门的树结构时根据id其实是否一致判断的
|
||||
if (currentDepId.length() > depId.length() || ComparatorUtils.equals(currentDepId, depId)) continue; |
||||
int currentLevel = getDepIdSimilarityDegree(currentDepId, depId); |
||||
if (currentLevel > similarLevel) { |
||||
similarLevel = currentLevel; |
||||
mostSimilarDepId = department.getId(); |
||||
} |
||||
} |
||||
return mostSimilarDepId; |
||||
} |
||||
|
||||
private static int getDepIdSimilarityDegree(String depId1, String depId2) { |
||||
String shortId, longId; |
||||
if (depId1.length() > depId2.length()) { |
||||
shortId = depId2; |
||||
longId = depId1; |
||||
} else { |
||||
shortId = depId1; |
||||
longId = depId2; |
||||
} |
||||
|
||||
if (longId.startsWith(shortId)) { |
||||
return shortId.length(); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
public static String checkAndAddRole(String roleName) throws Exception { |
||||
CustomRole customRole = AuthorityContext.getInstance().getCustomRoleController().findOne( |
||||
QueryFactory.create().addRestriction( |
||||
RestrictionFactory.eq(CustomRoleEntity.COLUMN_NAME, roleName)) |
||||
); |
||||
if (null != customRole) return customRole.getId(); |
||||
String roleId = UUIDUtil.generate(); |
||||
addRole(roleName, roleId); |
||||
return roleId; |
||||
} |
||||
|
||||
public static void addRole(String roleName, String roleId) throws Exception { |
||||
String adminId = UserService.getInstance().getAdminUserIdList().get(0); |
||||
CustomRole record = (new CustomRole()).id(roleId).name(roleName); |
||||
ControllerFactory.getInstance().getCustomRoleController(adminId).addCustomRole(adminId, record); |
||||
} |
||||
|
||||
/** |
||||
* 更新用户的部门信息 |
||||
* |
||||
* @param currentUserId |
||||
* @param userBean |
||||
* @throws Exception |
||||
*/ |
||||
public static void updateUserDepartmentPost(String currentUserId, UserBean userBean) throws Exception { |
||||
if (userBean.getDepartmentPostIds() != null) { |
||||
List<DepRole> newDepRoleList = new LinkedList(); |
||||
Iterator depRoleIt = userBean.getDepartmentPostIds().iterator(); |
||||
|
||||
while (depRoleIt.hasNext()) { |
||||
String depPostId = (String) depRoleIt.next(); |
||||
DepRole depRole = WebServiceUtils.parseUniqueDepartmentPostId(depPostId); |
||||
newDepRoleList.add(AuthorityContext.getInstance().getDepartmentController().getDepRole(depRole.getDepartmentId(), depRole.getPostId())); |
||||
} |
||||
|
||||
List<DepRole> oldDepRoleList = AuthorityContext.getInstance().getDepartmentController().findDepRoleByUser(userBean.getId()); |
||||
Map<String, DepRole> newIdDepRoleMap = CollectionUtil.convertToMap(newDepRoleList, BaseDataRecord::getId); |
||||
Map<String, DepRole> oldIdDepRoleMap = CollectionUtil.convertToMap(oldDepRoleList, BaseDataRecord::getId); |
||||
List<String> newDepRoleIdList = new LinkedList(newIdDepRoleMap.keySet()); |
||||
List<String> oldDepRoleIdList = new LinkedList(oldIdDepRoleMap.keySet()); |
||||
List<String> addDepRoleIdList = new LinkedList(newDepRoleIdList); |
||||
List<String> removeDepRoleIdList = new LinkedList(oldDepRoleIdList); |
||||
addDepRoleIdList.removeAll(oldDepRoleIdList); |
||||
removeDepRoleIdList.removeAll(newDepRoleIdList); |
||||
User targetUser = UserService.getInstance().getUserByUserId(userBean.getId()); |
||||
Iterator addDepRoleIt = addDepRoleIdList.iterator(); |
||||
|
||||
String removeDepRoleId; |
||||
DepRole depRole; |
||||
while (addDepRoleIt.hasNext()) { |
||||
removeDepRoleId = (String) addDepRoleIt.next(); |
||||
depRole = newIdDepRoleMap.get(removeDepRoleId); |
||||
if (RoleCheckerType.DEPARTMENT.checkAuthority(currentUserId, depRole.getDepartmentId())) { |
||||
Department department = AuthorityContext.getInstance().getDepartmentController().getById(depRole.getDepartmentId()); |
||||
Post post = AuthorityContext.getInstance().getPostController().getById(depRole.getPostId()); |
||||
UserSourceFactory.getInstance().checkSource(targetUser, department); |
||||
UserSourceFactory.getInstance().checkSource(targetUser, post); |
||||
AuthorityContext.getInstance().getUserController().addUserToDepartmentAndPost(targetUser.getId(), depRole.getDepartmentId(), depRole.getPostId()); |
||||
} |
||||
} |
||||
|
||||
addDepRoleIt = removeDepRoleIdList.iterator(); |
||||
|
||||
while (addDepRoleIt.hasNext()) { |
||||
removeDepRoleId = (String) addDepRoleIt.next(); |
||||
depRole = oldIdDepRoleMap.get(removeDepRoleId); |
||||
if (RoleCheckerType.DEPARTMENT.checkAuthority(currentUserId, depRole.getDepartmentId())) { |
||||
AuthorityContext.getInstance().getUserController().removeUserFromDepartmentAndPost(targetUser.getId(), depRole.getDepartmentId(), depRole.getPostId()); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 更新用户平台的类型 |
||||
* |
||||
* @param userBean |
||||
* @param platformTypeList |
||||
* @throws Exception |
||||
*/ |
||||
public static void updateUserPlatformType(UserBean userBean, List<Integer> platformTypeList) throws Exception { |
||||
UserController userController = AuthorityContext.getInstance().getUserController(); |
||||
// 查询用户的平台用户类型
|
||||
List<ExtraProperty> extraProperties = userController.findUserExtraProperty(QueryFactory.create().addRestriction( |
||||
RestrictionFactory.eq(ExtraProperty.COLUMN_RELEATED_ID, userBean.getId()) |
||||
).addRestriction( |
||||
RestrictionFactory.startWith(ExtraProperty.COLUMN_NAME, UserProductTypeKey.KEY.getKey()) |
||||
)); |
||||
List<Integer> newIdList = new LinkedList(platformTypeList); |
||||
List<Integer> oldIdList = new LinkedList(); |
||||
for (ExtraProperty property : extraProperties) { |
||||
UserProductTypeKey userProductTypeKey = (UserProductTypeKey) PlatformUserKey.fromKey(property.getName()); |
||||
oldIdList.add(UserProductType.fromKey(userProductTypeKey).toInteger()); |
||||
} |
||||
|
||||
// 校验新的用户平台类型是否冲突
|
||||
for (int i=0; i<platformTypeList.size(); i++) { |
||||
UserProductType leftType = UserProductType.fromInteger(platformTypeList.get(i)); |
||||
for (int j=i+1; j<platformTypeList.size(); j++) { |
||||
UserProductType rightType = UserProductType.fromInteger(platformTypeList.get(j)); |
||||
if (ArrayUtils.contains(leftType.excludeProductKeys(), rightType.transProductKey())) { |
||||
throw new IllegalArgumentException("add user platform type illegal " + platformTypeList); |
||||
} |
||||
} |
||||
} |
||||
|
||||
LogUtils.debug("update user platform type, old type:{} new type:{}", oldIdList, newIdList); |
||||
List<Integer> addIdList = new LinkedList(newIdList); |
||||
List<Integer> removeIdList = new LinkedList(oldIdList); |
||||
addIdList.removeAll(oldIdList); |
||||
removeIdList.removeAll(newIdList); |
||||
|
||||
// 删除用户原有平台类型
|
||||
for (Integer i : removeIdList) { |
||||
userController.removeUserProductType(userBean.getId(), UserProductType.fromInteger(i).transProductKey()); |
||||
} |
||||
|
||||
// 添加新增部分的平台类型
|
||||
out: |
||||
for (Integer platformType : addIdList) { |
||||
UserProductType userProductType = UserProductType.fromInteger(platformType); |
||||
if (!userProductType.isNoLimitEditOpen()) { |
||||
continue out; |
||||
} |
||||
|
||||
if (userProductType.allowMax() > 0 && 1 > userProductType.leftRegisterTotal()) { |
||||
throw new AddUserProductTypeException(); |
||||
} |
||||
userController.addUserProductType(userBean.getId(), userProductType.transProductKey()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 随机生成强密码 |
||||
* |
||||
* @param len |
||||
* @return |
||||
*/ |
||||
public static String getRandomPassword(int len) { |
||||
// 密码字典
|
||||
char[] str = { |
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', |
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', |
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '~', '!', '@', '#', '$', '%', '^', '-', '+' |
||||
}; |
||||
StringBuffer pwd = null; |
||||
boolean flag = false; |
||||
while (!flag) { |
||||
int a = 0, b = 0, c = 0, d = 0; |
||||
pwd = new StringBuffer(); |
||||
for (int i = 0; i < len; i++) { |
||||
int rand = (int) (Math.random() * str.length); |
||||
pwd.append(str[rand]); |
||||
if (rand < 26) { |
||||
a++; |
||||
} else if (rand < 52) { |
||||
b++; |
||||
} else if (rand < 62) { |
||||
c++; |
||||
} else { |
||||
d++; |
||||
} |
||||
} |
||||
flag = (a * b * c * d != 0); |
||||
} |
||||
return pwd.toString(); |
||||
} |
||||
} |
@ -0,0 +1,42 @@
|
||||
!(function () { |
||||
var Item = BI.inherit(BI.Widget, { |
||||
props: { |
||||
value: "", |
||||
items: [], |
||||
changeAction: BI.emptyFn() |
||||
}, |
||||
|
||||
render: function () { |
||||
var self = this, o = this.options; |
||||
return { |
||||
type: "bi.button_group", |
||||
value: o.value + "", |
||||
layouts: [{ |
||||
type: "bi.vertical_adapt" |
||||
}], |
||||
items: BI.createItems(o.items, { |
||||
type: "bi.single_select_radio_item", |
||||
height: 16, |
||||
logic: { |
||||
dynamic: true |
||||
}, |
||||
cls: "bi-list-item-none" |
||||
}), |
||||
listeners: [{ |
||||
eventName: BI.ButtonGroup.EVENT_CHANGE, |
||||
action: function (e) { |
||||
o.changeAction && o.changeAction(e); |
||||
} |
||||
}], |
||||
ref: function (_ref) { |
||||
self.group = _ref; |
||||
} |
||||
} |
||||
}, |
||||
|
||||
getValue: function () { |
||||
return this.group.getValue()[0]; |
||||
} |
||||
}); |
||||
BI.shortcut("dec.plugin.system.integration.group", Item); |
||||
})(); |
@ -0,0 +1,17 @@
|
||||
!(function () { |
||||
BI.constant("plugin.integration.userCreate", [{ |
||||
value: "0", text: "仅用户名", userType: "onlyUser" |
||||
}, { |
||||
value: "1", text: "包含部门职位", userType: "containDepRole" |
||||
}]); |
||||
BI.constant("plugin.integration.pwd", [{ |
||||
value: "0", text: "同用户名" |
||||
}, { |
||||
value: "1", text: "随机密码" |
||||
}]); |
||||
BI.constant("plugin.integration.dep", [{ |
||||
value: "0", text: "部门ID长度构建部门树" |
||||
}, { |
||||
value: "1", text: "部门名称拼接构建部门树" |
||||
}]); |
||||
})(); |
@ -0,0 +1,44 @@
|
||||
!(function () { |
||||
var user_only = BI.Constants.getConstant("plugin.integration.userCreate")[0], |
||||
user_roledep = BI.Constants.getConstant("plugin.integration.userCreate")[1]; |
||||
var Model = BI.inherit(Fix.Model, { |
||||
state: function () { |
||||
return { |
||||
config: {} |
||||
} |
||||
}, |
||||
|
||||
computed: { |
||||
userType: function () { |
||||
return this.model.config.userStrategy.userType === user_only.userType ? user_only.value : user_roledep.value; |
||||
} |
||||
}, |
||||
|
||||
actions: { |
||||
initData: function (cb) { |
||||
var self = this; |
||||
Dec.Utils.getPluginIntegrateConfig(function (res) { |
||||
if (!res.errorCode) { |
||||
self.model.config = res; |
||||
cb(); |
||||
} |
||||
}) |
||||
}, |
||||
|
||||
changeUserType: function (v) { |
||||
this.model.config.userStrategy.userType = (v === user_only.value ? user_only.userType : user_roledep.userType) |
||||
}, |
||||
|
||||
saveData: function (value) { |
||||
Dec.Utils.updatePluginIntegrateConfig(value, function (res) { |
||||
if (res.data === "success") { |
||||
BI.Msg.toast("保存成功!", {level: "success"}) |
||||
} else { |
||||
BI.Msg.toast("保存失败!", {level: "error"}) |
||||
} |
||||
}) |
||||
} |
||||
} |
||||
}); |
||||
BI.model("dec.plugin.system.integration.model", Model); |
||||
})(); |
@ -0,0 +1,510 @@
|
||||
!(function () { |
||||
var WIDGET_HEIGHT = 24; |
||||
var user_only = BI.Constants.getConstant("plugin.integration.userCreate")[0], |
||||
user_roledep = BI.Constants.getConstant("plugin.integration.userCreate")[1]; |
||||
var dep_legnth = BI.Constants.getConstant("plugin.integration.dep")[0]; |
||||
|
||||
var Pane = BI.inherit(BI.Widget, { |
||||
props: { |
||||
baseCls: "dec-plugin-system-integration" |
||||
}, |
||||
_store: function () { |
||||
return BI.Models.getModel("dec.plugin.system.integration.model"); |
||||
}, |
||||
beforeInit: function (cb) { |
||||
this.store.initData(cb); |
||||
}, |
||||
render: function () { |
||||
var self = this; |
||||
var createUserInfoPane = { |
||||
type: "bi.vertical", |
||||
lgap: 10, bgap: 10, |
||||
ref: function (_ref) { |
||||
self.createUserInfoPane = _ref; |
||||
}, |
||||
invisible: !self.model.config.createUserTurnOn, |
||||
items: [{ |
||||
type: "bi.vertical_adapt", |
||||
height: 24, |
||||
items: [{ |
||||
type: "bi.label", |
||||
textAlign: "left", |
||||
cls: "dec-font-weight-bold", |
||||
text: "创建远程连接同名目录", |
||||
title: "创建远程连接同名目录", |
||||
width: 210 |
||||
}, { |
||||
type: "dec.switch_button", |
||||
value: self.model.config.remoteFolder, |
||||
ref: function (_ref) { |
||||
self.remoteFolder = _ref; |
||||
} |
||||
}] |
||||
}, { |
||||
type: "bi.vertical_adapt", |
||||
height: WIDGET_HEIGHT, |
||||
items: [{ |
||||
type: "bi.label", |
||||
textAlign: "left", |
||||
cls: "dec-font-weight-bold", |
||||
text: "用户创建策略", |
||||
width: 210 |
||||
}, { |
||||
type: "dec.plugin.system.integration.group", |
||||
value: self.model.userType, |
||||
items: BI.Constants.getConstant("plugin.integration.userCreate"), |
||||
changeAction: function (e) { |
||||
self.depStrategyPane.setVisible(e === user_roledep.value); |
||||
self.store.changeUserType(e); |
||||
}, |
||||
ref: function (_ref) { |
||||
self.userCreate = _ref; |
||||
} |
||||
}] |
||||
}, { |
||||
type: "bi.vertical_adapt", |
||||
height: WIDGET_HEIGHT, |
||||
items: [{ |
||||
type: "bi.label", |
||||
textAlign: "left", |
||||
cls: "dec-font-weight-bold", |
||||
text: "密码策略", |
||||
width: 210 |
||||
}, { |
||||
type: "dec.plugin.system.integration.group", |
||||
value: self.model.config.userStrategy.pwdStrategy, |
||||
items: BI.Constants.getConstant("plugin.integration.pwd"), |
||||
ref: function (_ref) { |
||||
self.pwd = _ref; |
||||
} |
||||
}] |
||||
}, { |
||||
type: "bi.vertical", |
||||
bgap: 10, |
||||
invisible: self.model.userType === user_only.value, |
||||
items: [{ |
||||
type: "bi.vertical_adapt", |
||||
height: WIDGET_HEIGHT, |
||||
items: [{ |
||||
type: "bi.label", |
||||
textAlign: "left", |
||||
cls: "dec-font-weight-bold", |
||||
text: "创建部门策略", |
||||
width: 210 |
||||
}, { |
||||
type: "dec.plugin.system.integration.group", |
||||
value: self.model.config.userStrategy.depStrategy || dep_legnth.value, |
||||
items: BI.Constants.getConstant("plugin.integration.dep"), |
||||
ref: function (_ref) { |
||||
self.dep = _ref; |
||||
}, |
||||
changeAction: function (e) { |
||||
var depLen = e == 0; |
||||
self.specialRootId.setVisible(depLen); |
||||
self.separator.setVisible(!depLen); |
||||
}, |
||||
}] |
||||
}, { |
||||
type: "dec.label.editor.item", |
||||
textWidth: 210, |
||||
invisible: BI.isKey(self.model.config.userStrategy.depStrategy) && self.model.config.userStrategy.depStrategy != 0, |
||||
cls: "dec-font-weight-bold", |
||||
text: "特殊根部门ID", |
||||
editorWidth: 180, |
||||
value: self.model.config.userStrategy.specialRootId, |
||||
ref: function (_ref) { |
||||
self.specialRootId = _ref |
||||
} |
||||
}, { |
||||
type: "dec.label.editor.item", |
||||
textWidth: 210, |
||||
invisible: self.model.config.userStrategy.depStrategy != 1, |
||||
cls: "dec-font-weight-bold", |
||||
text: "分隔符", |
||||
editorWidth: 180, |
||||
value: self.model.config.userStrategy.separator, |
||||
ref: function (_ref) { |
||||
self.separator = _ref |
||||
} |
||||
}], |
||||
ref: function (_ref) { |
||||
self.depStrategyPane = _ref; |
||||
} |
||||
}] |
||||
}; |
||||
|
||||
|
||||
return { |
||||
type: "bi.vertical", |
||||
cls: "bi-card", |
||||
hgap: 10, |
||||
items: [{ |
||||
type: "dec.card.vertical", |
||||
text: "配置项", |
||||
content: { |
||||
type: "bi.vertical", |
||||
vgap: 10, |
||||
items: [{ |
||||
type: "dec.label.editor.item", |
||||
textWidth: 210, |
||||
cls: "dec-font-weight-bold", |
||||
text: "帆软平台地址", |
||||
title: "帆软平台地址", |
||||
watermark: "http(s)://ip:port/webroot/decision", |
||||
editorWidth: 300, |
||||
value: self.model.config.decisionUrl, |
||||
ref: function (_ref) { |
||||
self.decisionUrl = _ref |
||||
} |
||||
}, { |
||||
type: "dec.label.editor.item", |
||||
textWidth: 210, |
||||
cls: "dec-font-weight-bold", |
||||
text: "Jwt 密钥值", |
||||
editorWidth: 300, |
||||
value: self.model.config.jwtKey, |
||||
ref: function (_ref) { |
||||
self.jwtKey = _ref |
||||
} |
||||
}, { |
||||
type: "bi.vertical_adapt", |
||||
height: 24, |
||||
items: [{ |
||||
type: "bi.label", |
||||
textAlign: "left", |
||||
cls: "dec-font-weight-bold", |
||||
text: "认证完成创建用户", |
||||
title: "Jwt Token认证用户在平台中不存在时,自动在平台中创建用户信息", |
||||
width: 210 |
||||
}, { |
||||
type: "dec.switch_button", |
||||
value: self.model.config.createUserTurnOn, |
||||
listeners: [{ |
||||
eventName: "EVENT_CHANGE", |
||||
action: function () { |
||||
self.createUserInfoPane.setVisible(this.getValue()); |
||||
} |
||||
}], |
||||
ref: function (_ref) { |
||||
self.createUserTurnOn = _ref; |
||||
} |
||||
}] |
||||
}, createUserInfoPane, { |
||||
type: "bi.vertical_adapt", |
||||
height: 24, |
||||
items: [{ |
||||
type: "bi.label", |
||||
textAlign: "left", |
||||
cls: "dec-font-weight-bold", |
||||
text: "模板预览参数校验", |
||||
width: 210 |
||||
}, { |
||||
type: "dec.switch_button", |
||||
value: self.model.config.paraCheckTurnOn, |
||||
listeners: [{ |
||||
eventName: "EVENT_CHANGE", |
||||
action: function () { |
||||
self.paraCheckPane.setVisible(this.getValue()); |
||||
} |
||||
}], |
||||
ref: function (_ref) { |
||||
self.paraCheckTurnOn = _ref; |
||||
} |
||||
}] |
||||
}, { |
||||
type: "bi.vertical", |
||||
lgap: 10, bgap: 10, |
||||
invisible: !self.model.config.paraCheckTurnOn, |
||||
items: [{ |
||||
type: "dec.label.editor.item", |
||||
textWidth: 210, |
||||
cls: "dec-font-weight-bold", |
||||
text: "校验地址", |
||||
title: "校验地址", |
||||
editorWidth: 180, |
||||
value: self.model.config.paraCheckUrl, |
||||
ref: function (_ref) { |
||||
self.paraCheckUrl = _ref |
||||
} |
||||
}], |
||||
ref: function (_ref) { |
||||
self.paraCheckPane = _ref |
||||
} |
||||
}, { |
||||
type: "bi.vertical_adapt", |
||||
height: 24, |
||||
items: [{ |
||||
type: "bi.label", |
||||
textAlign: "left", |
||||
cls: "dec-font-weight-bold", |
||||
text: "远程设计连接开启token校验", |
||||
width: 210 |
||||
}, { |
||||
type: "dec.switch_button", |
||||
value: self.model.config.remoteTokenAuth, |
||||
ref: function (_ref) { |
||||
self.remoteTokenAuth = _ref; |
||||
} |
||||
}] |
||||
}, { |
||||
type: "bi.vertical_adapt", |
||||
height: 24, |
||||
items: [{ |
||||
type: "bi.label", |
||||
textAlign: "left", |
||||
cls: "dec-font-weight-bold", |
||||
text: "用户信息是否进行AES加密", |
||||
title: "Jwt Token中的 subject 字段是否使用 AES/ECB/PKCS5Padding 加密", |
||||
width: 210 |
||||
}, { |
||||
type: "dec.switch_button", |
||||
value: self.model.config.aesEncryptSubject, |
||||
ref: function (_ref) { |
||||
self.aesEncryptSubjectButton = _ref; |
||||
}, |
||||
listeners: [{ |
||||
eventName: "EVENT_CHANGE", |
||||
action: function () { |
||||
self.aesEncryptKeyPane.setVisible(this.getValue()); |
||||
} |
||||
}], |
||||
}] |
||||
}, { |
||||
type: "bi.vertical", |
||||
lgap: 10, bgap: 10, |
||||
invisible: !self.model.config.aesEncryptSubject, |
||||
items: [{ |
||||
type: "dec.label.editor.item", |
||||
textWidth: 210, |
||||
cls: "dec-font-weight-bold", |
||||
text: "AES加密密钥(16位)", |
||||
title: "AES加密密钥", |
||||
editorWidth: 180, |
||||
value: self.model.config.aesEncryptKey, |
||||
ref: function (_ref) { |
||||
self.aesEncryptKeyEditor = _ref |
||||
} |
||||
}], |
||||
ref: function (_ref) { |
||||
self.aesEncryptKeyPane = _ref |
||||
} |
||||
}, /*{ |
||||
type: "bi.vertical_adapt", |
||||
height: 24, |
||||
items: [{ |
||||
type: "bi.label", |
||||
textAlign: "left", |
||||
cls: "dec-font-weight-bold", |
||||
text: "自定义登录页", |
||||
title: "页面未登录时跳转至指定URL地址替代帆软登录页", |
||||
width: 210 |
||||
}, { |
||||
type: "dec.switch_button", |
||||
value: self.model.config.portalURLTurnOn, |
||||
ref: function (_ref) { |
||||
self.portalURLTurnOnBtn = _ref; |
||||
}, |
||||
listeners: [{ |
||||
eventName: "EVENT_CHANGE", |
||||
action: function () { |
||||
self.portalURLPane.setVisible(this.getValue()); |
||||
} |
||||
}], |
||||
}] |
||||
}, { |
||||
type: "bi.vertical", |
||||
lgap: 10, bgap: 10, |
||||
invisible: !self.model.config.portalURLTurnOn, |
||||
items: [{ |
||||
type: "dec.label.editor.item", |
||||
textWidth: 210, |
||||
cls: "dec-font-weight-bold", |
||||
text: "地址", |
||||
title: "自定义登录页地址", |
||||
editorWidth: 180, |
||||
value: self.model.config.portalURL, |
||||
ref: function (_ref) { |
||||
self.portalURLEditor = _ref |
||||
} |
||||
}], |
||||
ref: function (_ref) { |
||||
self.portalURLPane = _ref |
||||
} |
||||
}, */{ |
||||
type: "bi.vertical_adapt", |
||||
height: 24, |
||||
items: [{ |
||||
type: "bi.label", |
||||
textAlign: "left", |
||||
cls: "dec-font-weight-bold", |
||||
text: "跨域功能", |
||||
title: "开启后会在 response 中会添加允许的请求头", |
||||
width: 210 |
||||
}, { |
||||
type: "dec.switch_button", |
||||
value: self.model.config.crossDomain, |
||||
ref: function (_ref) { |
||||
self.crossDomainBtn = _ref; |
||||
} |
||||
}] |
||||
}] |
||||
}, |
||||
listeners: [{ |
||||
eventName: "EVENT_CHANGE", |
||||
action: function () { |
||||
self.validate() && self.store.saveData(self.getValue()); |
||||
} |
||||
}] |
||||
}, { |
||||
type: "bi.vertical_adapt", |
||||
height: 24, |
||||
items: [{ |
||||
type: "bi.label", |
||||
textAlign: "left", |
||||
cls: "dec-font-weight-bold", |
||||
text: "显示唤醒设计器", |
||||
title: "平台首页地址显示唤醒设计器功能", |
||||
width: 210 |
||||
}, { |
||||
type: "dec.switch_button", |
||||
value: self.model.config.webStartDesigner, |
||||
ref: function (_ref) { |
||||
self.webStartDesigner = _ref; |
||||
}, |
||||
listeners: [{ |
||||
eventName: "EVENT_CHANGE", |
||||
action: function () { |
||||
self.downloadURLPane.setVisible(this.getValue()); |
||||
} |
||||
}], |
||||
}] |
||||
}, { |
||||
type: "bi.vertical", |
||||
lgap: 10, vgap: 10, |
||||
invisible: !self.model.config.webStartDesigner, |
||||
items: [{ |
||||
type: "dec.label.editor.item", |
||||
textWidth: 210, |
||||
cls: "dec-font-weight-bold", |
||||
text: "64位设计器下载地址", |
||||
title: "64位设计器下载地址", |
||||
editorWidth: 500, |
||||
value: self.model.config.downloadUrl64, |
||||
ref: function (_ref) { |
||||
self.downloadUrl64 = _ref |
||||
} |
||||
}, { |
||||
type: "dec.label.editor.item", |
||||
textWidth: 210, |
||||
cls: "dec-font-weight-bold", |
||||
text: "32位设计器下载地址", |
||||
title: "32位设计器下载地址", |
||||
editorWidth: 500, |
||||
value: self.model.config.downloadUrl32, |
||||
ref: function (_ref) { |
||||
self.downloadUrl32 = _ref |
||||
} |
||||
}], |
||||
ref: function (_ref) { |
||||
self.downloadURLPane = _ref |
||||
} |
||||
}] |
||||
|
||||
} |
||||
}, |
||||
|
||||
aesValidate: function () { |
||||
var editor = this.aesEncryptKeyEditor; |
||||
return editor.getValue().length == 16 ? true : (editor.showError("AES密钥长度需为16"), false); |
||||
}, |
||||
|
||||
validate: function () { |
||||
if (!BI.isKey(this.decisionUrl.getValue())) { |
||||
BI.Msg.toast("帆软平台地址不允许为空", {level: "error"}); |
||||
return false; |
||||
} |
||||
if (this.aesEncryptSubjectButton.getValue()) { |
||||
return this.aesValidate(); |
||||
} |
||||
if (this.webStartDesigner.getValue()) { |
||||
if (!BI.isKey(this.downloadUrl32.getValue())) { |
||||
BI.Msg.toast("32位下载地址不允许为空", {level: "error"}); |
||||
return false; |
||||
} |
||||
if (!BI.isKey(this.downloadUrl64.getValue())) { |
||||
BI.Msg.toast("64位下载地址不允许为空", {level: "error"}); |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
}, |
||||
|
||||
getValue: function () { |
||||
var self = this; |
||||
var value = { |
||||
decisionUrl: self.decisionUrl.getValue(), |
||||
jwtKey: self.jwtKey.getValue(), |
||||
remoteTokenAuth: self.remoteTokenAuth.getValue(), |
||||
aesEncryptSubject: self.aesEncryptSubjectButton.getValue(), |
||||
aesEncryptKey: self.aesEncryptKeyEditor.getValue(), |
||||
/*portalURLTurnOn: self.portalURLTurnOnBtn.getValue(), |
||||
portalURL: self.portalURLEditor.getValue(),*/ |
||||
crossDomain: self.crossDomainBtn.getValue(), |
||||
remoteFolder: self.remoteFolder.getValue() |
||||
}; |
||||
|
||||
if (self.createUserTurnOn.getValue()) { |
||||
var userStrategy = { |
||||
pwdStrategy: self.pwd.getValue() |
||||
}; |
||||
switch (self.userCreate.getValue()) { |
||||
case user_only.value: |
||||
BI.extend(userStrategy, { |
||||
userType: user_only.userType |
||||
}); |
||||
break; |
||||
case user_roledep.value: |
||||
BI.extend(userStrategy, { |
||||
userType: user_roledep.userType, |
||||
depStrategy: self.dep.getValue(), |
||||
specialRootId: self.specialRootId.getValue(), |
||||
separator: self.separator.getValue() |
||||
}); |
||||
break; |
||||
} |
||||
BI.extend(value, { |
||||
createUserTurnOn: true, |
||||
userStrategy: userStrategy |
||||
}); |
||||
} else { |
||||
BI.extend(value, { |
||||
createUserTurnOn: false |
||||
}) |
||||
} |
||||
|
||||
if (self.paraCheckTurnOn.getValue()) { |
||||
BI.extend(value, { |
||||
paraCheckTurnOn: true, |
||||
paraCheckUrl: self.paraCheckUrl.getValue() |
||||
}) |
||||
} else { |
||||
BI.extend(value, { |
||||
paraCheckTurnOn: false |
||||
}) |
||||
} |
||||
|
||||
var webStartDesigner = self.webStartDesigner.getValue(); |
||||
value.webStartDesigner = webStartDesigner; |
||||
if (webStartDesigner) { |
||||
BI.extend(value, { |
||||
downloadUrl64: self.downloadUrl64.getValue(), |
||||
downloadUrl32: self.downloadUrl32.getValue(), |
||||
}) |
||||
} |
||||
console.log(value); |
||||
return value; |
||||
} |
||||
}); |
||||
|
||||
BI.shortcut("dec.plugin.system.integration", Pane); |
||||
})(); |
@ -0,0 +1,35 @@
|
||||
!(function () { |
||||
BI.Plugin.config(function (type, options) { |
||||
}, function (type, object) { |
||||
object.element.attr("shortcut", object.options.type); |
||||
}); |
||||
|
||||
Dec.Utils = Dec.Utils || {}; |
||||
BI.extend(Dec.Utils, { |
||||
getPluginIntegrateConfig: function (callback) { |
||||
Dec.reqGet("/third/auth/conf", "", callback); |
||||
}, |
||||
updatePluginIntegrateConfig: function (val, callback) { |
||||
Dec.reqPost("/third/auth/conf", val, callback); |
||||
}, |
||||
getWebStartInfo: function (callback) { |
||||
Dec.reqGet("/third/auth/username/token", "", callback); |
||||
} |
||||
}); |
||||
|
||||
BI.config("dec.constant.system.tabs", function (items) { |
||||
items.push({ |
||||
value: "integration", |
||||
text: "登录集成", |
||||
cardType: "dec.plugin.system.integration" |
||||
}); |
||||
return items; |
||||
}); |
||||
|
||||
var commonPath = Dec.fineServletURL + "/file?path=com/fr/plugin/decision/integration/web/js/"; |
||||
BI.$import(commonPath + "constant.js"); |
||||
BI.$import(commonPath + "button_group.item.js"); |
||||
BI.$import(commonPath + "model.pane.js"); |
||||
BI.$import(commonPath + "pane.js"); |
||||
BI.$import(commonPath + "protocolcheck.js"); |
||||
})(); |
@ -0,0 +1,263 @@
|
||||
(function (f) { |
||||
if (typeof exports === "object" && typeof module !== "undefined") { |
||||
module.exports = f() |
||||
} else if (typeof define === "function" && define.amd) { |
||||
define([], f) |
||||
} else { |
||||
var g; |
||||
if (typeof window !== "undefined") { |
||||
g = window |
||||
} else if (typeof global !== "undefined") { |
||||
g = global |
||||
} else if (typeof self !== "undefined") { |
||||
g = self |
||||
} else { |
||||
g = this |
||||
} |
||||
g.protocolCheck = f() |
||||
} |
||||
})(function () { |
||||
var define, module, exports; |
||||
return (function e(t, n, r) { |
||||
function s(o, u) { |
||||
if (!n[o]) { |
||||
if (!t[o]) { |
||||
var a = typeof require == "function" && require; |
||||
if (!u && a) return a(o, !0); |
||||
if (i) return i(o, !0); |
||||
var f = new Error("Cannot find module '" + o + "'"); |
||||
throw f.code = "MODULE_NOT_FOUND", f |
||||
} |
||||
var l = n[o] = {exports: {}}; |
||||
t[o][0].call(l.exports, function (e) { |
||||
var n = t[o][1][e]; |
||||
return s(n ? n : e) |
||||
}, l, l.exports, e, t, n, r) |
||||
} |
||||
return n[o].exports |
||||
} |
||||
|
||||
var i = typeof require == "function" && require; |
||||
for (var o = 0; o < r.length; o++) s(r[o]); |
||||
return s |
||||
})({ |
||||
1: [function (require, module, exports) { |
||||
function _registerEvent(target, eventType, cb) { |
||||
if (target.addEventListener) { |
||||
target.addEventListener(eventType, cb); |
||||
return { |
||||
remove: function () { |
||||
target.removeEventListener(eventType, cb); |
||||
} |
||||
}; |
||||
} else { |
||||
target.attachEvent(eventType, cb); |
||||
return { |
||||
remove: function () { |
||||
target.detachEvent(eventType, cb); |
||||
} |
||||
}; |
||||
} |
||||
} |
||||
|
||||
function _createHiddenIframe(target, uri) { |
||||
var iframe = document.createElement("iframe"); |
||||
iframe.src = uri; |
||||
iframe.id = "hiddenIframe"; |
||||
iframe.style.display = "none"; |
||||
target.appendChild(iframe); |
||||
|
||||
return iframe; |
||||
} |
||||
|
||||
function openUriWithHiddenFrame(uri, failCb, successCb) { |
||||
|
||||
var timeout = setTimeout(function () { |
||||
failCb(); |
||||
handler.remove(); |
||||
}, 1000); |
||||
|
||||
var iframe = document.querySelector("#hiddenIframe"); |
||||
if (!iframe) { |
||||
iframe = _createHiddenIframe(document.body, "about:blank"); |
||||
} |
||||
|
||||
var handler = _registerEvent(window, "blur", onBlur); |
||||
|
||||
function onBlur() { |
||||
clearTimeout(timeout); |
||||
handler.remove(); |
||||
successCb(); |
||||
} |
||||
|
||||
iframe.contentWindow.location.href = uri; |
||||
} |
||||
|
||||
function openUriWithTimeoutHack(uri, failCb, successCb) { |
||||
|
||||
var timeout = setTimeout(function () { |
||||
failCb(); |
||||
handler.remove(); |
||||
}, 1000); |
||||
|
||||
//handle page running in an iframe (blur must be registered with top level window)
|
||||
var target = window; |
||||
while (target != target.parent) { |
||||
target = target.parent; |
||||
} |
||||
|
||||
var handler = _registerEvent(target, "blur", onBlur); |
||||
|
||||
function onBlur() { |
||||
clearTimeout(timeout); |
||||
handler.remove(); |
||||
successCb(); |
||||
} |
||||
|
||||
window.location = uri; |
||||
} |
||||
|
||||
function openUriUsingFirefox(uri, failCb, successCb) { |
||||
var iframe = document.querySelector("#hiddenIframe"); |
||||
|
||||
if (!iframe) { |
||||
iframe = _createHiddenIframe(document.body, "about:blank"); |
||||
} |
||||
|
||||
try { |
||||
iframe.contentWindow.location.href = uri; |
||||
successCb(); |
||||
} catch (e) { |
||||
if (e.name == "NS_ERROR_UNKNOWN_PROTOCOL") { |
||||
alert("Un Kown!") |
||||
failCb(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
function openUriWithIE11UsingRegistry(uri, failCb, successCb) { |
||||
var shell = new ActiveXObject("WScript.shell"); |
||||
try { |
||||
var reg = shell.RegRead("HKEY_CLASSES_ROOT\\glcloud\\URL Protocol"); |
||||
if (reg) { |
||||
console.log(reg); |
||||
window.location.href = uri; |
||||
} |
||||
successCb(); |
||||
} catch (e) { |
||||
failCb(); |
||||
} |
||||
|
||||
} |
||||
|
||||
function openUriUsingIEInOlderWindows(uri, failCb, successCb) { |
||||
if (getInternetExplorerVersion() === 10) { |
||||
openUriUsingIE10InWindows7(uri, failCb, successCb); |
||||
} else if (getInternetExplorerVersion() === 9 || getInternetExplorerVersion() === 11) { |
||||
/*openUriWithHiddenFrame(uri, failCb, successCb);*/ |
||||
openUriWithIE11UsingRegistry(uri, failCb, successCb); |
||||
} else { |
||||
openUriInNewWindowHack(uri, failCb, successCb); |
||||
} |
||||
} |
||||
|
||||
function openUriUsingIE10InWindows7(uri, failCb, successCb) { |
||||
var timeout = setTimeout(failCb, 6000); |
||||
window.addEventListener("blur", function () { |
||||
clearTimeout(timeout); |
||||
successCb(); |
||||
}); |
||||
|
||||
var iframe = document.querySelector("#hiddenIframe"); |
||||
if (!iframe) { |
||||
iframe = _createHiddenIframe(document.body, "about:blank"); |
||||
} |
||||
try { |
||||
iframe.contentWindow.location.href = uri; |
||||
} catch (e) { |
||||
failCb(); |
||||
clearTimeout(timeout); |
||||
} |
||||
} |
||||
|
||||
function openUriInNewWindowHack(uri, failCb, successCb) { |
||||
var myWindow = window.open('', '', 'width=0,height=0'); |
||||
|
||||
myWindow.document.write("<iframe src='" + uri + "'></iframe>"); |
||||
|
||||
setTimeout(function () { |
||||
try { |
||||
myWindow.location.href; |
||||
myWindow.setTimeout("window.close()", 1000); |
||||
successCb(); |
||||
} catch (e) { |
||||
myWindow.close(); |
||||
failCb(); |
||||
} |
||||
}, 1000); |
||||
} |
||||
|
||||
function openUriWithMsLaunchUri(uri, failCb, successCb) { |
||||
navigator.msLaunchUri(uri, |
||||
successCb, |
||||
failCb |
||||
); |
||||
} |
||||
|
||||
function checkBrowser() { |
||||
var isOpera = !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0; |
||||
return { |
||||
isOpera: isOpera, |
||||
isFirefox: typeof InstallTrigger !== 'undefined', |
||||
isSafari: Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0, |
||||
isChrome: !!window.chrome && !isOpera, |
||||
isIE: /*@cc_on!@*/false || !!document.documentMode // At least IE6
|
||||
} |
||||
} |
||||
|
||||
function getInternetExplorerVersion() { |
||||
var rv = -1; |
||||
if (navigator.appName === "Microsoft Internet Explorer") { |
||||
var ua = navigator.userAgent; |
||||
var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})"); |
||||
if (re.exec(ua) != null) |
||||
rv = parseFloat(RegExp.$1); |
||||
} else if (navigator.appName === "Netscape") { |
||||
var ua = navigator.userAgent; |
||||
var re = new RegExp("Trident/.*rv:([0-9]{1,}[\.0-9]{0,})"); |
||||
if (re.exec(ua) != null) { |
||||
rv = parseFloat(RegExp.$1); |
||||
} |
||||
} |
||||
return rv; |
||||
} |
||||
|
||||
module.exports = function (uri, failCb, successCb) { |
||||
function failCallback() { |
||||
failCb && failCb(); |
||||
} |
||||
|
||||
function successCallback() { |
||||
successCb && successCb(); |
||||
} |
||||
|
||||
if (navigator.msLaunchUri) { //for IE and Edge in Win 8 and Win 10
|
||||
openUriWithMsLaunchUri(uri, failCb, successCb); |
||||
} else { |
||||
var browser = checkBrowser(); |
||||
|
||||
if (browser.isFirefox) { |
||||
openUriUsingFirefox(uri, failCallback, successCallback); |
||||
} else if (browser.isChrome) { |
||||
openUriWithTimeoutHack(uri, failCallback, successCallback); |
||||
} else if (browser.isIE) { |
||||
openUriUsingIEInOlderWindows(uri, failCallback, successCallback); |
||||
} else { |
||||
//not supported, implement please
|
||||
} |
||||
} |
||||
} |
||||
|
||||
}, {}] |
||||
}, {}, [1])(1) |
||||
}); |
@ -0,0 +1,26 @@
|
||||
!(function () { |
||||
BI.config("dec.constant.header.items", function (items) { |
||||
return BI.concat([{ |
||||
type: "bi.button", |
||||
text: "启动设计器", |
||||
ghost: true, |
||||
css: {color: "white"}, |
||||
handler: function () { |
||||
Dec.Utils.getWebStartInfo(function (res) { |
||||
if (res.data) { |
||||
console.log(res); |
||||
window.protocolCheck(res.data.url, function () { |
||||
var agent = navigator.userAgent.toLowerCase(); |
||||
var is64 = agent.indexOf("win64") >= 0 || agent.indexOf("wow64") >= 0 || agent.indexOf("x64") >= 0; |
||||
var downloadURL = is64 ? res.data.download64 : res.data.download32; |
||||
console.log(downloadURL); |
||||
window.open(downloadURL); |
||||
}) |
||||
} else { |
||||
BI.Msg.toast(res.errorMsg, {level: "error"}) |
||||
} |
||||
}) |
||||
} |
||||
}], items); |
||||
}); |
||||
})(); |
Loading…
Reference in new issue