diff --git a/JSD-8486-需求文档V1.docx b/JSD-8486-需求文档V1.docx new file mode 100644 index 0000000..26c8209 Binary files /dev/null and b/JSD-8486-需求文档V1.docx differ diff --git a/README.md b/README.md index f533354..e1814df 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ # open-JSD-8486 -JSD-8486 开源任务材料 \ No newline at end of file +JSD-8486 IDM单点+组织架构同步\ +免责说明:该源码为第三方爱好者提供,不保证源码和方案的可靠性,也不提供任何形式的源码教学指导和协助!\ +仅作为开发者学习参考使用!禁止用于任何商业用途!\ +为保护开发者隐私,开发者信息已隐去!若原开发者希望公开自己的信息,可联系hugh处理。 \ No newline at end of file diff --git a/conf.properties b/conf.properties new file mode 100644 index 0000000..dba9a45 --- /dev/null +++ b/conf.properties @@ -0,0 +1,17 @@ +##\u8BF7\u6C42\u7528\u6237\u4FE1\u606F\u7684\u63A5\u53E3 +userinfourl= +##\u6821\u9A8Ctoken\u4FE1\u606F\u7684\u63A5\u53E3 +validationurl= +##\u670D\u52A1\u7F16\u53F7 +servicecode= +##\u670D\u52A1\u79D8\u94A5 +servicepwd= +# \u63A5\u53E3\u6240\u9700\u7684\u53C2\u6570\u503C +api.client_id=xxxx +api.client_secret=xxxx +# \u767B\u9646\u9875\u9762\u83B7\u53D6code\u5730\u5740 +api.authorize=https://xxxx/oauth2/authorize +# \u83B7\u53D6access_token\u63A5\u53E3 +api.get-token=https://xxxx/oauth2/token +# \u83B7\u53D6\u7528\u6237\u4FE1\u606F\u63A5\u53E3 +api.get-user=https://xxxx/oauth2/get_user_info \ No newline at end of file diff --git a/plugin.xml b/plugin.xml new file mode 100644 index 0000000..7ad7c88 --- /dev/null +++ b/plugin.xml @@ -0,0 +1,22 @@ + + com.fr.plugin.idm.sso + com.fr.plugin.idm.sso + + yes + 1.8 + 10.0 + 2018-07-31 + holger + + + + + + + + + + \ No newline at end of file diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..8191d54 --- /dev/null +++ b/readme.txt @@ -0,0 +1,7 @@ +此次完成功能如下 + a、单点登录 + +1、将压缩文件解压后的conf.properties配置文件拷贝至 %部署路径%/WEB-INF/resources, 并修改相应的属性配置 +2、安装本插件,插件安装见连接http://help.finereport.com/doc-view-2198.html +3、进入系统测试单点登录 + PC端访问地址为http://ip:port/webroot/decision \ No newline at end of file diff --git a/src/main/java/com/fr/plugin/idm/sso/BaseAction.java b/src/main/java/com/fr/plugin/idm/sso/BaseAction.java new file mode 100644 index 0000000..9cc69de --- /dev/null +++ b/src/main/java/com/fr/plugin/idm/sso/BaseAction.java @@ -0,0 +1,62 @@ +package com.fr.plugin.idm.sso; + +import com.fr.general.IOUtils; +import com.fr.json.JSONObject; +import com.fr.json.revise.EmbedJson; +import com.fr.stable.StringUtils; +import com.fr.stable.db.entity.BaseEntity; +import com.fr.third.fasterxml.jackson.databind.DeserializationFeature; +import com.fr.third.fasterxml.jackson.databind.ObjectMapper; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @Author fr.open + * @Date 2020/8/18 + * @Description + **/ +public abstract class BaseAction { + + /** + * 执行的业务方法 + * @param req + * @param res + * @return + */ + public abstract IdmResponse handel(HttpServletRequest req, HttpServletResponse res) throws Exception; + + public T getBody(HttpServletRequest req,Class t) throws IOException, SyncException { + String body = IOUtils.inputStream2String(req.getInputStream()); + if(StringUtils.isBlank(body)){ + throw new SyncException("body_is_null"); + } + JSONObject jsonObject = new JSONObject(body); + if(jsonObject.isEmpty()){ + throw new SyncException("json_is_null"); + } + return (T) getEntity(jsonObject,t); + + + } + + public JSONObject getBody(HttpServletRequest req) throws IOException, SyncException { + String body = IOUtils.inputStream2String(req.getInputStream()); + if(StringUtils.isBlank(body)){ + throw new SyncException("body_is_null"); + } + JSONObject jsonObject = new JSONObject(body); + if(jsonObject.isEmpty()){ + throw new SyncException("json_is_null"); + } + return jsonObject; + + + } + + protected T getEntity(JSONObject object, Class t) { + ObjectMapper mapper = EmbedJson.MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + return mapper.convertValue(object, t); + } +} diff --git a/src/main/java/com/fr/plugin/idm/sso/IdmResponse.java b/src/main/java/com/fr/plugin/idm/sso/IdmResponse.java new file mode 100644 index 0000000..82c4fdb --- /dev/null +++ b/src/main/java/com/fr/plugin/idm/sso/IdmResponse.java @@ -0,0 +1,100 @@ +package com.fr.plugin.idm.sso; + +import com.fr.third.fasterxml.jackson.annotation.JsonInclude; + +import java.io.Serializable; +import java.util.HashMap; + +/** + * @Author fr.open + * @Date 2020/12/10 + * @Description + **/ +@JsonInclude(JsonInclude.Include.NON_DEFAULT) +public class IdmResponse implements Serializable { + private int status; + private String errorCode; + private String errorMsg; + private Object result; + + public IdmResponse() { + } + + public IdmResponse status(int var1) { + this.status = var1; + return this; + } + + public IdmResponse errorCode(String var1) { + this.errorCode = var1; + return this; + } + + public IdmResponse errorMsg(String var1) { + this.errorMsg = var1; + return this; + } + + public IdmResponse data(Object var1) { + this.result = var1; + return this; + } + + public Object getResult() { + return this.result; + } + + public void setResult(Object var1) { + this.result = var1; + } + + public String getErrorCode() { + return this.errorCode; + } + + public void setErrorCode(String var1) { + this.errorCode = var1; + } + + public String getErrorMsg() { + return this.errorMsg; + } + + public void setErrorMsg(String var1) { + this.errorMsg = var1; + } + + public int getStatus() { + return this.status; + } + + public void setStatus(int var1) { + this.status = var1; + } + + private static IdmResponse create() { + return new IdmResponse(); + } + + public static IdmResponse ok(Object var0) { + return create().data(var0); + } + + public static IdmResponse success() { + return ok("0"); + } + + public static IdmResponse success(int var0) { + HashMap var1 = new HashMap(); + var1.put("count", var0); + return ok(var1); + } + + public static IdmResponse error(int var0, String var1, String var2) { + return create().status(var0).errorCode(var1).errorMsg(var2); + } + + public static IdmResponse error(String var0, String var1) { + return create().errorCode(var0).errorMsg(var1); + } +} diff --git a/src/main/java/com/fr/plugin/idm/sso/PluginConstants.java b/src/main/java/com/fr/plugin/idm/sso/PluginConstants.java new file mode 100644 index 0000000..09cb172 --- /dev/null +++ b/src/main/java/com/fr/plugin/idm/sso/PluginConstants.java @@ -0,0 +1,11 @@ +package com.fr.plugin.idm.sso; + +/** + * @Author fr.open + * @Date 2021/9/15 + * @Description + **/ +public class PluginConstants { + + public static final String PLUGIN_ID = "com.fr.plugin.idm.sso"; +} diff --git a/src/main/java/com/fr/plugin/idm/sso/RecordDBAccessProvider.java b/src/main/java/com/fr/plugin/idm/sso/RecordDBAccessProvider.java new file mode 100644 index 0000000..09c23f7 --- /dev/null +++ b/src/main/java/com/fr/plugin/idm/sso/RecordDBAccessProvider.java @@ -0,0 +1,69 @@ +package com.fr.plugin.idm.sso; + +import com.fr.db.fun.impl.AbstractDBAccessProvider; +import com.fr.plugin.idm.sso.dao.OrgDao; +import com.fr.plugin.idm.sso.dao.UserDao; +import com.fr.plugin.idm.sso.dao.UserOrgDao; +import com.fr.plugin.idm.sso.entity.OrgEntity; +import com.fr.plugin.idm.sso.entity.UserEntity; +import com.fr.plugin.idm.sso.entity.UserOrgEntity; +import com.fr.stable.db.accessor.DBAccessor; +import com.fr.stable.db.dao.BaseDAO; +import com.fr.stable.db.dao.DAOProvider; + +/** + * @Author fr.open + * @Date 2020/5/24 + **/ +public class RecordDBAccessProvider extends AbstractDBAccessProvider { + + private static DBAccessor dbAccessor = null; + + public static DBAccessor getDbAccessor() { + return dbAccessor; + } + + @Override + public DAOProvider[] registerDAO() { + return new DAOProvider[]{ + new DAOProvider() { + @Override + public Class getEntityClass() { + return UserEntity.class; + } + + @Override + public Class getDAOClass() { + return UserDao.class; + } + }, + new DAOProvider() { + @Override + public Class getEntityClass() { + return OrgEntity.class; + } + + @Override + public Class getDAOClass() { + return OrgDao.class; + } + }, + new DAOProvider() { + @Override + public Class getEntityClass() { + return UserOrgEntity.class; + } + + @Override + public Class getDAOClass() { + return UserOrgDao.class; + } + } + }; + } + + @Override + public void onDBAvailable(DBAccessor dbAccessor) { + RecordDBAccessProvider.dbAccessor = dbAccessor; + } +} diff --git a/src/main/java/com/fr/plugin/idm/sso/SsoFilter.java b/src/main/java/com/fr/plugin/idm/sso/SsoFilter.java new file mode 100644 index 0000000..0cd02c9 --- /dev/null +++ b/src/main/java/com/fr/plugin/idm/sso/SsoFilter.java @@ -0,0 +1,216 @@ +package com.fr.plugin.idm.sso; + +import com.fr.decision.fun.impl.AbstractGlobalRequestFilterProvider; +import com.fr.decision.webservice.Response; +import com.fr.decision.webservice.utils.WebServiceUtils; +import com.fr.general.PropertiesUtils; +import com.fr.general.http.HttpToolbox; +import com.fr.intelli.record.Focus; +import com.fr.intelli.record.Original; +import com.fr.json.JSONObject; +import com.fr.locale.InterProviderFactory; +import com.fr.log.FineLoggerFactory; +import com.fr.plugin.context.PluginContexts; +import com.fr.plugin.idm.sso.action.OrgAction; +import com.fr.plugin.idm.sso.action.UserAction; +import com.fr.plugin.transform.FunctionRecorder; +import com.fr.stable.StringUtils; +import com.fr.stable.fun.Authorize; +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.io.PrintWriter; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.UUID; +import java.util.stream.Stream; + +import static com.fr.plugin.idm.sso.util.CommonUtils.*; + +/** + * @Author fr.open + * @Date 2020/8/18 + * @Description + **/ +@FunctionRecorder +@Authorize(callSignKey = PluginConstants.PLUGIN_ID) +public class SsoFilter extends AbstractGlobalRequestFilterProvider { + + private final static String[] NOT_FILTER = { + "/decision/file", + "/decision/resources", + "/decision/login/config", + "/decision/system", + "/decision/login/slider", + "/decision/remote", + "/decision/login" + }; + + private String apiClientId; + + private String apiClientSecret; + + private String apiAuthorize; + + private String apiGetToken; + + private String apiGetUser; + + private void initParams() { + Properties props = PropertiesUtils.getProperties("conf"); + this.apiClientId = getProperty(props, "api.client_id", false); + this.apiAuthorize = getProperty(props, "api.authorize", false); + this.apiGetToken = getProperty(props, "api.get-token", false); + this.apiGetUser = getProperty(props, "api.get-user", false); + this.apiClientSecret = getProperty(props, "api.client_secret", false); + } + + @Override + public String filterName() { + return "sso"; + } + + @Override + public String[] urlPatterns() { + return new String[]{"/*"}; + } + + @Override + @Focus(id = PluginConstants.PLUGIN_ID, text = "idm单点", source = Original.PLUGIN) + public void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) { + if (!PluginContexts.currentContext().isAvailable()) { + next(req, res, chain); + return; + } + + BaseAction action = null; + if (req.getRequestURI().endsWith("sync/org")) { + action = new OrgAction(); + } else if (req.getRequestURI().endsWith("sync/user")) { + action = new UserAction(); + } + if (action != null) { + executeAction(req, res, action); + return; + } + //执行单点登录 + if (isAccept(req)) { + next(req, res, chain); + return; + } + try { + initParams(); + String code = req.getParameter("code"); + if (StringUtils.isBlank(code)) { + jumpAuthorize(req, res); + return; + } + login(getUsername(getToken(code, req)), req, res); + String state = req.getParameter("state"); + if (StringUtils.isNotBlank(state)) { + String accessURL = getCachedParam(state, "accessURL"); + if (StringUtils.isNotBlank(accessURL)) { + res.sendRedirect(accessURL); + return; + } + } + } catch (Exception e) { + FineLoggerFactory.getLogger().error("sso >>> 单点登陆处理失败", e); + setError(res, e.getMessage()); + } + + next(req, res, chain); + } + + private boolean isAccept(HttpServletRequest request) { + String url = request.getRequestURL().toString(); + if (Stream.of(NOT_FILTER).anyMatch(url::contains)) { + return true; + } + return isLogin(request); + } + + private String getUsername(String token) throws IOException { + HashMap params = new HashMap<>(); + params.put("access_token", token); + String res = HttpToolbox.get(apiGetUser, params); + JSONObject body = new JSONObject(res); + if (body.has("name")) { + return body.getString("name"); + } + throw new RuntimeException("获取用户信息失败,Cause by: " + res); + } + + private String getToken(String code, HttpServletRequest request) throws IOException { + HashMap params = new HashMap<>(); + params.put("grant_type", "authorization_code"); + params.put("code", code); + params.put("client_id", apiClientId); + params.put("client_secret", apiClientSecret); + params.put("redirect_uri", request.getRequestURL().toString()); + String res = HttpToolbox.get(apiGetToken, params); + JSONObject body = new JSONObject(res); + if (body.has("access_token")) { + return body.getString("access_token"); + } + throw new RuntimeException("获取access_token失败,Cause by: " + res); + } + + private void jumpAuthorize(HttpServletRequest request, HttpServletResponse response) throws IOException { + String state = UUID.randomUUID().toString(); + String accessURL = request.getRequestURI(); + if (StringUtils.isNotBlank(request.getQueryString())) { + accessURL += "?" + request.getQueryString(); + } + Map params = new HashMap<>(); + params.put("accessURL", accessURL); + cacheParams(state, params); + String address = String.format("%s?response_type=code&client_id=%s&state=%s&redirect_uri=%s", apiAuthorize, apiClientId, state, URLEncoder.encode(request.getRequestURL().toString(), "utf-8")); + FineLoggerFactory.getLogger().info("oauth2 >>> 请求中不包含code值,条转到登陆页面 >>> \"{}\"", address); + response.sendRedirect(address); + } + + private void executeAction(HttpServletRequest req, HttpServletResponse res, BaseAction action) { + try { + IdmResponse response = action.handel(req, res); + WebUtils.printAsJSON(res, JSONObject.mapFrom(response)); + } catch (SyncException e) { + try { + WebUtils.printAsJSON(res, JSONObject.mapFrom(Response.error(e.getMessage(), e.getMessage()))); + } catch (Exception exception) { + FineLoggerFactory.getLogger().error(e.getMessage(),e); + } + } catch (Exception e) { + try { + FineLoggerFactory.getLogger().error(e.getMessage(),e); + WebUtils.printAsJSON(res, JSONObject.mapFrom(Response.error("unknown_error", e.getMessage()))); + } catch (Exception exception) { + FineLoggerFactory.getLogger().error(e.getMessage(),e); + } + } + } + + private void setError(HttpServletResponse res, String reason) { + try { + PrintWriter printWriter = WebUtils.createPrintWriter(res); + Map map = new HashMap<>(); + map.put("result", InterProviderFactory.getProvider().getLocText("Fine-Engine_Error_Page_Result")); + map.put("reason", reason); + map.put("solution", InterProviderFactory.getProvider().getLocText("Fine-Engine_Please_Contact_Platform_Admin")); + String page = WebServiceUtils.parseWebPageResourceSafe("com/fr/web/controller/decision/entrance/resources/unavailable.html", map); + printWriter.write(page); + printWriter.flush(); + printWriter.close(); + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(), e); + } + } + + +} diff --git a/src/main/java/com/fr/plugin/idm/sso/SyncException.java b/src/main/java/com/fr/plugin/idm/sso/SyncException.java new file mode 100644 index 0000000..b93dcab --- /dev/null +++ b/src/main/java/com/fr/plugin/idm/sso/SyncException.java @@ -0,0 +1,12 @@ +package com.fr.plugin.idm.sso; + +/** + * @Author fr.open + * @Date 2020/8/19 + * @Description + **/ +public class SyncException extends Exception { + public SyncException(String message) { + super(message); + } +} diff --git a/src/main/java/com/fr/plugin/idm/sso/action/OrgAction.java b/src/main/java/com/fr/plugin/idm/sso/action/OrgAction.java new file mode 100644 index 0000000..2321d5d --- /dev/null +++ b/src/main/java/com/fr/plugin/idm/sso/action/OrgAction.java @@ -0,0 +1,35 @@ +package com.fr.plugin.idm.sso.action; + +import com.fr.plugin.idm.sso.BaseAction; +import com.fr.plugin.idm.sso.IdmResponse; +import com.fr.plugin.idm.sso.RecordDBAccessProvider; +import com.fr.plugin.idm.sso.dao.OrgDao; +import com.fr.plugin.idm.sso.entity.OrgEntity; +import com.fr.stable.db.action.DBAction; +import com.fr.stable.db.dao.DAOContext; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.UUID; + +/** + * @Author fr.open + * @Date 2020/8/18 + * @Description + **/ +public class OrgAction extends BaseAction { + + @Override + public IdmResponse handel(HttpServletRequest req, HttpServletResponse res) throws Exception { + OrgEntity orgEntity = getBody(req,OrgEntity.class); + RecordDBAccessProvider.getDbAccessor().runDMLAction(new DBAction() { + @Override + public OrgEntity run(DAOContext daoContext) throws Exception { + orgEntity.setId(UUID.randomUUID().toString()); + daoContext.getDAO(OrgDao.class).add(orgEntity); + return null; + } + }); + return IdmResponse.ok("0"); + } +} diff --git a/src/main/java/com/fr/plugin/idm/sso/action/UserAction.java b/src/main/java/com/fr/plugin/idm/sso/action/UserAction.java new file mode 100644 index 0000000..cc6ad71 --- /dev/null +++ b/src/main/java/com/fr/plugin/idm/sso/action/UserAction.java @@ -0,0 +1,83 @@ +package com.fr.plugin.idm.sso.action; + +import com.fr.json.JSONArray; +import com.fr.json.JSONObject; +import com.fr.plugin.db.PluginDBManager; +import com.fr.plugin.idm.sso.BaseAction; +import com.fr.plugin.idm.sso.IdmResponse; +import com.fr.plugin.idm.sso.RecordDBAccessProvider; +import com.fr.plugin.idm.sso.dao.UserDao; +import com.fr.plugin.idm.sso.dao.UserOrgDao; +import com.fr.plugin.idm.sso.entity.OrgEntity; +import com.fr.plugin.idm.sso.entity.UserEntity; +import com.fr.plugin.idm.sso.entity.UserOrgEntity; +import com.fr.stable.db.action.DBAction; +import com.fr.stable.db.dao.DAOContext; +import com.fr.stable.db.session.DBSession; +import com.fr.stable.query.QueryFactory; +import com.fr.stable.query.restriction.RestrictionFactory; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * @Author fr.open + * @Date 2020/8/18 + * @Description + **/ +public class UserAction extends BaseAction { + + @Override + public IdmResponse handel(HttpServletRequest req, HttpServletResponse res) throws Exception { + JSONObject object = getBody(req); + JSONArray array = object.getJsonArray("userorgs"); + List list = new ArrayList<>(); + for (int i = 0; i < array.size();i++){ + JSONObject jsonObject = array.getJSONObject(i); + UserOrgEntity userOrgEntity = jsonObject.mapTo(UserOrgEntity.class); + list.add(userOrgEntity); + } + object.remove("userorgs"); + UserEntity user = this.getEntity(object,UserEntity.class); + RecordDBAccessProvider.getDbAccessor().runDMLAction(new DBAction() { + @Override + public OrgEntity run(DAOContext daoContext) throws Exception { + user.setId(UUID.randomUUID().toString()); + UserDao userDao = daoContext.getDAO(UserDao.class); + UserOrgDao userOrgDao = daoContext.getDAO(UserOrgDao.class); + userDao.addOrUpdate(user); + userOrgDao.remove(QueryFactory.create().addRestriction(RestrictionFactory.eq("uid",user.getUid()))); + for (UserOrgEntity userOrgEntity:list) { + userOrgEntity.setId(UUID.randomUUID().toString()); + userOrgDao.add(userOrgEntity); + } + return null; + } + }); + + + return IdmResponse.ok("0"); + } + + public void batchSubmit(List addData) throws Exception {//list里面的就是DBAccessProvider接口里面定义的entity对象 + DBSession session = PluginDBManager.getInstance().getDbContext().openSession(); + try { + session.beginTransaction();//开始事务 + if (addData != null) { + for (Object addO : addData) { + //添加更新的数据 + session.persist(addO); + } + } + session.commitTransaction();//提交 + // + session.closeSession(); + } catch (Exception e) { + session.rollbackTransaction();//回滚 + throw e; + } + } +} diff --git a/src/main/java/com/fr/plugin/idm/sso/dao/OrgDao.java b/src/main/java/com/fr/plugin/idm/sso/dao/OrgDao.java new file mode 100644 index 0000000..c44bbb9 --- /dev/null +++ b/src/main/java/com/fr/plugin/idm/sso/dao/OrgDao.java @@ -0,0 +1,21 @@ +package com.fr.plugin.idm.sso.dao; + +import com.fr.plugin.idm.sso.entity.OrgEntity; +import com.fr.stable.db.dao.BaseDAO; +import com.fr.stable.db.session.DAOSession; + +/** + * @Author fr.open + * @Date 2020/8/19 + * @Description + **/ +public class OrgDao extends BaseDAO { + public OrgDao(DAOSession daoSession) { + super(daoSession); + } + + @Override + protected Class getEntityClass() { + return OrgEntity.class; + } +} diff --git a/src/main/java/com/fr/plugin/idm/sso/dao/UserDao.java b/src/main/java/com/fr/plugin/idm/sso/dao/UserDao.java new file mode 100644 index 0000000..26f59ae --- /dev/null +++ b/src/main/java/com/fr/plugin/idm/sso/dao/UserDao.java @@ -0,0 +1,22 @@ +package com.fr.plugin.idm.sso.dao; + +import com.fr.plugin.idm.sso.entity.UserEntity; +import com.fr.stable.db.dao.BaseDAO; +import com.fr.stable.db.session.DAOSession; + +/** + * @Author fr.open + * @Date 2020/8/19 + * @Description + **/ +public class UserDao extends BaseDAO { + + public UserDao(DAOSession daoSession) { + super(daoSession); + } + + @Override + protected Class getEntityClass() { + return UserEntity.class; + } +} diff --git a/src/main/java/com/fr/plugin/idm/sso/dao/UserOrgDao.java b/src/main/java/com/fr/plugin/idm/sso/dao/UserOrgDao.java new file mode 100644 index 0000000..19e3797 --- /dev/null +++ b/src/main/java/com/fr/plugin/idm/sso/dao/UserOrgDao.java @@ -0,0 +1,21 @@ +package com.fr.plugin.idm.sso.dao; + +import com.fr.plugin.idm.sso.entity.UserOrgEntity; +import com.fr.stable.db.dao.BaseDAO; +import com.fr.stable.db.session.DAOSession; + +/** + * @Author fr.open + * @Date 2020/8/19 + * @Description + **/ +public class UserOrgDao extends BaseDAO { + public UserOrgDao(DAOSession daoSession) { + super(daoSession); + } + + @Override + protected Class getEntityClass() { + return UserOrgEntity.class; + } +} diff --git a/src/main/java/com/fr/plugin/idm/sso/entity/OrgEntity.java b/src/main/java/com/fr/plugin/idm/sso/entity/OrgEntity.java new file mode 100644 index 0000000..6433cac --- /dev/null +++ b/src/main/java/com/fr/plugin/idm/sso/entity/OrgEntity.java @@ -0,0 +1,90 @@ +package com.fr.plugin.idm.sso.entity; + +import com.fr.stable.db.entity.BaseEntity; +import com.fr.third.javax.persistence.Column; +import com.fr.third.javax.persistence.Entity; +import com.fr.third.javax.persistence.Table; + +/** + * @Author fr.open + * @Date 2020/8/18 + * @Description + **/ +@Entity +@Table(name = "plugin_sso_org") +public class OrgEntity extends BaseEntity { + + @Column(name = "orgtype") + private int orgtype; + @Column(name = "code") + private String code; + @Column(name = "name") + private String name; + @Column(name = "orderby") + private int orderby; + @Column(name = "oid") + private String oid; + @Column(name = "fullname") + private String fullname; + @Column(name = "poid") + private String poid; + + public OrgEntity() { + } + + public void setOrgtype(int orgtype) { + this.orgtype = orgtype; + } + + public int getOrgtype() { + return orgtype; + } + + public void setCode(String code) { + this.code = code; + } + + public String getCode() { + return code; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setOrderby(int orderby) { + this.orderby = orderby; + } + + public int getOrderby() { + return orderby; + } + + public void setOid(String oid) { + this.oid = oid; + } + + public String getOid() { + return oid; + } + + public void setFullname(String fullname) { + this.fullname = fullname; + } + + public String getFullname() { + return fullname; + } + + public void setPoid(String poid) { + this.poid = poid; + } + + public String getPoid() { + return poid; + } +} diff --git a/src/main/java/com/fr/plugin/idm/sso/entity/UserDTOEntity.java b/src/main/java/com/fr/plugin/idm/sso/entity/UserDTOEntity.java new file mode 100644 index 0000000..f761d37 --- /dev/null +++ b/src/main/java/com/fr/plugin/idm/sso/entity/UserDTOEntity.java @@ -0,0 +1,75 @@ +package com.fr.plugin.idm.sso.entity; + +import com.fr.stable.db.entity.BaseEntity; +import com.fr.third.javax.persistence.Column; +import com.fr.third.javax.persistence.Entity; +import com.fr.third.javax.persistence.Table; + +import java.util.List; + +/** + * @Author fr.open + * @Date 2020/8/18 + * @Description + **/ +public class UserDTOEntity extends BaseEntity { + + private String uid; + private int sex; + private List UserOrgs; + private String loginname; + private String mobilephone; + private String username; + + public UserDTOEntity() { + } + + public void setUid(String uid) { + this.uid = uid; + } + + public String getUid() { + return uid; + } + + public void setSex(int sex) { + this.sex = sex; + } + + public int getSex() { + return sex; + } + + public void setUserOrgs(List UserOrgs) { + this.UserOrgs = UserOrgs; + } + + public List getUserOrgs() { + return UserOrgs; + } + + public void setLoginname(String loginname) { + this.loginname = loginname; + } + + public String getLoginname() { + return loginname; + } + + public void setMobilephone(String mobilephone) { + this.mobilephone = mobilephone; + } + + public String getMobilephone() { + return mobilephone; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getUsername() { + return username; + } + +} diff --git a/src/main/java/com/fr/plugin/idm/sso/entity/UserEntity.java b/src/main/java/com/fr/plugin/idm/sso/entity/UserEntity.java new file mode 100644 index 0000000..e5d41a6 --- /dev/null +++ b/src/main/java/com/fr/plugin/idm/sso/entity/UserEntity.java @@ -0,0 +1,73 @@ +package com.fr.plugin.idm.sso.entity; + +import com.fr.stable.db.entity.BaseEntity; +import com.fr.third.javax.persistence.Column; +import com.fr.third.javax.persistence.Entity; +import com.fr.third.javax.persistence.Table; + +import java.util.List; + +/** + * @Author fr.open + * @Date 2020/8/18 + * @Description + **/ +@Entity +@Table(name = "plugin_sso_user") +public class UserEntity extends BaseEntity { + + @Column(name = "uid") + private String uid; + @Column(name = "sex") + private int sex; + @Column(name = "loginname") + private String loginname; + @Column(name = "mobilephone") + private String mobilephone; + @Column(name = "username") + private String username; + + public UserEntity() { + } + + public void setUid(String uid) { + this.uid = uid; + } + + public String getUid() { + return uid; + } + + public void setSex(int sex) { + this.sex = sex; + } + + public int getSex() { + return sex; + } + + public void setLoginname(String loginname) { + this.loginname = loginname; + } + + public String getLoginname() { + return loginname; + } + + public void setMobilephone(String mobilephone) { + this.mobilephone = mobilephone; + } + + public String getMobilephone() { + return mobilephone; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getUsername() { + return username; + } + +} diff --git a/src/main/java/com/fr/plugin/idm/sso/entity/UserOrgEntity.java b/src/main/java/com/fr/plugin/idm/sso/entity/UserOrgEntity.java new file mode 100644 index 0000000..f2f2bd1 --- /dev/null +++ b/src/main/java/com/fr/plugin/idm/sso/entity/UserOrgEntity.java @@ -0,0 +1,69 @@ +package com.fr.plugin.idm.sso.entity; + +import com.fr.stable.db.entity.BaseEntity; +import com.fr.third.javax.persistence.Column; +import com.fr.third.javax.persistence.Entity; +import com.fr.third.javax.persistence.Table; + +/** + * @Author fr.open + * @Date 2020/8/18 + * @Description + **/ +@Entity +@Table(name = "plugin_user_org") +public class UserOrgEntity extends BaseEntity { + @Column(name = "uid") + private String uid; + @Column(name = "positionids") + private String positionids; + @Column(name = "oid") + private String oid; + @Column(name = "orderby") + private int orderby; + @Column(name = "jobids") + private String jobids; + + public UserOrgEntity() { + } + + public void setUid(String uid) { + this.uid = uid; + } + + public String getUid() { + return uid; + } + + public void setPositionids(String positionids) { + this.positionids = positionids; + } + + public String getPositionids() { + return positionids; + } + + public void setOid(String oid) { + this.oid = oid; + } + + public String getOid() { + return oid; + } + + public void setOrderby(int orderby) { + this.orderby = orderby; + } + + public int getOrderby() { + return orderby; + } + + public void setJobids(String jobids) { + this.jobids = jobids; + } + + public String getJobids() { + return jobids; + } +} diff --git a/src/main/java/com/fr/plugin/idm/sso/util/CommonUtils.java b/src/main/java/com/fr/plugin/idm/sso/util/CommonUtils.java new file mode 100644 index 0000000..24517cf --- /dev/null +++ b/src/main/java/com/fr/plugin/idm/sso/util/CommonUtils.java @@ -0,0 +1,132 @@ +package com.fr.plugin.idm.sso.util; + +import com.fr.data.NetworkHelper; +import com.fr.decision.authority.data.User; +import com.fr.decision.mobile.terminal.TerminalHandler; +import com.fr.decision.webservice.utils.DecisionServiceConstants; +import com.fr.decision.webservice.utils.DecisionStatusService; +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.log.FineLoggerFactory; +import com.fr.stable.StringUtils; +import com.fr.stable.web.Device; +import com.fr.web.utils.WebUtils; + +import javax.servlet.FilterChain; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Map; +import java.util.Properties; + +/** + * @author fr.open + * @since 2021/8/27 + */ +public class CommonUtils { + + public static String getProperty(Properties props, String key, String defaultValue, boolean allowBlank) { + String value = props.getProperty(key); + if (StringUtils.isNotBlank(value)) { + return value; + } else { + if (allowBlank) { + FineLoggerFactory.getLogger().warn("Property[" + key + "] value is blank."); + return defaultValue; + } else { + throw new IllegalArgumentException("Property[" + key + "] cann't be blank."); + } + } + } + + public static String getProperty(Properties props, String key, boolean allowBlank) { + return getProperty(props, key, null, allowBlank); + } + + public static String getProperty(Properties props, String key) { + return getProperty(props, key, null, true); + } + + public static boolean isLogin(HttpServletRequest request) { + String oldToken = TokenResource.COOKIE.getToken(request); + return oldToken != null && checkTokenValid(request, (String) oldToken); + } + + private static boolean checkTokenValid(HttpServletRequest req, String token) { + try { + Device device = NetworkHelper.getDevice(req); + LoginService.getInstance().loginStatusValid(token, TerminalHandler.getTerminal(req, device)); + return true; + } catch (Exception ignore) { + } + return false; + } + + /** + * 跳转到过滤器链中的下一个过滤器 + * + * @param request + * @param response + * @param chain + */ + public static void next(HttpServletRequest request, HttpServletResponse response, FilterChain chain) { + try { + chain.doFilter(request, response); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void login(String username, HttpServletRequest request, HttpServletResponse response) { + try { + User user = UserService.getInstance().getUserByUserName(username); + if (user == null) { + throw new RuntimeException("系统未授权, 当前用户是\"" + username + "\""); + } + String token = LoginService.getInstance().login(request, response, username); + request.setAttribute(DecisionServiceConstants.FINE_AUTH_TOKEN_NAME, token); + } catch (Exception e) { + FineLoggerFactory.getLogger().error("sso >> Failed to login with[" + username + "]", e); + throw new RuntimeException("用户\"" + username +"\"登录失败"); + } + } + + public static boolean isMobileDevice(HttpServletRequest request) { + if (WebUtils.getDevice(request).isMobile()) { + FineLoggerFactory.getLogger().info("current request is is mobile request ,url is {}", request.getRequestURI()); + return true; + } + String requestHeader = request.getHeader("user-agent"); + String[] deviceArray = new String[]{"android", "iphone", "ipad", "ios", "windows phone", "wechat"}; + if (requestHeader == null) { + return false; + } + requestHeader = requestHeader.toLowerCase(); + for (int i = 0; i < deviceArray.length; i++) { + if (requestHeader.toLowerCase().contains(deviceArray[i])) { + FineLoggerFactory.getLogger().info("current request:{} is mobile request!", request.getRequestURI()); + return true; + } + } + String op = WebUtils.getHTTPRequestParameter(request, "op"); + return StringUtils.isNotBlank(op) && StringUtils.equals("h5",op); + } + + public static void cacheParams(String key, Map values) { + try { + DecisionStatusService.originUrlStatusService().put(key, values); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static String getCachedParam(String key, String name) { + try { + Map values = DecisionStatusService.originUrlStatusService().get(key); + return values.get(name); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/src/main/java/com/fr/plugin/idm/sso/util/HttpUtil.java b/src/main/java/com/fr/plugin/idm/sso/util/HttpUtil.java new file mode 100644 index 0000000..210138a --- /dev/null +++ b/src/main/java/com/fr/plugin/idm/sso/util/HttpUtil.java @@ -0,0 +1,246 @@ +package com.fr.plugin.idm.sso.util; + +import com.fr.json.JSONObject; +import com.fr.log.FineLoggerFactory; +import com.fr.stable.StringUtils; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSession; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author fr.open + * @date 2019/4/2 + */ +public class HttpUtil { + + private static HostnameVerifier hv = new HostnameVerifier() { + @Override + public boolean verify(String urlHostName, SSLSession session) { + System.out.println("Warning: URL Host: " + urlHostName + " vs. " + + session.getPeerHost()); + return true; + } + }; + + /** + * 发送get请求 + * + * @param url + * @param param + * @param header + * @return + * @throws IOException + */ + public static String sendGet(String url, Map param, Map header) { + String result = ""; + BufferedReader in = null; + String urlNameString = url; + try { + if (param != null) { + urlNameString += "?"; + urlNameString += param.entrySet() + .stream() + .map(entry -> entry.getKey() + "=" + entry.getValue()) + .collect(Collectors.joining("&")); + } + + URL realUrl = new URL(urlNameString); + // 打开和URL之间的连接 + HttpURLConnection connection; + if (url.startsWith("https")) { + trustAllHttpsCertificates(); + HttpsURLConnection.setDefaultHostnameVerifier(hv); + connection = (HttpURLConnection) realUrl.openConnection(); + } else { + connection = (HttpURLConnection) realUrl.openConnection(); + } + //设置超时时间 + connection.setDoInput(true); + connection.setRequestMethod("GET"); + connection.setConnectTimeout(5000); + connection.setReadTimeout(15000); + // 设置通用的请求属性 + if (header != null) { + Iterator> it = header.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = it.next(); + System.out.println(entry.getKey() + ":::" + entry.getValue()); + connection.setRequestProperty(entry.getKey(), entry.getValue()); + } + } + connection.setRequestProperty("accept", "*/*"); + connection.setRequestProperty("connection", "Keep-Alive"); + connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + // 建立实际的连接 + connection.connect(); + // 定义 BufferedReader输入流来读取URL的响应,设置utf8防止中文乱码 + in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8")); + String line; + while ((line = in.readLine()) != null) { + result += line; + } + if (in != null) { + in.close(); + } + }catch (Exception e){ + FineLoggerFactory.getLogger().error(e,"get url error ,url is:{},error is {}",urlNameString,e.getMessage()); + } + return result; + } + + public static String sendPost(String url,Map header, Map param) { + PrintWriter out = null; + BufferedReader in = null; + String result = StringUtils.EMPTY; + String res = StringUtils.EMPTY; + try { + String urlNameString = url; + /*if (param != null && !param.isEmpty()) { + urlNameString += "?"; + urlNameString += param.entrySet() + .stream() + .map(entry -> entry.getKey() + "=" + entry.getValue()) + .collect(Collectors.joining("&")); + }*/ + + URL realUrl = new URL(urlNameString); + // 打开和URL之间的连接 + HttpURLConnection conn; + if (url.startsWith("https")) { + trustAllHttpsCertificates(); + HttpsURLConnection.setDefaultHostnameVerifier(hv); + conn = (HttpURLConnection) realUrl.openConnection(); + } else { + conn = (HttpURLConnection) realUrl.openConnection(); + } + // 设置通用的请求属性 + conn.setRequestProperty("accept", "*/*"); + conn.setRequestProperty("connection", "Keep-Alive"); + conn.setRequestProperty("user-agent", + "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + //conn.setRequestProperty("Content-Type","application/json;;charset=UTF-8"); + conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=----footfoodapplicationrequestnetwork"); + if(header != null){ + header.forEach((k, v) -> { + conn.setRequestProperty(k, v); + }); + } + // 发送POST请求必须设置如下两行 + conn.setDoOutput(true); + conn.setDoInput(true); + //获取请求头 + + // 获取URLConnection对象对应的输出流 + out = new PrintWriter(conn.getOutputStream()); + StringBuffer buffer = new StringBuffer(); + param.forEach((k,v)->{ + buffer.append("------footfoodapplicationrequestnetwork\r\n"); + buffer.append("Content-Disposition: form-data; name=\""); + buffer.append(k); + buffer.append("\"\r\n\r\n"); + buffer.append(v); + buffer.append("\r\n"); + }); + buffer.append("------footfoodapplicationrequestnetwork--\r\n"); + out.print(buffer.toString()); + /*// 发送请求参数 + if(body != null){ + out.print(body.toString()); + }*/ + // flush输出流的缓冲 + out.flush(); + // 定义BufferedReader输入流来读取URL的响应 + in = new BufferedReader( + new InputStreamReader(conn.getInputStream())); + String line; + while ((line = in.readLine()) != null) { + result += line; + } + res = result; + } catch (Exception e) { + FineLoggerFactory.getLogger().error(e.getMessage(),e); + } + //使用finally块来关闭输出流、输入流 + finally{ + try{ + if(out!=null){ + out.close(); + } + if(in!=null){ + in.close(); + } + } + catch(IOException e){ + FineLoggerFactory.getLogger().error(e.getMessage(),e); + } + } + return res; + } + + private static void trustAllHttpsCertificates() throws Exception { + javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1]; + javax.net.ssl.TrustManager tm = new miTM(); + trustAllCerts[0] = tm; + javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext.getInstance("SSL","SunJSSE"); + sc.init(null, trustAllCerts, null); + HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); + } + + + /** + * encode url by UTF-8 + * @param url url before encoding + * @return url after encoding + */ + public static String encodeUrl(String url){ + String eurl = url; + try { + eurl = URLEncoder.encode(url,"UTF-8"); + } catch (UnsupportedEncodingException e) { + } + return eurl; + } + + private static class miTM implements javax.net.ssl.TrustManager, + javax.net.ssl.X509TrustManager { + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return null; + } + + public boolean isServerTrusted( + java.security.cert.X509Certificate[] certs) { + return true; + } + + public boolean isClientTrusted( + java.security.cert.X509Certificate[] certs) { + return true; + } + + @Override + public void checkServerTrusted( + java.security.cert.X509Certificate[] certs, String authType) + throws java.security.cert.CertificateException { + return; + } + + @Override + public void checkClientTrusted( + java.security.cert.X509Certificate[] certs, String authType) + throws java.security.cert.CertificateException { + return; + } + } +} diff --git a/src/main/resources/conf.properties b/src/main/resources/conf.properties new file mode 100644 index 0000000..dba9a45 --- /dev/null +++ b/src/main/resources/conf.properties @@ -0,0 +1,17 @@ +##\u8BF7\u6C42\u7528\u6237\u4FE1\u606F\u7684\u63A5\u53E3 +userinfourl= +##\u6821\u9A8Ctoken\u4FE1\u606F\u7684\u63A5\u53E3 +validationurl= +##\u670D\u52A1\u7F16\u53F7 +servicecode= +##\u670D\u52A1\u79D8\u94A5 +servicepwd= +# \u63A5\u53E3\u6240\u9700\u7684\u53C2\u6570\u503C +api.client_id=xxxx +api.client_secret=xxxx +# \u767B\u9646\u9875\u9762\u83B7\u53D6code\u5730\u5740 +api.authorize=https://xxxx/oauth2/authorize +# \u83B7\u53D6access_token\u63A5\u53E3 +api.get-token=https://xxxx/oauth2/token +# \u83B7\u53D6\u7528\u6237\u4FE1\u606F\u63A5\u53E3 +api.get-user=https://xxxx/oauth2/get_user_info \ No newline at end of file