diff --git a/JSD-8933-需求文档V1.docx b/JSD-8933-需求文档V1.docx
new file mode 100644
index 0000000..780db37
Binary files /dev/null and b/JSD-8933-需求文档V1.docx differ
diff --git a/README.md b/README.md
index ff5c4d9..ec0e5f9 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
# open-JSD-8933
-JSD-8933 chrome打开实现
\ No newline at end of file
+JSD-8933 chrome打开实现\
+免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\
+仅作为开发者学习参考使用!禁止用于任何商业用途!\
+为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系hugh处理。
\ No newline at end of file
diff --git a/plugin.xml b/plugin.xml
new file mode 100644
index 0000000..046268b
--- /dev/null
+++ b/plugin.xml
@@ -0,0 +1,25 @@
+
+
+ com.fr.plugin.xxxx.cqjg.jump
+ com.fr.plugin.xxxx.cqjg.jump
+
+ yes
+ 1.4
+ 10.0
+ 2018-07-31
+ fr.open
+
+
+ [2021-11-04]【1.1】逻辑修改为解析token中用户的方式。
+ [2021-11-08]【1.2】增加获取token链接,直接比对数据库密码。
+ [2021-11-08]【1.3】增加sha256加密后比对数据库密码。
+ [2021-11-08]【1.4】增加写入cookie。
+ ]]>
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/fr/plugin/xxxx/cqjg/jump/Constants.java b/src/main/java/com/fr/plugin/xxxx/cqjg/jump/Constants.java
new file mode 100644
index 0000000..c5d9a07
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/cqjg/jump/Constants.java
@@ -0,0 +1,9 @@
+package com.fr.plugin.xxxx.cqjg.jump;
+
+/**
+ * @author fr.open
+ * @date 2020/5/14
+ */
+public class Constants {
+ public static final String PLUGIN_ID = "com.fr.plugin.xxxx.cqjg.jump";
+}
diff --git a/src/main/java/com/fr/plugin/xxxx/cqjg/jump/GlobalFilter.java b/src/main/java/com/fr/plugin/xxxx/cqjg/jump/GlobalFilter.java
new file mode 100644
index 0000000..a099e23
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/cqjg/jump/GlobalFilter.java
@@ -0,0 +1,109 @@
+package com.fr.plugin.xxxx.cqjg.jump;
+
+import com.fr.cert.token.Claims;
+import com.fr.cert.token.Jwts;
+import com.fr.decision.authority.data.User;
+import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider;
+import com.fr.decision.webservice.exception.user.UserNotExistException;
+import com.fr.decision.webservice.utils.DecisionServiceConstants;
+import com.fr.decision.webservice.v10.config.ConfigService;
+import com.fr.decision.webservice.v10.login.LoginService;
+import com.fr.decision.webservice.v10.user.UserService;
+import com.fr.intelli.record.Focus;
+import com.fr.intelli.record.Original;
+import com.fr.log.FineLoggerFactory;
+import com.fr.plugin.context.PluginContexts;
+import com.fr.plugin.transform.FunctionRecorder;
+import com.fr.record.analyzer.EnableMetrics;
+import com.fr.security.KeySecretSeedConfig;
+import com.fr.security.SecurityToolbox;
+import com.fr.stable.StringUtils;
+import com.fr.stable.fun.Authorize;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * @Author fr.open
+ * @Date 2021/10/29
+ * @Description
+ **/
+@FunctionRecorder
+@Authorize(callSignKey = Constants.PLUGIN_ID)
+@EnableMetrics
+public class GlobalFilter extends AbstractGlobalRequestFilterProvider {
+
+ private static final String flag = "00000";
+
+ @Override
+ public String filterName() {
+ return "global";
+ }
+
+ @Override
+ @Focus(id = Constants.PLUGIN_ID, text = "xxxx跳转", source = Original.PLUGIN)
+ public String[] urlPatterns() {
+ if (PluginContexts.currentContext().isAvailable()) {
+ String servletPathName = "decision";
+ try {
+ servletPathName = ConfigService.getInstance().getBasicParam().getServletPathName();
+ } catch (Exception e) {
+ FineLoggerFactory.getLogger().error(e.getMessage(), e);
+ }
+ return new String[]{
+ "/" + servletPathName,
+ "/" + servletPathName + "/view/report",
+
+ };
+ } else {
+ return new String[0];
+ }
+ }
+
+ @Override
+ public void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) {
+ String query = req.getQueryString();
+ if (StringUtils.isNotBlank(query) && query.contains(flag)) {
+ int start = query.indexOf(flag) + 5;
+ int end = query.indexOf("&", start);
+ String token = query.substring(start, end == -1 ? query.length() : end);
+ FineLoggerFactory.getLogger().info("get token is {}", token);
+ try {
+ byte[] bytes = SecurityToolbox.base642Byte(KeySecretSeedConfig.getInstance().getTrustSeed());
+ Claims claims = Jwts.parser().setSigningKey(bytes).parseClaimsJws(token).getBody();
+ loginFromToken(req,res,claims.getSubject());
+ } catch (Exception e) {
+ FineLoggerFactory.getLogger().error(e.getMessage(), e);
+ }
+ }
+ try {
+ filterChain.doFilter(req, res);
+ } catch (IOException e) {
+ FineLoggerFactory.getLogger().error(e.getMessage());
+ } catch (ServletException e) {
+ FineLoggerFactory.getLogger().error(e.getMessage());
+ }
+ }
+
+ private boolean loginFromToken(HttpServletRequest req, HttpServletResponse res, String username) throws Exception {
+ try {
+ if (StringUtils.isNotEmpty(username)) {
+ User user = UserService.getInstance().getUserByUserName(username);
+ if (user == null) {
+ throw new UserNotExistException();
+ }
+ String token = LoginService.getInstance().login(req, res, username);
+ req.setAttribute(DecisionServiceConstants.FINE_AUTH_TOKEN_NAME, token);
+ return true;
+ } else {
+ return false;
+ }
+ } catch (Exception e) {
+ FineLoggerFactory.getLogger().error(e.getMessage(), e);
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/com/fr/plugin/xxxx/cqjg/jump/TokenRequestHandlerBridge.java b/src/main/java/com/fr/plugin/xxxx/cqjg/jump/TokenRequestHandlerBridge.java
new file mode 100644
index 0000000..aa60cd4
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/cqjg/jump/TokenRequestHandlerBridge.java
@@ -0,0 +1,18 @@
+package com.fr.plugin.xxxx.cqjg.jump;
+
+import com.fr.decision.fun.HttpHandler;
+import com.fr.decision.fun.impl.AbstractHttpHandlerProvider;
+import com.fr.plugin.xxxx.cqjg.jump.handle.TokenHandler;
+
+/**
+ * @author fr.open
+ * @since 2021/07/28
+ */
+public class TokenRequestHandlerBridge extends AbstractHttpHandlerProvider {
+ @Override
+ public HttpHandler[] registerHandlers() {
+ return new HttpHandler[]{
+ new TokenHandler()
+ };
+ }
+}
diff --git a/src/main/java/com/fr/plugin/xxxx/cqjg/jump/TokenRequestURLAliasBridge.java b/src/main/java/com/fr/plugin/xxxx/cqjg/jump/TokenRequestURLAliasBridge.java
new file mode 100644
index 0000000..53325a8
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/cqjg/jump/TokenRequestURLAliasBridge.java
@@ -0,0 +1,18 @@
+package com.fr.plugin.xxxx.cqjg.jump;
+
+import com.fr.decision.fun.impl.AbstractURLAliasProvider;
+import com.fr.decision.webservice.url.alias.URLAlias;
+import com.fr.decision.webservice.url.alias.URLAliasFactory;
+
+/**
+ * @author fr.open
+ * @since 2021/07/28
+ */
+public class TokenRequestURLAliasBridge extends AbstractURLAliasProvider {
+ @Override
+ public URLAlias[] registerAlias() {
+ return new URLAlias[]{
+ URLAliasFactory.createPluginAlias("/token", "/token", true),
+ };
+ }
+}
diff --git a/src/main/java/com/fr/plugin/xxxx/cqjg/jump/handle/TokenHandler.java b/src/main/java/com/fr/plugin/xxxx/cqjg/jump/handle/TokenHandler.java
new file mode 100644
index 0000000..f4fd30e
--- /dev/null
+++ b/src/main/java/com/fr/plugin/xxxx/cqjg/jump/handle/TokenHandler.java
@@ -0,0 +1,136 @@
+package com.fr.plugin.xxxx.cqjg.jump.handle;
+
+import com.fr.base.ServerConfig;
+import com.fr.base.TemplateUtils;
+import com.fr.data.NetworkHelper;
+import com.fr.decision.authority.AuthorityContext;
+import com.fr.decision.authority.data.User;
+import com.fr.decision.config.FSConfig;
+import com.fr.decision.fun.impl.BaseHttpHandler;
+import com.fr.decision.mobile.terminal.TerminalHandler;
+import com.fr.decision.webservice.CrossDomainResponse;
+import com.fr.decision.webservice.bean.authentication.LoginClientBean;
+import com.fr.decision.webservice.exception.user.UserNotExistException;
+import com.fr.decision.webservice.utils.DecisionStatusService;
+import com.fr.log.FineLoggerFactory;
+import com.fr.security.JwtUtils;
+import com.fr.stable.StringUtils;
+import com.fr.stable.query.QueryFactory;
+import com.fr.stable.query.restriction.RestrictionFactory;
+import com.fr.stable.web.Device;
+import com.fr.store.Converter;
+import com.fr.third.com.lowagie.text.pdf.BadPasswordException;
+import com.fr.third.org.apache.commons.codec.digest.DigestUtils;
+import com.fr.third.springframework.web.bind.annotation.RequestMethod;
+import com.fr.web.utils.WebUtils;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.HashMap;
+
+
+/**
+ * @author fr.open
+ * @Date 2021/08/17
+ */
+public class TokenHandler extends BaseHttpHandler {
+
+ @Override
+ public RequestMethod getMethod() {
+ return RequestMethod.GET;
+ }
+
+ @Override
+ public String getPath() {
+ return "/token";
+ }
+
+ @Override
+ public boolean isPublic() {
+ return true;
+ }
+
+
+ @Override
+ public void handle(HttpServletRequest req, HttpServletResponse res) {
+ CrossDomainResponse domainResponse = null;
+ try {
+ String origin = NetworkHelper.getOriginalURL(req);
+ String uri = req.getRequestURI();
+ String render = TemplateUtils.render(origin.replace(uri, "${fineServletURL}"));
+ String username = WebUtils.getHTTPRequestParameter(req, "fine_username");
+ String password = WebUtils.getHTTPRequestParameter(req, "fine_password");
+ String validity = WebUtils.getHTTPRequestParameter(req, "validity");
+ User user = AuthorityContext.getInstance().getUserController().findOne(QueryFactory.create().addRestriction(RestrictionFactory.eq("userName", username)));
+ if (user == null) {
+ throw new UserNotExistException();
+ }
+ if (!StringUtils.equals(DigestUtils.sha256Hex(password), user.getPassword())) {
+ throw new BadPasswordException();
+ }
+ long timeout = getTokenTimeOutByValidity(Integer.parseInt(validity));
+ String token = generateToken(user.getUserName(), user.getDisplayName(), user.getTenantId(),timeout );
+ Device device = NetworkHelper.getDevice(req);
+ TerminalHandler handler = TerminalHandler.getTerminal(req, device);
+ LoginClientBean clientBean = new LoginClientBean(req, device, handler);
+ clientBean.setUsername(user.getUserName());
+ clientBean.setToken(token);
+ clientBean.setValidity(Integer.parseInt(validity));
+ clientBean.setUserId(user.getId());
+ this.addLoginStatus(token, clientBean, timeout);
+ this.writeToken2Cookie(res, token, Integer.parseInt(validity));
+
+ domainResponse = CrossDomainResponse.create().callbackFuncName("callback").parameter("accessToken",token).parameter("url", render).parameter("status", "success");
+ } catch (Exception e) {
+ FineLoggerFactory.getLogger().error(e.getMessage(), e);
+ domainResponse = CrossDomainResponse.error(e, "callback");
+ }
+ try {
+ WebUtils.printAsString(res, domainResponse.createCrossDomainResponse());
+ ;
+ } catch (Exception e) {
+ FineLoggerFactory.getLogger().error(e.getMessage(), e);
+ }
+ }
+ private void writeToken2Cookie(HttpServletResponse res, String token, int validity) {
+ try {
+ if (StringUtils.isNotEmpty(token)) {
+ Cookie tokenCookie = new Cookie("fine_auth_token", token);
+ long timeout = validity == -2 ? 1209600000L : (long)validity;
+ tokenCookie.setMaxAge((int)timeout);
+ tokenCookie.setPath(ServerConfig.getInstance().getCookiePath());
+ res.addCookie(tokenCookie);
+ Cookie rememberLogin = new Cookie("fine_remember_login", String.valueOf(validity == -2 ? -2 : -1));
+ rememberLogin.setMaxAge((int)timeout);
+ rememberLogin.setPath(ServerConfig.getInstance().getCookiePath());
+ res.addCookie(rememberLogin);
+ } else {
+ FineLoggerFactory.getLogger().error("empty token cannot save.");
+ }
+ } catch (Exception e) {
+ FineLoggerFactory.getLogger().error(e.getMessage(), e);
+ }
+
+ }
+
+ private void addLoginStatus(String token, LoginClientBean bean, long timeout) throws Exception {
+ DecisionStatusService.loginStatusService().put(token, bean, new Converter() {
+ @Override
+ public String[] createAlias(LoginClientBean bean) {
+ return new String[]{bean.getUsername()};
+ }
+ }, timeout);
+ }
+
+ private long getTokenTimeOutByValidity(int validity) {
+ return validity == -2 ? 1209600000L : FSConfig.getInstance().getLoginConfig().getLoginTimeout();
+ }
+
+ private String generateToken(String username, String displayName, String tenanId, long validity) {
+ HashMap map = new HashMap();
+ map.put("description", displayName);
+ map.put("tenantId", tenanId);
+ return JwtUtils.createDefaultJWT(username, map, validity);
+ }
+}