Browse Source

open

master
pioneer 2 years ago
commit
ac664f8b99
  1. 6
      README.md
  2. BIN
      lib/finekit-10.0.jar
  3. BIN
      lib/gson-2.8.6.jar
  4. 23
      plugin.xml
  5. 27
      src/main/java/com/fr/plugin/third/party/jsdbacbj/OutputPluginLifecycleMonitor.java
  6. 355
      src/main/java/com/fr/plugin/third/party/jsdbacbj/Utils.java
  7. 284
      src/main/java/com/fr/plugin/third/party/jsdbacbj/config/CustomDataConfig.java
  8. 44
      src/main/java/com/fr/plugin/third/party/jsdbacbj/http/CustomConfigHttpHandler.java
  9. 16
      src/main/java/com/fr/plugin/third/party/jsdbacbj/http/CustomHttpHandlerProvider.java
  10. 14
      src/main/java/com/fr/plugin/third/party/jsdbacbj/http/CustomURLAliasProvider.java
  11. 552
      src/main/java/com/fr/plugin/third/party/jsdbacbj/http/SessionGlobalRequestFilterProvider.java
  12. 46
      src/main/java/com/fr/plugin/third/party/jsdbacbj/web/MainFilesComponent.java
  13. 19
      src/main/java/com/fr/plugin/third/party/jsdbacbj/web/MainWebResourceProvider.java
  14. 27
      src/main/resources/com/fr/plugin/third/party/jsdbacbj/main.js

6
README.md

@ -0,0 +1,6 @@
# open-JSD-10219
JSD-10219 竹云单点集成\
免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\
仅作为开发者学习参考使用!禁止用于任何商业用途!\
为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系【pioneer】处理。

BIN
lib/finekit-10.0.jar

Binary file not shown.

BIN
lib/gson-2.8.6.jar

Binary file not shown.

23
plugin.xml

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><plugin>
<id>com.fr.plugin.third.party.jsdbacbj</id>
<name><![CDATA[登录集成_EK]]></name>
<active>yes</active>
<version>1.0.1</version>
<env-version>10.0</env-version>
<jartime>2019-01-01</jartime>
<vendor>fr.open</vendor>
<description><![CDATA[]]></description>
<change-notes><![CDATA[
[2022-08-18]JSD-10219插件初始化<br/>
]]></change-notes>
<lifecycle-monitor class="com.fr.plugin.third.party.jsdbacbj.OutputPluginLifecycleMonitor"/>
<extra-core>
</extra-core>
<extra-decision>
<WebResourceProvider class="com.fr.plugin.third.party.jsdbacbj.web.MainWebResourceProvider"/>
<HttpHandlerProvider class="com.fr.plugin.third.party.jsdbacbj.http.CustomHttpHandlerProvider"/>
<URLAliasProvider class="com.fr.plugin.third.party.jsdbacbj.http.CustomURLAliasProvider"/>
<GlobalRequestFilterProvider class="com.fr.plugin.third.party.jsdbacbj.http.SessionGlobalRequestFilterProvider"/>
</extra-decision>
<function-recorder class="com.fr.plugin.third.party.jsdbacbj.OutputPluginLifecycleMonitor"/>
</plugin>

27
src/main/java/com/fr/plugin/third/party/jsdbacbj/OutputPluginLifecycleMonitor.java

@ -0,0 +1,27 @@
package com.fr.plugin.third.party.jsdbacbj;
import com.fr.intelli.record.Focus;
import com.fr.intelli.record.Original;
import com.fr.plugin.context.PluginContext;
import com.fr.plugin.observer.inner.AbstractPluginLifecycleMonitor;
import com.fr.plugin.third.party.jsdbacbj.config.CustomDataConfig;
import com.fr.record.analyzer.EnableMetrics;
import com.fr.stable.fun.Authorize;
/**
* 配置信息初始化
*/
@EnableMetrics
@Authorize(callSignKey = "com.fr.plugin.third.party.jsdbacbj")
public class OutputPluginLifecycleMonitor extends AbstractPluginLifecycleMonitor {
@Override
@Focus(id = "com.fr.plugin.third.party.jsdbacbj", text = "plugin-jsdbacbj", source = Original.PLUGIN)
public void afterRun(PluginContext pluginContext) {
CustomDataConfig.getInstance();
}
@Override
public void beforeStop(PluginContext pluginContext) {
}
}

355
src/main/java/com/fr/plugin/third/party/jsdbacbj/Utils.java

@ -0,0 +1,355 @@
package com.fr.plugin.third.party.jsdbacbj;
import com.fanruan.api.log.LogKit;
import com.fanruan.api.util.StringKit;
import com.fr.decision.authority.data.User;
import com.fr.decision.webservice.bean.user.UserBean;
import com.fr.decision.webservice.bean.user.UserUpdateBean;
import com.fr.decision.webservice.impl.user.UserPageQueryAuthorityParam;
import com.fr.decision.webservice.utils.ControllerFactory;
import com.fr.decision.webservice.utils.controller.UserController;
import com.fr.decision.webservice.v10.user.UserService;
import com.fr.plugin.third.party.jsdbacbj.config.CustomDataConfig;
import com.fr.stable.StringUtils;
import com.fr.stable.query.data.DataList;
import com.fr.stable.query.restriction.Restriction;
import com.fr.third.org.apache.http.HttpEntity;
import com.fr.third.org.apache.http.HttpStatus;
import com.fr.third.org.apache.http.client.config.RequestConfig;
import com.fr.third.org.apache.http.client.methods.CloseableHttpResponse;
import com.fr.third.org.apache.http.client.methods.HttpGet;
import com.fr.third.org.apache.http.client.methods.HttpPost;
import com.fr.third.org.apache.http.conn.ssl.NoopHostnameVerifier;
import com.fr.third.org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import com.fr.third.org.apache.http.entity.StringEntity;
import com.fr.third.org.apache.http.impl.client.CloseableHttpClient;
import com.fr.third.org.apache.http.impl.client.HttpClients;
import com.fr.third.org.apache.http.ssl.SSLContextBuilder;
import com.fr.third.org.apache.http.ssl.TrustStrategy;
import com.fr.third.org.apache.http.util.EntityUtils;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class Utils {
public static String DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36";
public static RequestConfig REQUEST_CONFIG = RequestConfig.custom()
.setConnectionRequestTimeout(30000)
.setSocketTimeout(30000) // 服务端相应超时
.setConnectTimeout(30000) // 建立socket链接超时时间
.build();
public static CloseableHttpClient createSslHttpClient() {
try {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
}).build();
HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
return HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
} catch (Exception e) {
LogKit.error(e.getMessage(), e);
}
return HttpClients.createDefault();
}
public static CloseableHttpClient createDefaultHttpClient() {
CloseableHttpClient httpClient = HttpClients.custom()
.build();
return httpClient;
}
public static synchronized CloseableHttpClient createHttpClient(String url) {
CloseableHttpClient httpClient = null;
if (StringKit.isEmpty(url)) {
httpClient = createDefaultHttpClient();
return httpClient;
}
if (url.startsWith("https://")) {
httpClient = createSslHttpClient();
return httpClient;
}
httpClient = createDefaultHttpClient();
return httpClient;
}
public static synchronized String createHttpGetContent(CloseableHttpClient httpClient, String url, String basicAuth) throws IOException {
if ((httpClient == null) || (StringKit.isEmpty(url))) {
return "";
}
HttpGet httpGet = new HttpGet(url);
httpGet.addHeader("User-Agent", Utils.DEFAULT_USER_AGENT);
if (StringKit.isNotEmpty(basicAuth)) {
httpGet.addHeader("Authorization", basicAuth);
}
httpGet.setConfig(Utils.REQUEST_CONFIG);
CloseableHttpResponse response = httpClient.execute(httpGet);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
response.close();
LogKit.info("http请求出错,http status:" + statusCode);
return "";
}
HttpEntity httpEntity = response.getEntity();
if (httpEntity == null) {
response.close();
LogKit.info("http请求出错,http响应内容为空");
return "";
}
String responseContent = EntityUtils.toString(httpEntity, "UTF-8");
response.close();
if (StringKit.isEmpty(responseContent)) {
LogKit.info("http请求出错,http响应内容为空1");
return "";
}
return responseContent;
}
public static synchronized String createHttpPostContent(CloseableHttpClient httpClient, String url, String bodyContent, String basicAuth, String contentType) throws IOException {
if ((httpClient == null) || (StringKit.isEmpty(url))) {
return "";
}
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader("User-Agent", Utils.DEFAULT_USER_AGENT);
httpPost.setConfig(Utils.REQUEST_CONFIG);
if (StringKit.isNotEmpty(basicAuth)) {
httpPost.addHeader("Authorization", basicAuth);
}
if (StringKit.isNotEmpty(contentType)) {
httpPost.addHeader("Content-Type", contentType);
}
StringEntity bodyEntity = new StringEntity(bodyContent, "UTF-8");
httpPost.setEntity(bodyEntity);
CloseableHttpResponse response = httpClient.execute(httpPost);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
response.close();
LogKit.info("http请求出错,http status:" + statusCode);
return "";
}
HttpEntity httpEntity = response.getEntity();
if (httpEntity == null) {
response.close();
LogKit.info("http请求出错,http响应内容为空");
return "";
}
String responseContent = EntityUtils.toString(httpEntity, "UTF-8");
response.close();
if (StringKit.isEmpty(responseContent)) {
LogKit.info("http请求出错,http响应内容为空1");
return "";
}
return responseContent;
}
/**
* 获取完整请求链接
*
* @param req 请求
* @return
*/
public static String getFullRequestUrl(HttpServletRequest req) {
if (req == null) {
return "";
}
String url = req.getRequestURL().toString();
String queryUrl = req.getQueryString();
if ((queryUrl == null) || "null".equalsIgnoreCase(queryUrl)) {
queryUrl = "";
} else {
queryUrl = "?" + queryUrl;
}
String fullUrl = url + queryUrl;
return fullUrl;
}
/**
* 重定向
*
* @param res
* @param url
*/
public static void sendRedirect(HttpServletResponse res, String url) {
if ((res == null) || (StringKit.isEmpty(url))) {
return;
}
res.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
res.setHeader("Location", url);
}
public static synchronized String getUuid() {
String uuid = UUID.randomUUID().toString().replace("-", "");
return uuid;
}
public static String getFullAuthorizeUrl(String state) {
CustomDataConfig config = CustomDataConfig.getInstance();
//String tempUrl = URLEncoder.encode(config.getFrUrl(), "UTF-8");
String tempUrl = config.getFrUrl();
String url = config.getAuthorizeUrl() + "?client_id=" + config.getClientId() + "&response_type=code&redirect_uri=" + tempUrl + "&state=" + state;
LogKit.info("登录集成及用户同步,请求用户授权地址:" + url);
return url;
}
public static String getFullAuthorizeUrlWithState() {
String state = getUuid();
String oAuthLoginUrl = getFullAuthorizeUrl(state);
return oAuthLoginUrl;
}
public static String getLogoutUrl() {
return CustomDataConfig.getInstance().getLogoutUrl() + "?redirctToUrl=" + CustomDataConfig.getInstance().getFrUrl() + "&redirectToLogin=true&entityId=" + CustomDataConfig.getInstance().getClientId();
}
/**
* 获取用户信息
*
* @param userCount 用户数,-1为不限制用户数
* @param isAdminContained 是否包含管理员用户
* @return
* @throws Exception
*/
public static List<UserBean> getAllUsers(int userCount, boolean isAdminContained) throws Exception {
List<UserBean> userBeans = new ArrayList<>();
if (userCount == 0) {
return userBeans;
}
int limitCount = userCount;
if (userCount <= -1) {
limitCount = Integer.MAX_VALUE;
}
List<String> adminUserIds = UserService.getInstance().getAdminUserIdList();
if ((adminUserIds == null) || (adminUserIds.size() <= 0)) {
return userBeans;
}
String adminUserId = adminUserIds.get(0);
UserController userController = ControllerFactory.getInstance().getUserController(adminUserId);
DataList dataList = userController.findPageUsersPerfectMatch(adminUserId, new UserPageQueryAuthorityParam(1, limitCount, "", null), new Restriction[0]);
if (dataList == null) {
return userBeans;
}
List users = dataList.getList();
if ((users == null) || (users.size() <= 0)) {
return userBeans;
}
User user;
UserBean userBean;
String userId;
for (int i = 0, max = users.size() - 1; i <= max; i++) {
user = (User) users.get(i);
userId = user.getId();
if ((!isAdminContained) && (adminUserIds.contains(userId))) {
continue;
}
userBean = new UserBean(user.getEmail(), user.isEnable(), user.getMobile(), user.getRealName(), user.getUserName(), user.getId());
userBean.setCreationType(user.getCreationType().toInteger());
userBeans.add(userBean);
}
return userBeans;
}
/**
* 获取不包含管理员的用户信息
*
* @param userCount
* @return
* @throws Exception
*/
public static List<UserBean> getAllUsersWithoutAdmin(int userCount) throws Exception {
return getAllUsers(userCount, false);
}
public static List<String> getAllUserNames(int userCount, boolean isAdminContained) throws Exception {
List<String> userNames = new ArrayList<>();
List<UserBean> userBeans = getAllUsers(userCount, isAdminContained);
UserBean userBean;
for (int i = 0, max = userBeans.size() - 1; i <= max; i++) {
userBean = userBeans.get(i);
userNames.add(userBean.getUsername());
}
return userNames;
}
public static List<String> getAllUserNamesWithoutAdmin(int userCount) throws Exception {
return getAllUserNames(userCount, false);
}
/**
* 通过用户名删除用户,管理员用户无法删除
*
* @param username 用户名
* @return
* @throws Exception
*/
public static int deleteUsersByUsername(String username) throws Exception {
if (StringUtils.isEmpty(username)) {
return 0;
}
User user = UserService.getInstance().getUserByUserName(username);
if (user == null) {
return 0;
}
String userId = user.getId();
List<String> adminUserIds = UserService.getInstance().getAdminUserIdList();
if ((adminUserIds != null) && (adminUserIds.size() >= 1) && (adminUserIds.contains(userId))) {
return 0;
}
UserUpdateBean userUpdateBean = new UserUpdateBean();
userUpdateBean.setRemoveUserIds(new String[]{userId});
return UserService.getInstance().deleteUsers(userUpdateBean);
}
public static int deleteUsersByUsernames(List<String> usernames) throws Exception {
if ((usernames == null) || (usernames.size() <= 0)) {
return 0;
}
String username;
int totalCount = 0, count;
for (int i = 0, max = usernames.size() - 1; i <= max; i++) {
username = usernames.get(i);
count = deleteUsersByUsername(username);
totalCount = totalCount + count;
}
return totalCount;
}
public static void editRealNameByUsername(String username, String realName) throws Exception {
if (StringUtils.isEmpty(username) || StringUtils.isEmpty(realName)) {
return;
}
User user = UserService.getInstance().getUserByUserName(username);
if (user == null) {
return;
}
UserBean userBean = new UserBean(user.getEmail(), user.isEnable(), user.getMobile(), realName, user.getUserName(), user.getId());
UserService.getInstance().editAccount(username, userBean);
}
}

284
src/main/java/com/fr/plugin/third/party/jsdbacbj/config/CustomDataConfig.java

@ -0,0 +1,284 @@
package com.fr.plugin.third.party.jsdbacbj.config;
import com.fr.config.*;
import com.fr.config.holder.Conf;
import com.fr.config.holder.factory.Holders;
import java.util.HashMap;
import java.util.Map;
/**
* 配置数据保存
*/
@Visualization(category = "登录集成配置")
public class CustomDataConfig extends DefaultConfiguration {
public String getNameSpace() {
return this.getClass().getName();
}
private static volatile CustomDataConfig config = null;
public static CustomDataConfig getInstance() {
if (config == null) {
config = ConfigContext.getConfigInstance(CustomDataConfig.class);
}
return config;
}
private static volatile Map<String, String> URL_MAP = new HashMap<>();
public synchronized static void addMapUrl(String key, String url) {
URL_MAP.put(key, url);
}
public synchronized static String getMapUrl(String key) {
if (!URL_MAP.containsKey(key)) {
return "";
}
String url = URL_MAP.get(key);
URL_MAP.remove(key);
return url;
}
@Identifier(value = "clientId", name = "应用标识", description = "", status = Status.SHOW)
private Conf<String> clientId = Holders.simple("");
@Identifier(value = "clientSecret", name = "应用密钥", description = "", status = Status.SHOW)
private Conf<String> clientSecret = Holders.simple("");
@Identifier(value = "authorizeUrl", name = "请求用户授权地址", description = "", status = Status.SHOW)
private Conf<String> authorizeUrl = Holders.simple("");
@Identifier(value = "accessTokenUrl", name = "获取授权Token地址", description = "", status = Status.SHOW)
private Conf<String> accessTokenUrl = Holders.simple("");
@Identifier(value = "profileUrl", name = "获取用户信息地址", description = "", status = Status.SHOW)
private Conf<String> profileUrl = Holders.simple("");
@Identifier(value = "frUrl", name = "报表地址", description = "", status = Status.SHOW)
private Conf<String> frUrl = Holders.simple("");
@Identifier(value = "logoutUrl", name = "统一认证注销地址", description = "", status = Status.SHOW)
private Conf<String> logoutUrl = Holders.simple("");
@Identifier(value = "userDataUrl", name = "用户同步API地址", description = "", status = Status.HIDE)
private Conf<String> userDataUrl = Holders.simple("");
@Identifier(value = "userSystemCode", name = "用户同步系统编码(systemCode)", description = "", status = Status.HIDE)
private Conf<String> userSystemCode = Holders.simple("");
@Identifier(value = "userIntegrationKey", name = "用户同步集成密钥(integrationKey)", description = "", status = Status.HIDE)
private Conf<String> userIntegrationKey = Holders.simple("");
@Identifier(value = "userLoopTimes", name = "用户同步循环最大次数", description = "", status = Status.HIDE)
private Conf<Integer> userLoopTimes = Holders.simple(10000);
@Identifier(value = "dataSyncUrl", name = "待办发送接口地址", description = "", status = Status.HIDE)
private Conf<String> dataSyncUrl = Holders.simple("");
@Identifier(value = "dataUsername", name = "待办发送接口用户名", description = "", status = Status.HIDE)
private Conf<String> dataUsername = Holders.simple("");
@Identifier(value = "dataPassword", name = "待办发送接口密码", description = "", status = Status.HIDE)
private Conf<String> dataPassword = Holders.simple("");
@Identifier(value = "appName", name = "待办发送来源", description = "", status = Status.HIDE)
private Conf<String> appName = Holders.simple("");
@Identifier(value = "modelName", name = "待办发送模块名", description = "", status = Status.HIDE)
private Conf<String> modelName = Holders.simple("");
@Identifier(value = "docCreator", name = "待办发送待办创建者", description = "", status = Status.HIDE)
private Conf<String> docCreator = Holders.simple("");
@Identifier(value = "loginTypeNameParameter", name = "登录类型参数名称", description = "", status = Status.HIDE)
private Conf<String> loginTypeNameParameter = Holders.simple("loginType");
@Identifier(value = "loginTypeValue", name = "登录类型值", description = "", status = Status.HIDE)
private Conf<String> loginTypeValue = Holders.simple("oauth");
public String getLoginTypeNameParameter() {
return loginTypeNameParameter.get();
}
public void setLoginTypeNameParameter(String loginTypeNameParameter) {
this.loginTypeNameParameter.set(loginTypeNameParameter);
}
public String getLoginTypeValue() {
return loginTypeValue.get();
}
public void setLoginTypeValue(String loginTypeValue) {
this.loginTypeValue.set(loginTypeValue);
}
public Integer getUserLoopTimes() {
return userLoopTimes.get();
}
public void setUserLoopTimes(Integer userLoopTimes) {
this.userLoopTimes.set(userLoopTimes);
}
public String getUserDataUrl() {
return userDataUrl.get();
}
public void setUserDataUrl(String userDataUrl) {
this.userDataUrl.set(userDataUrl);
}
public String getUserSystemCode() {
return userSystemCode.get();
}
public void setUserSystemCode(String userSystemCode) {
this.userSystemCode.set(userSystemCode);
}
public String getUserIntegrationKey() {
return userIntegrationKey.get();
}
public void setUserIntegrationKey(String userIntegrationKey) {
this.userIntegrationKey.set(userIntegrationKey);
}
public String getDataSyncUrl() {
return dataSyncUrl.get();
}
public void setDataSyncUrl(String dataSyncUrl) {
this.dataSyncUrl.set(dataSyncUrl);
}
public String getDataUsername() {
return dataUsername.get();
}
public void setDataUsername(String dataUsername) {
this.dataUsername.set(dataUsername);
}
public String getDataPassword() {
return dataPassword.get();
}
public void setDataPassword(String dataPassword) {
this.dataPassword.set(dataPassword);
}
public String getAppName() {
return appName.get();
}
public void setAppName(String appName) {
this.appName.set(appName);
}
public String getModelName() {
return modelName.get();
}
public void setModelName(String modelName) {
this.modelName.set(modelName);
}
public String getDocCreator() {
return docCreator.get();
}
public void setDocCreator(String docCreator) {
this.docCreator.set(docCreator);
}
public String getClientId() {
return clientId.get();
}
public void setClientId(String clientId) {
this.clientId.set(clientId);
}
public String getClientSecret() {
return clientSecret.get();
}
public void setClientSecret(String clientSecret) {
this.clientSecret.set(clientSecret);
}
public String getAuthorizeUrl() {
return authorizeUrl.get();
}
public void setAuthorizeUrl(String authorizeUrl) {
this.authorizeUrl.set(authorizeUrl);
}
public String getAccessTokenUrl() {
return accessTokenUrl.get();
}
public void setAccessTokenUrl(String accessTokenUrl) {
this.accessTokenUrl.set(accessTokenUrl);
}
public String getProfileUrl() {
return profileUrl.get();
}
public void setProfileUrl(String profileUrl) {
this.profileUrl.set(profileUrl);
}
public String getFrUrl() {
return frUrl.get();
}
public void setFrUrl(String frUrl) {
this.frUrl.set(frUrl);
}
public String getLogoutUrl() {
return logoutUrl.get();
}
public void setLogoutUrl(String logoutUrl) {
this.logoutUrl.set(logoutUrl);
}
@Override
public Object clone() throws CloneNotSupportedException {
CustomDataConfig cloned = (CustomDataConfig) super.clone();
cloned.dataSyncUrl = (Conf<String>) dataSyncUrl.clone();
cloned.dataUsername = (Conf<String>) dataUsername.clone();
cloned.dataPassword = (Conf<String>) dataPassword.clone();
cloned.appName = (Conf<String>) appName.clone();
cloned.modelName = (Conf<String>) modelName.clone();
cloned.docCreator = (Conf<String>) docCreator.clone();
cloned.userDataUrl = (Conf<String>) userDataUrl.clone();
cloned.userSystemCode = (Conf<String>) userSystemCode.clone();
cloned.userIntegrationKey = (Conf<String>) userIntegrationKey.clone();
cloned.userLoopTimes = (Conf<Integer>) userLoopTimes.clone();
cloned.loginTypeNameParameter = (Conf<String>) loginTypeNameParameter.clone();
cloned.loginTypeValue = (Conf<String>) loginTypeValue.clone();
cloned.clientId = (Conf<String>) clientId.clone();
cloned.clientSecret = (Conf<String>) clientSecret.clone();
cloned.authorizeUrl = (Conf<String>) authorizeUrl.clone();
cloned.accessTokenUrl = (Conf<String>) accessTokenUrl.clone();
cloned.profileUrl = (Conf<String>) profileUrl.clone();
cloned.frUrl = (Conf<String>) frUrl.clone();
cloned.logoutUrl = (Conf<String>) logoutUrl.clone();
return cloned;
}
}

44
src/main/java/com/fr/plugin/third/party/jsdbacbj/http/CustomConfigHttpHandler.java

@ -0,0 +1,44 @@
package com.fr.plugin.third.party.jsdbacbj.http;
import com.fr.decision.fun.impl.BaseHttpHandler;
import com.fr.json.JSONObject;
import com.fr.plugin.third.party.jsdbacbj.Utils;
import com.fr.third.springframework.web.bind.annotation.RequestMethod;
import com.fr.web.utils.WebUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
*/
public class CustomConfigHttpHandler extends BaseHttpHandler {
@Override
public RequestMethod getMethod() {
return RequestMethod.POST;
}
@Override
public String getPath() {
return "/jsdbacbj/oauth/config";
}
@Override
public boolean isPublic() {
return true;
}
@Override
public void handle(HttpServletRequest req, HttpServletResponse res) throws Exception {
res.setContentType("application/json; charset=utf-8");
String logoutUrl = Utils.getLogoutUrl();
String oAuthLoginUrl = Utils.getFullAuthorizeUrlWithState();
JSONObject configJson = new JSONObject();
configJson.put("logoutUrl", logoutUrl);
configJson.put("oAuthLoginUrl", oAuthLoginUrl);
WebUtils.printAsJSON(res, configJson);
}
}

16
src/main/java/com/fr/plugin/third/party/jsdbacbj/http/CustomHttpHandlerProvider.java

@ -0,0 +1,16 @@
package com.fr.plugin.third.party.jsdbacbj.http;
import com.fr.decision.fun.impl.AbstractHttpHandlerProvider;
import com.fr.decision.fun.impl.BaseHttpHandler;
public class CustomHttpHandlerProvider extends AbstractHttpHandlerProvider {
@Override
public BaseHttpHandler[] registerHandlers() {
return new BaseHttpHandler[]{
new CustomConfigHttpHandler(),
};
}
}

14
src/main/java/com/fr/plugin/third/party/jsdbacbj/http/CustomURLAliasProvider.java

@ -0,0 +1,14 @@
package com.fr.plugin.third.party.jsdbacbj.http;
import com.fr.decision.fun.impl.AbstractURLAliasProvider;
import com.fr.decision.webservice.url.alias.URLAlias;
import com.fr.decision.webservice.url.alias.URLAliasFactory;
public class CustomURLAliasProvider extends AbstractURLAliasProvider {
@Override
public URLAlias[] registerAlias() {
return new URLAlias[]{
URLAliasFactory.createPluginAlias("/jsdbacbj/oauth/config", "/jsdbacbj/oauth/config", true),
};
}
}

552
src/main/java/com/fr/plugin/third/party/jsdbacbj/http/SessionGlobalRequestFilterProvider.java

@ -0,0 +1,552 @@
package com.fr.plugin.third.party.jsdbacbj.http;
import com.fanruan.api.log.LogKit;
import com.fanruan.api.util.StringKit;
import com.fr.decision.authority.data.User;
import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider;
import com.fr.decision.webservice.v10.login.LoginService;
import com.fr.decision.webservice.v10.user.UserService;
import com.fr.general.ComparatorUtils;
import com.fr.json.JSONArray;
import com.fr.json.JSONObject;
import com.fr.plugin.third.party.jsdbacbj.Utils;
import com.fr.plugin.third.party.jsdbacbj.config.CustomDataConfig;
import com.fr.third.org.apache.commons.codec.digest.DigestUtils;
import com.fr.third.org.apache.http.HttpEntity;
import com.fr.third.org.apache.http.HttpStatus;
import com.fr.third.org.apache.http.NameValuePair;
import com.fr.third.org.apache.http.client.config.RequestConfig;
import com.fr.third.org.apache.http.client.entity.UrlEncodedFormEntity;
import com.fr.third.org.apache.http.client.methods.CloseableHttpResponse;
import com.fr.third.org.apache.http.client.methods.HttpGet;
import com.fr.third.org.apache.http.client.methods.HttpPost;
import com.fr.third.org.apache.http.impl.client.CloseableHttpClient;
import com.fr.third.org.apache.http.message.BasicNameValuePair;
import com.fr.third.org.apache.http.util.EntityUtils;
import com.fr.web.utils.WebUtils;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
public class SessionGlobalRequestFilterProvider extends AbstractGlobalRequestFilterProvider {
private static String DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36";
@Override
public String filterName() {
return "com.fr.plugin.third.party.jsdbacbj";
}
@Override
public String[] urlPatterns() {
return new String[]{"/decision", "/decision/*"};
}
@Override
public void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) {
try {
String fullUrl = req.getRequestURL().toString();
String queryUrl = req.getQueryString();
if ((queryUrl == null) || "null".equalsIgnoreCase(queryUrl)) {
queryUrl = "";
} else {
queryUrl = "?" + queryUrl;
}
String fullUrl1 = fullUrl + queryUrl;
String method = req.getMethod();
LogKit.info("登录集成,记录访问地址:" + method + " " + fullUrl1);
if (!"GET".equalsIgnoreCase(method)) {
filterChain.doFilter(req, res);
return;
}
if (isNoAuthRequest(req)) {
filterChain.doFilter(req, res);
return;
}
if (fullUrl.indexOf("/remote/") >= 0) {
filterChain.doFilter(req, res);
return;
}
if (fullUrl.indexOf("terminal=H5") >= 0) {
filterChain.doFilter(req, res);
return;
}
if (fullUrl.indexOf("__device__=") >= 0) {
filterChain.doFilter(req, res);
return;
}
if (fullUrl.indexOf("/weixin/") >= 0) {
filterChain.doFilter(req, res);
return;
}
if (fullUrl.indexOf("/dingtalk/") >= 0) {
filterChain.doFilter(req, res);
return;
}
if (isLoginRequest(req)) {
LogKit.info("登录集成,登录页,访问地址:" + method + " " + fullUrl1);
filterChain.doFilter(req, res);
return;
}
//boolean option = isLogged(req);
boolean option = LoginService.getInstance().isLogged(req);
if (option && (!isOauthCodeRequest(req)) && (!isAllowLoginWithParameter(req))) {
LogKit.info("登录集成,标记a,访问地址:" + method + " " + fullUrl1);
filterChain.doFilter(req, res);
return;
}
String state, reqUrl;
if (isAllowLoginWithParameter(req) || ((!option) && (!isOauthCodeRequest(req)) && isReportRequest(req))) {
LogKit.info("登录集成,标记b,访问地址:" + method + " " + fullUrl1);
reqUrl = getRequestUrl(req);
state = Utils.getUuid();
CustomDataConfig.getInstance().addMapUrl(state, reqUrl);
String tempUrl = Utils.getFullAuthorizeUrl(state);
LogKit.info("登录集成,请求认证地址:" + tempUrl);
sendRedirect(res, tempUrl);
return;
}
String loginUsername = getOauthLoginUsername(req);
if (StringKit.isEmpty(loginUsername)) {
filterChain.doFilter(req, res);
return;
}
LogKit.info("登录集成,用户名:" + loginUsername);
User user = UserService.getInstance().getUserByUserName(loginUsername);
boolean tipsOption = false;
String tipsContent = "";
if (user == null) {
tipsOption = true;
LogKit.info("登录集成,用户名:" + loginUsername + "在报表平台不存在");
tipsContent = "在报表服务器上不存在";
} else if (!user.isEnable()) {
tipsOption = true;
LogKit.info("登录集成,用户名:" + loginUsername + "在报表平台上被禁用");
tipsContent = "在报表平台上被禁用";
}
if (tipsOption) {
String jumpContent = "<!doctype html>\n" +
"<head>\n" +
" <meta charset=\"utf-8\" />\n" +
" <title>提示</title>\n" +
"</head>\n" +
"<body>\n" +
" <script>\n" +
" var t = 10;\n" +
" var referI = setInterval(\"refer()\", 1000);\n" +
" function refer() {\n" +
" document.getElementById('show').innerHTML = \"用户:" + loginUsername + tipsContent + ",请联系管理员!<br>\" + t + \"秒后跳转到报表首页\"; \n" +
" t--;\n" +
" if (t <= 0) {\n" +
" clearInterval(referI);\n" +
" window.location = \"" + Utils.getLogoutUrl() + "\";\n" +
"setTimeout(function(){\n" +
" window.location = \"" + Utils.getFullAuthorizeUrlWithState() + "\";\n" +
"}, 1000);" +
" }\n" +
" }\n" +
" </script>\n" +
" <div style=\"width: 100%;height:200px; line-height: 200px;font-size:30px;vertical-align:middle;text-align:center\">\n" +
" <span id=\"show\"></span>\n" +
" </div>\n" +
"</body>\n" +
"</html>";
jumpContent = "<!doctype html>\n" +
"<head>\n" +
" <meta charset=\"utf-8\" />\n" +
" <title>提示</title>\n" +
"\t\n" +
"<script type=\"text/javascript\">\n" +
"window.onload=function(){\n" +
" alert(\"用户:" + loginUsername + tipsContent + ",请联系管理员!\");\n" +
" window.location = \"" + Utils.getLogoutUrl() + "\";\n" +
" setTimeout(function(){\n" +
" window.location = \"" + Utils.getFullAuthorizeUrlWithState() + "\";\n" +
" }, 1000); \n" +
"}\n" +
"</script>\t\n" +
"</head>\n" +
"<body>\n" +
" <div style=\"width: 100%;height:200px; line-height: 200px;font-size:30px;vertical-align:middle;text-align:center\">\n" +
" <span id=\"show\"></span>\n" +
" </div>\n" +
"</body>\n" +
"</html>";
res.setContentType("text/html;charset=UTF-8");
WebUtils.printAsString(res, jumpContent);
res.setStatus(200);
return;
}
loginUsername = user.getUserName();
LogKit.info("登录集成,报表平台用户名:" + loginUsername);
String loginToken = LoginService.getInstance().login(req, res, loginUsername);
req.setAttribute("fine_auth_token", loginToken);
reqUrl = getRealUrl(req);
if (StringKit.isNotEmpty(reqUrl)) {
sendRedirect(res, reqUrl);
return;
}
filterChain.doFilter(req, res);
} catch (Exception e) {
LogKit.error("登录集成出错," + e.getMessage(), e);
}
}
private String getRealUrl(HttpServletRequest req) {
if (req == null) {
return "";
}
String state = WebUtils.getHTTPRequestParameter(req, "state");
if (StringKit.isEmpty(state)) {
return "";
}
String url = CustomDataConfig.getInstance().getMapUrl(state);
return url;
}
private String getOauthLoginUsername(HttpServletRequest req) throws IOException {
if (req == null) {
return "";
}
String oAuthCode = WebUtils.getHTTPRequestParameter(req, "code");
if (StringKit.isEmpty(oAuthCode)) {
return "";
}
LogKit.info("登录集成,OAuth Code:" + oAuthCode);
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(10000)
.setSocketTimeout(10000) // 服务端相应超时
.setConnectTimeout(10000) // 建立socket链接超时时间
.build();
//获取授权Token
String accessTokenUrl = CustomDataConfig.getInstance().getAccessTokenUrl();
LogKit.info("登录集成,获取授权Token地址:" + accessTokenUrl);
HttpPost httpPost = new HttpPost(accessTokenUrl);
httpPost.addHeader("User-Agent", DEFAULT_USER_AGENT);
List<NameValuePair> params = new ArrayList<NameValuePair>();
NameValuePair clientIdNameValuePair = new BasicNameValuePair("client_id", CustomDataConfig.getInstance().getClientId());
NameValuePair clientSecretNameValuePair = new BasicNameValuePair("client_secret", CustomDataConfig.getInstance().getClientSecret());
NameValuePair redirectUriNameValuePair = new BasicNameValuePair("redirect_uri", CustomDataConfig.getInstance().getFrUrl());
NameValuePair codeNameValuePair = new BasicNameValuePair("code", oAuthCode);
NameValuePair grantTypeNameValuePair = new BasicNameValuePair("grant_type", "authorization_code");
params.add(clientIdNameValuePair);
params.add(clientSecretNameValuePair);
params.add(codeNameValuePair);
params.add(grantTypeNameValuePair);
httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
httpPost.setConfig(requestConfig);
CloseableHttpClient httpClient = Utils.createHttpClient(accessTokenUrl);
CloseableHttpResponse response = httpClient.execute(httpPost);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
response.close();
httpClient.close();
LogKit.info("登录集成,获取授权Token请求出错,http status:" + statusCode);
return "";
}
HttpEntity httpEntity = response.getEntity();
if (httpEntity == null) {
response.close();
httpClient.close();
LogKit.info("登录集成,获取授权Token请求出错,http响应内容为空");
return "";
}
String responseContent = EntityUtils.toString(httpEntity, "UTF-8");
response.close();
if (StringKit.isEmpty(responseContent)) {
httpClient.close();
LogKit.info("登录集成,获取授权Token请求出错,http响应内容为空1");
return "";
}
LogKit.info("登录集成,获取授权Token请求,http响应内容\n" + responseContent);
String accessToken = getAccessToken(responseContent);
if (StringKit.isEmpty(accessToken)) {
httpClient.close();
LogKit.info("登录集成,获取授权Token请求出错,授权Token为空");
return "";
}
LogKit.info("登录集成,授权Token:" + accessToken);
String userUrl = CustomDataConfig.getInstance().getProfileUrl() + "?access_token=" + accessToken + "&client_id=" + CustomDataConfig.getInstance().getClientId();
HttpGet httpGet = new HttpGet(userUrl);
httpGet.setConfig(requestConfig);
response = httpClient.execute(httpGet);
statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
response.close();
httpClient.close();
LogKit.info("登录集成,获取用户信息请求出错,http status:" + statusCode);
return "";
}
httpEntity = response.getEntity();
if (httpEntity == null) {
response.close();
httpClient.close();
LogKit.info("登录集成,获取用户信息请求出错,http响应内容为空");
return "";
}
responseContent = EntityUtils.toString(httpEntity, "UTF-8");
response.close();
httpClient.close();
if (StringKit.isEmpty(responseContent)) {
LogKit.info("登录集成,获取用户信息请求出错,http响应内容为空1");
return "";
}
LogKit.info("登录集成,获取用户信息请求,http响应内容\n" + responseContent);
String uid = getUserId(responseContent);
if (StringKit.isEmpty(uid)) {
LogKit.info("登录集成,,获取用户信息请求出错,uid为空");
return "";
}
LogKit.info("登录集成,uid:" + uid);
return uid;
}
public static String getSign(Map<String, String> params, String secret) {
String sign = "";
StringBuilder sb = new StringBuilder();
//排序
Set<String> keyset = params.keySet();
TreeSet<String> sortSet = new TreeSet<String>();
sortSet.addAll(keyset);
Iterator<String> it = sortSet.iterator();
//加密字符串
while (it.hasNext()) {
String key = it.next();
String value = params.get(key);
sb.append(key).append(value);
}
sb.append("appkey").append(secret);
String md5Str = sb.toString();
LogKit.info("登录集成,获取授权Token,sign 待加密字符串:" + md5Str);
try {
sign = DigestUtils.md5Hex(md5Str).toUpperCase();
} catch (Exception e) {
}
return sign;
}
private String getAccessToken(String content) {
if (StringKit.isEmpty(content)) {
return "";
}
JSONObject contentJson = new JSONObject(content);
String token = contentJson.getString("access_token");
return token;
}
private String getUserId(String content) {
if (StringKit.isEmpty(content)) {
return "";
}
String loginName;
JSONObject contentJson = new JSONObject(content);
if (contentJson.containsKey("spRoleList")) {
JSONArray jsonArray = contentJson.getJSONArray("spRoleList");
if ((jsonArray != null) && (jsonArray.size() >= 1)) {
return jsonArray.getString(0);
}
}
loginName = contentJson.getString("loginName");
return loginName;
}
public synchronized static String getSysTime() {
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
Date date = new Date();
String nowData = format.format(date);
return nowData;
}
private void sendRedirect(HttpServletResponse res, String url) {
res.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
res.setHeader("Location", url);
}
private String getRequestUrl(HttpServletRequest req) {
String fullUrl = req.getRequestURL().toString();
fullUrl = getRealUrl(fullUrl);
Map<String, String[]> paraMap = req.getParameterMap();
String paraName;
String[] paraValues;
String loginTypeParaName = CustomDataConfig.getInstance().getLoginTypeNameParameter();
String queryStr = "";
for (Map.Entry<String, String[]> entry : paraMap.entrySet()) {
paraName = entry.getKey();
if (ComparatorUtils.equals(paraName, loginTypeParaName)) {
continue;
}
if (ComparatorUtils.equals(paraName, "code")) {
continue;
}
paraValues = entry.getValue();
queryStr = addParaToQuery(queryStr, paraName, paraValues);
}
if (StringKit.isEmpty(queryStr)) {
return fullUrl;
}
fullUrl = fullUrl + "?" + queryStr;
return fullUrl;
}
private String getRealUrl(String url) {
if (StringKit.isEmpty(url)) {
return url;
}
int index = url.indexOf("/decision");
if (index < 0) {
return url;
}
String tempUrl = CustomDataConfig.getInstance().getFrUrl() + url.substring(index + "/decision".length());
return tempUrl;
}
private String addParaToQuery(String query, String paraName, String[] paraValues) {
if (StringKit.isEmpty(paraName)) {
return query;
}
String fullQuery = query;
if ((paraValues == null) || (paraValues.length <= 0)) {
if (StringKit.isNotEmpty(fullQuery)) {
fullQuery = fullQuery + "&";
}
fullQuery = paraName + "=";
return fullQuery;
}
for (int i = 0, max = paraValues.length - 1; i <= max; i++) {
if (StringKit.isNotEmpty(fullQuery)) {
fullQuery = fullQuery + "&";
}
fullQuery = fullQuery + paraName + "=" + paraValues[i];
}
return fullQuery;
}
private boolean isAllowLoginWithParameter(HttpServletRequest req) {
if (req == null) {
return false;
}
String loginTypeNameParameter = CustomDataConfig.getInstance().getLoginTypeNameParameter();
String loginTypeConfigValue = CustomDataConfig.getInstance().getLoginTypeValue();
if (StringKit.isEmpty(loginTypeNameParameter) || StringKit.isEmpty(loginTypeConfigValue)) {
return false;
}
String loginTypeValue = WebUtils.getHTTPRequestParameter(req, loginTypeNameParameter);
return ComparatorUtils.equalsIgnoreCase(loginTypeConfigValue, loginTypeValue);
}
private boolean isReportRequest(HttpServletRequest req) {
if (req == null) {
return false;
}
if (!"GET".equalsIgnoreCase(req.getMethod())) {
return false;
}
String url = req.getRequestURL().toString();
if (url.endsWith("/decision") || url.endsWith("/decision/")) {
return true;
}
if ((url.indexOf("/decision/") >= 0) && (url.indexOf("/entry/access/") >= 0)) {
return true;
}
String viewlet = WebUtils.getHTTPRequestParameter(req, "viewlet");
if ((url.indexOf("/decision/view/report") >= 0) && (StringKit.isNotEmpty(viewlet))) {
return true;
}
if ((url.indexOf("/decision/view/form") >= 0) && (StringKit.isNotEmpty(viewlet))) {
return true;
}
return false;
}
private boolean isOauthCodeRequest(HttpServletRequest req) throws IOException {
if (req == null) {
return false;
}
if (!"GET".equalsIgnoreCase(req.getMethod())) {
return false;
}
String oAuthCode = WebUtils.getHTTPRequestParameter(req, "code");
if (StringKit.isNotEmpty(oAuthCode)) {
return true;
}
return false;
}
private boolean isLoginRequest(HttpServletRequest req) {
if (req == null) {
return false;
}
if (!"GET".equalsIgnoreCase(req.getMethod())) {
return false;
}
String url = req.getRequestURL().toString();
if (url.endsWith("/decision/login") || url.endsWith("/decision/login/")) {
return true;
}
return false;
}
private boolean isNoAuthRequest(HttpServletRequest req) throws IOException {
if (req == null) {
return false;
}
if (!"GET".equalsIgnoreCase(req.getMethod())) {
return false;
}
String oAuthCode = WebUtils.getHTTPRequestParameter(req, "loginType");
if (StringKit.equalsIgnoreCase("noauth", oAuthCode)) {
return true;
}
return false;
}
}

46
src/main/java/com/fr/plugin/third/party/jsdbacbj/web/MainFilesComponent.java

@ -0,0 +1,46 @@
package com.fr.plugin.third.party.jsdbacbj.web;
import com.fr.web.struct.Component;
import com.fr.web.struct.Filter;
import com.fr.web.struct.browser.RequestClient;
import com.fr.web.struct.category.ScriptPath;
import com.fr.web.struct.category.StylePath;
public class MainFilesComponent extends Component {
public static final MainFilesComponent KEY = new MainFilesComponent();
private MainFilesComponent(){}
/**
* 返回需要引入的JS脚本路径
* @param client 请求客户端描述
* @return JS脚本路径
*/
public ScriptPath script(RequestClient client ) {
//如果不需要就直接返回 ScriptPath.EMPTY
return ScriptPath.build("com/fr/plugin/third/party/jsdbacbj/main.js");
}
/**
* 返回需要引入的CSS样式路径
* @param client 请求客户端描述
* @return CSS样式路径
*/
public StylePath style(RequestClient client ) {
//如果不需要就直接返回 StylePath.EMPTY;
//return StylePath.build("com/fr/plugin/jscssinput/demo/demo.css");
return StylePath.EMPTY;
}
/**
* 通过给定的资源过滤器控制是否加载这个资源
* @return 资源过滤器
*/
public Filter filter() {
return new Filter(){
@Override
public boolean accept() {
//任何情况下我们都在平台组件加载时加载我们的组件
return true;
}
};
}
}

19
src/main/java/com/fr/plugin/third/party/jsdbacbj/web/MainWebResourceProvider.java

@ -0,0 +1,19 @@
package com.fr.plugin.third.party.jsdbacbj.web;
import com.fr.decision.fun.impl.AbstractWebResourceProvider;
import com.fr.decision.web.MainComponent;
import com.fr.web.struct.Atom;
public class MainWebResourceProvider extends AbstractWebResourceProvider {
@Override
public Atom attach() {
//在平台主组件加载时添加我们自己的组件
return MainComponent.KEY;
}
@Override
public Atom client() {
//我们自己要引入的组件
return MainFilesComponent.KEY;
}
}

27
src/main/resources/com/fr/plugin/third/party/jsdbacbj/main.js

@ -0,0 +1,27 @@
$(function () {
var url = Dec.fineServletURL + "/url/jsdbacbj/oauth/config";
$.post(url,
function (data, status) {
if (status == "success") {
//debugger;
var logoutUrl = data.logoutUrl;
var oAuthLoginUrl = data.oAuthLoginUrl;
Dec.Logout = function () {
Dec.Utils.logout(function (e) {
Dec.Utils.clearLoginToken();
window.location.href = oAuthLoginUrl;
})
}
var a = Dec.Logout;
Dec.Logout = function () {
window.location.href = logoutUrl;
//$.get(logoutUrl);
a();
}
}
}, "json");
});
Loading…
Cancel
Save