|
@@ -0,0 +1,367 @@
|
|
|
+package com.kingdee.eas.custom.sso;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.kingdee.bos.BOSException;
|
|
|
+import com.kingdee.bos.Context;
|
|
|
+import com.kingdee.eas.cp.eip.sso.util.CASLoginConfigPropUtil;
|
|
|
+import com.kingdee.eas.cp.eip.sso.util.CloudParamUtil;
|
|
|
+import com.kingdee.eas.util.app.DbUtil;
|
|
|
+import com.kingdee.jdbc.rowset.IRowSet;
|
|
|
+import com.kingdee.shr.base.syssetting.exception.SHRWebException;
|
|
|
+import com.kingdee.util.StringUtils;
|
|
|
+import okhttp3.OkHttpClient;
|
|
|
+import okhttp3.Request;
|
|
|
+import okhttp3.Response;
|
|
|
+import org.apache.log4j.Logger;
|
|
|
+
|
|
|
+import javax.servlet.ServletException;
|
|
|
+import javax.servlet.http.HttpServlet;
|
|
|
+import javax.servlet.http.HttpServletRequest;
|
|
|
+import javax.servlet.http.HttpServletResponse;
|
|
|
+import java.io.*;
|
|
|
+import java.net.URLEncoder;
|
|
|
+import java.sql.SQLException;
|
|
|
+import java.text.MessageFormat;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Properties;
|
|
|
+import java.util.Random;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @Description OA移动端单点移动bos
|
|
|
+ * @Date 2024/10/30 11:22
|
|
|
+ * @Created by Heyuan
|
|
|
+ */
|
|
|
+public class OAToMBos extends HttpServlet {
|
|
|
+ private static Logger logger = Logger.getLogger(OAToMBos.class);
|
|
|
+ private static ExpiringMapCache<String, String> redirectUrlCache = new ExpiringMapCache<>();
|
|
|
+ private Properties prop = new Properties();
|
|
|
+ private String propPath = System.getProperty("EAS_HOME") + "/server/properties/scy/OAToMBosConfig.properties";
|
|
|
+ private final String MBOSAPPROVECENTERURL = "https://mbos.kdeascloud.com/mbos/page/loadPage?appid=10036&eid={0}&path=lczs2&name=lczshome.navui";
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
|
|
+ throws ServletException, IOException {
|
|
|
+ logger.error("OAToMBos -> doGet");
|
|
|
+ doPost(req, resp);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp)
|
|
|
+ throws ServletException, IOException {
|
|
|
+ logger.error("OAToMBos -> doPost");
|
|
|
+ BufferedReader streamReader = null;
|
|
|
+ String resultStr = null;
|
|
|
+ prop.load(new FileInputStream(propPath));
|
|
|
+ logger.error("OAToMBos requestUrl" + req.getRequestURL().toString());
|
|
|
+ try {
|
|
|
+ String ticket = req.getParameter("ticket");
|
|
|
+ String token = req.getParameter("token");
|
|
|
+ logger.error("接收到的请求参数是:ticket " + ticket);
|
|
|
+ if (!StringUtils.isEmpty(ticket)) {
|
|
|
+ //重定向到Mbos
|
|
|
+ redirectMbos(req, resp, ticket);
|
|
|
+ } else if (!StringUtils.isEmpty(token)) {
|
|
|
+ //获取用户信息(mbos回调)
|
|
|
+ getTokenUrl(req, resp, token);
|
|
|
+ } else {
|
|
|
+ //认证
|
|
|
+ authorize(req, resp);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ Map result = new HashMap();
|
|
|
+ result.put("msgType", "0");
|
|
|
+ result.put("reason", e.getMessage());
|
|
|
+ resultStr = JSON.toJSONString(result);
|
|
|
+ resp.setStatus(500);
|
|
|
+ PrintWriter writer = resp.getWriter();
|
|
|
+ resp.setContentType("application/json");
|
|
|
+ writer.write(resultStr);
|
|
|
+ writer.close();
|
|
|
+ } finally {
|
|
|
+ try {
|
|
|
+ if (streamReader != null) {
|
|
|
+ streamReader.close();
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 重定向到mbos
|
|
|
+ *
|
|
|
+ * @param req
|
|
|
+ * @param resp
|
|
|
+ * @param ticket
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
+ private void redirectMbos(HttpServletRequest req,
|
|
|
+ HttpServletResponse resp,
|
|
|
+ String ticket) throws IOException {
|
|
|
+ if (StringUtils.isEmpty(ticket)) {
|
|
|
+ throw new RuntimeException("ticket不能为空!");
|
|
|
+ }
|
|
|
+ String getAccessTokenPath = prop.getProperty("getAccessTokenPath");
|
|
|
+ if (StringUtils.isEmpty(getAccessTokenPath)) {
|
|
|
+ throw new RuntimeException("getAccessTokenPath不能为空! 请检查配置文件: " + propPath);
|
|
|
+ }
|
|
|
+ String client_secret = prop.getProperty("client_secret");
|
|
|
+ if (StringUtils.isEmpty(client_secret)) {
|
|
|
+ throw new RuntimeException("client_secret不能为空! 请检查配置文件: " + propPath);
|
|
|
+ }
|
|
|
+ String client_id = prop.getProperty("client_id");
|
|
|
+ if (StringUtils.isEmpty(client_id)) {
|
|
|
+ throw new RuntimeException("client_id不能为空! 请检查配置文件: " + propPath);
|
|
|
+ }
|
|
|
+ String redirect_uri2 = prop.getProperty("redirect_uri2");
|
|
|
+ if (StringUtils.isEmpty(redirect_uri2)) {
|
|
|
+ throw new RuntimeException("redirect_uri2不能为空! 请检查配置文件: " + propPath);
|
|
|
+ }
|
|
|
+ String getLoginIdPath = prop.getProperty("getLoginIdPath");
|
|
|
+ if (StringUtils.isEmpty(getLoginIdPath)) {
|
|
|
+ throw new RuntimeException("getLoginIdPath不能为空! 请检查配置文件: " + propPath);
|
|
|
+ }
|
|
|
+ String redirectUrlKey = req.getParameter("redirect");
|
|
|
+ logger.error("callBack redirectUrl" + redirectUrlKey);
|
|
|
+ Map params = new HashMap();
|
|
|
+ params.put("client_id", client_id);
|
|
|
+ params.put("client_secret", client_secret);
|
|
|
+ params.put("grant_type", "authorization_code");
|
|
|
+ params.put("code", ticket);
|
|
|
+ params.put("redirect_uri", URLEncoder.encode(redirect_uri2, "UTF-8"));
|
|
|
+ try {
|
|
|
+ String redirectUrl = null;
|
|
|
+ String token = getAccessToken(getAccessTokenPath, params);
|
|
|
+ logger.error(token);
|
|
|
+ if (StringUtils.isEmpty(redirectUrlKey)) {
|
|
|
+ String eid = prop.getProperty("eid");
|
|
|
+ if (org.apache.commons.lang3.StringUtils.isEmpty(eid)) {
|
|
|
+ throw new RuntimeException("eid不能为空! 请检查配置文件: " + propPath);
|
|
|
+ }
|
|
|
+ redirectUrl = MessageFormat.format(MBOSAPPROVECENTERURL, eid);
|
|
|
+ } else {
|
|
|
+ redirectUrl = redirectUrlCache.get(redirectUrlKey);
|
|
|
+ }
|
|
|
+ Map toMbosparams = new HashMap();
|
|
|
+ toMbosparams.put("token", token);
|
|
|
+ String urlString = appendUrl(redirectUrl, toMbosparams);
|
|
|
+ resp.sendRedirect(urlString);
|
|
|
+ logger.error("redirectMbos url" + urlString);
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ throw new RuntimeException(e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 认证
|
|
|
+ * 拼接OA认证接口地址,转发
|
|
|
+ *
|
|
|
+ * @param resp
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public void authorize(HttpServletRequest req, HttpServletResponse resp) throws Exception {
|
|
|
+ String authorizePath = prop.getProperty("authorizePath");
|
|
|
+ if (StringUtils.isEmpty(authorizePath)) {
|
|
|
+ throw new RuntimeException("authorizePath不能为空! 请检查配置文件: " + propPath);
|
|
|
+ }
|
|
|
+ String response_type = prop.getProperty("response_type");
|
|
|
+ if (StringUtils.isEmpty(response_type)) {
|
|
|
+ throw new RuntimeException("response_type不能为空! 请检查配置文件: " + propPath);
|
|
|
+ }
|
|
|
+ String client_id = prop.getProperty("client_id");
|
|
|
+ if (StringUtils.isEmpty(client_id)) {
|
|
|
+ throw new RuntimeException("client_id不能为空! 请检查配置文件: " + propPath);
|
|
|
+ }
|
|
|
+ String redirect_uri1 = prop.getProperty("redirect_uri1");
|
|
|
+ if (StringUtils.isEmpty(redirect_uri1)) {
|
|
|
+ throw new RuntimeException("redirect_uri1不能为空! 请检查配置文件: " + propPath);
|
|
|
+ }
|
|
|
+ String redirectUrl = req.getParameter("redirect");
|
|
|
+ if (StringUtils.isEmpty(redirectUrl)) {
|
|
|
+ String serverName = prop.getProperty("serverName");
|
|
|
+ if (StringUtils.isEmpty(serverName)) {
|
|
|
+ throw new RuntimeException("serverName不能为空! 请检查配置文件: " + propPath);
|
|
|
+ }
|
|
|
+ redirectUrl = serverName + "/shr/dynamic.do?uipk=shr.perself.homepage";
|
|
|
+ }
|
|
|
+ Random random = new Random();
|
|
|
+ String key = System.currentTimeMillis() + String.valueOf(random.nextInt(99999));
|
|
|
+ redirectUrlCache.put(key, redirectUrl, 300000);
|
|
|
+ logger.error("callBack redirectUrl" + redirectUrl);
|
|
|
+ redirect_uri1 += "?redirect=" + key;
|
|
|
+ Map params = new HashMap();
|
|
|
+ params.put("client_id", client_id);
|
|
|
+ params.put("response_type", response_type);
|
|
|
+ params.put("redirect_uri", URLEncoder.encode(redirect_uri1, "UTF-8"));
|
|
|
+ String urlString = appendUrl(authorizePath, params);
|
|
|
+ resp.sendRedirect(urlString);
|
|
|
+ logger.error("authorize url" + urlString);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取用户信息
|
|
|
+ * 用户信息
|
|
|
+ *
|
|
|
+ * @param req
|
|
|
+ * @param resp
|
|
|
+ * @param token
|
|
|
+ * @throws SHRWebException
|
|
|
+ * @throws UnsupportedEncodingException
|
|
|
+ */
|
|
|
+ public void getTokenUrl(HttpServletRequest req,
|
|
|
+ HttpServletResponse resp, String token) throws
|
|
|
+ SHRWebException, IOException {
|
|
|
+ logger.error("getTokenUrl方法入参");
|
|
|
+ if (StringUtils.isEmpty(token)) {
|
|
|
+ throw new RuntimeException("token不能为空!");
|
|
|
+ }
|
|
|
+ String getLoginIdPath = prop.getProperty("getLoginIdPath");
|
|
|
+ if (StringUtils.isEmpty(getLoginIdPath)) {
|
|
|
+ throw new RuntimeException("getLoginIdPath不能为空! 请检查配置文件: " + propPath);
|
|
|
+ }
|
|
|
+ Map result = new HashMap();
|
|
|
+ try {
|
|
|
+ //从人员对象,获取纷享用户userId
|
|
|
+ String loginId = loginId2userId(getLoginIdPath, token);
|
|
|
+ result.put("status", "0");
|
|
|
+ result.put("message", loginId);
|
|
|
+ resp.setStatus(200);
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ result.put("status", "1");
|
|
|
+ result.put("message", e.getMessage());
|
|
|
+ resp.setStatus(500);
|
|
|
+ }
|
|
|
+ PrintWriter writer = resp.getWriter();
|
|
|
+ resp.setContentType("application/json");
|
|
|
+ writer.write(JSON.toJSONString(result));
|
|
|
+ writer.close();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取泛微token方法
|
|
|
+ *
|
|
|
+ * @param getAccessTokenPath
|
|
|
+ * @param params
|
|
|
+ * @return
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
+ private String getAccessToken(String getAccessTokenPath, Map<String, String> params)
|
|
|
+ throws IOException {
|
|
|
+ logger.error("getAccessToken方法参数: " + params);
|
|
|
+ String url = appendUrl(getAccessTokenPath, params);
|
|
|
+ logger.error("access_token url" + url);
|
|
|
+ OkHttpClient client = new OkHttpClient();
|
|
|
+ Request request = new Request.Builder()
|
|
|
+ .url(url)
|
|
|
+ .get()
|
|
|
+ .addHeader("content-type", "multipart/form-data; boundary=---011000010111000001101001")
|
|
|
+ .build();
|
|
|
+ Response response = client.newCall(request).execute();
|
|
|
+ if (response.isSuccessful()) {
|
|
|
+ String string = response.body().string();
|
|
|
+ JSONObject jsonObject = JSONObject.parseObject(string);
|
|
|
+ String code = jsonObject.getString("code");
|
|
|
+ if ("0".equals(code)) {
|
|
|
+ String access_token = jsonObject.getString("access_token");
|
|
|
+ logger.error("access_token " + access_token);
|
|
|
+ return access_token;
|
|
|
+ } else {
|
|
|
+ throw new RuntimeException(jsonObject.getString("msg"));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ //网络超时
|
|
|
+ throw new RuntimeException("获取token超时");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取用户信息
|
|
|
+ *
|
|
|
+ * @param accessToken
|
|
|
+ * @return
|
|
|
+ * @throws IOException
|
|
|
+ * @throws BOSException
|
|
|
+ * @throws SQLException
|
|
|
+ */
|
|
|
+ private String loginId2userId(String getLoginIdPath, String accessToken)
|
|
|
+ throws IOException, BOSException, SQLException {
|
|
|
+ if (StringUtils.isEmpty(accessToken)) {
|
|
|
+ throw new RuntimeException("accessToken不能为空! ");
|
|
|
+ }
|
|
|
+ //获取第三方用户信息
|
|
|
+ Map params = new HashMap();
|
|
|
+ params.put("access_token", accessToken);
|
|
|
+ String url = appendUrl(getLoginIdPath, params);
|
|
|
+ logger.error("loginId2userId url" + url);
|
|
|
+ OkHttpClient client = new OkHttpClient();
|
|
|
+ Request request = new Request.Builder()
|
|
|
+ .url(url)
|
|
|
+ .get()
|
|
|
+ .addHeader("content-type", "multipart/form-data; boundary=---011000010111000001101001")
|
|
|
+ .build();
|
|
|
+ Response response = client.newCall(request).execute();
|
|
|
+ if (response.isSuccessful()) {
|
|
|
+ String string = response.body().string();
|
|
|
+ JSONObject jsonObject = JSONObject.parseObject(string);
|
|
|
+ String code = jsonObject.getString("code");
|
|
|
+ if ("0".equals(code)) {
|
|
|
+ JSONObject attributes = jsonObject.getJSONObject("attributes");
|
|
|
+ //登录id
|
|
|
+ String loginid = attributes.getString("loginid");
|
|
|
+ String dataCenter = CASLoginConfigPropUtil.getDataCenter();
|
|
|
+ String locale = CASLoginConfigPropUtil.getLocale();
|
|
|
+ if (!StringUtils.isEmpty(dataCenter) && !StringUtils.isEmpty(locale)) {
|
|
|
+ Context ctx = CloudParamUtil.getContext(dataCenter, locale, "administrator");
|
|
|
+ String sql = "SELECT count(1) total FROM T_PM_USER WHERE fnumber=?";
|
|
|
+ IRowSet rs = DbUtil.executeQuery(ctx, sql, new Object[]{loginid});
|
|
|
+ int total = 0;
|
|
|
+ if (rs.next()) {
|
|
|
+ total = rs.getInt("total");
|
|
|
+ }
|
|
|
+ if (total <= 0) {
|
|
|
+ logger.error("SHR找不到对应的用户, loginid:" + loginid);
|
|
|
+ throw new RuntimeException("SHR找不到对应的用户, loginid: " + loginid);
|
|
|
+ //("您无权限访问SHR系统,请联系管理员处理。")
|
|
|
+ } else if (total > 1) {
|
|
|
+ logger.error("SHR找到多个对应的用户, loginid:" + loginid);
|
|
|
+ throw new RuntimeException("SHR找到多个对应的用户, loginid: " + loginid);
|
|
|
+ //("您无权限访问SHR系统,请联系管理员处理。")
|
|
|
+ } else {
|
|
|
+ return loginid;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ logger.error("获取用户信息报错,数据中心没找到!");
|
|
|
+ throw new RuntimeException("获取用户信息报错,数据中心没找到!");
|
|
|
+ } else {
|
|
|
+ logger.error(jsonObject.getString("msg"));
|
|
|
+ throw new RuntimeException(jsonObject.getString("msg"));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ //网络超时
|
|
|
+ logger.error("网络超时");
|
|
|
+ throw new RuntimeException("网络超时");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 拼接地址参数
|
|
|
+ */
|
|
|
+ private static String appendUrl(String url, Map<String, String> data) {
|
|
|
+ logger.error("appendUrl_url: " + url);
|
|
|
+ logger.error("appendUrl_data: " + data);
|
|
|
+ StringBuilder paramStr = new StringBuilder();
|
|
|
+ for (String key : data.keySet()) {
|
|
|
+ paramStr.append(key).append("=").append(data.get(key)).append("&");
|
|
|
+ }
|
|
|
+ paramStr.deleteCharAt(paramStr.lastIndexOf("&"));
|
|
|
+ String str = url.contains("?") ? (url + "&" + paramStr) : (url + "?" + paramStr);
|
|
|
+ logger.error("拼接后的地址为:" + str);
|
|
|
+ return str;
|
|
|
+ }
|
|
|
+}
|