From 2aff053d0e39413add1138956bf3efc4dc0f8e91 Mon Sep 17 00:00:00 2001 From: sunyuchao Date: Tue, 23 Feb 2021 15:16:12 +0800 Subject: [PATCH] =?UTF-8?q?=E9=85=92=E5=9F=8EH5=E5=B7=A5=E4=BD=9C=E7=AB=AF?= =?UTF-8?q?=E7=99=BB=E9=99=86=E4=B8=A4=E4=B8=AA=E8=8E=B7=E5=8F=96token?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/epmet/controller/SsoController.java | 25 ++ .../com/epmet/dto/form/SsoEnteOrgFormDTO.java | 53 ++++ .../com/epmet/dto/form/SsoLoginFormDTO.java | 5 +- .../java/com/epmet/service/SsoService.java | 15 + .../epmet/service/impl/SsoServiceImpl.java | 298 +++++++++++++++++- .../common/token/constant/LoginConstant.java | 5 + 6 files changed, 393 insertions(+), 8 deletions(-) create mode 100644 epmet-auth/src/main/java/com/epmet/dto/form/SsoEnteOrgFormDTO.java diff --git a/epmet-auth/src/main/java/com/epmet/controller/SsoController.java b/epmet-auth/src/main/java/com/epmet/controller/SsoController.java index 6d17e1a9a0..86fc44aa18 100644 --- a/epmet-auth/src/main/java/com/epmet/controller/SsoController.java +++ b/epmet-auth/src/main/java/com/epmet/controller/SsoController.java @@ -4,8 +4,10 @@ import com.epmet.commons.thirdplat.apiservice.jcet.JcetApiService; import com.epmet.commons.thirdplat.bean.ThirdPlatUserInfo; import com.epmet.commons.tools.utils.Result; import com.epmet.commons.tools.validator.ValidatorUtils; +import com.epmet.dto.form.SsoEnteOrgFormDTO; import com.epmet.dto.form.SsoLoginFormDTO; import com.epmet.dto.result.SsoLoginResultDTO; +import com.epmet.dto.result.UserTokenResultDTO; import com.epmet.service.SsoService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; @@ -50,4 +52,27 @@ public class SsoController { return new Result().ok(userInfoByTicket); } + /** + * @param formDTO + * @Author sun + * @Description 1、ticket自动登录获取内部token + **/ + @PostMapping("work/login") + public Result ssoWorkLogin(@RequestBody SsoLoginFormDTO formDTO){ + ValidatorUtils.validateEntity(formDTO, SsoLoginFormDTO.SsoLoginForm.class); + return new Result().ok(ssoService.ssoWorkLogin(formDTO)); + } + + /** + * @param formDTO + * @Author sun + * @Description 4、自动进入组织-返回token + **/ + @PostMapping(value = "work/enterorg") + public Result enterOrg(@RequestBody SsoEnteOrgFormDTO formDTO) { + ValidatorUtils.validateEntity(formDTO, SsoEnteOrgFormDTO.AddUserShowGroup.class, SsoEnteOrgFormDTO.AddUserInternalGroup.class); + UserTokenResultDTO userTokenResultDTO = ssoService.enterOrg(formDTO); + return new Result().ok(userTokenResultDTO); + } + } diff --git a/epmet-auth/src/main/java/com/epmet/dto/form/SsoEnteOrgFormDTO.java b/epmet-auth/src/main/java/com/epmet/dto/form/SsoEnteOrgFormDTO.java new file mode 100644 index 0000000000..4706061267 --- /dev/null +++ b/epmet-auth/src/main/java/com/epmet/dto/form/SsoEnteOrgFormDTO.java @@ -0,0 +1,53 @@ +package com.epmet.dto.form; + +import com.epmet.commons.tools.validator.group.CustomerClientShowGroup; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +/** + * @Description 4、自动进入组织-返回token + * @Author sun + */ +@Data +public class SsoEnteOrgFormDTO implements Serializable { + public interface AddUserInternalGroup {} + public interface AddUserShowGroup extends CustomerClientShowGroup {} + /** + * wxCode + */ + @NotBlank(message = "ticket不能为空",groups = {AddUserInternalGroup.class}) + private String ticket; + + /** + * 手机号 + */ + @NotBlank(message = "手机号不能为空",groups = {AddUserShowGroup.class}) + private String mobile; + + /** + * 选择的组织所属的id + */ + @NotBlank(message = "客户id不能为空",groups = {AddUserInternalGroup.class}) + private String customerId; + + /** + * 选择的要进入的组织(根组织id) + */ + @NotBlank(message = "组织id不能为空",groups = {AddUserInternalGroup.class}) + private String rootAgencyId; + + /** + * resi;居民段,gov:工作端 + */ + @NotBlank(message = "app不能为空",groups = SsoLoginFormDTO.SsoLoginForm.class) + private String app; + + /** + * app;居民段,app:工作端 + */ + @NotBlank(message = "client不能为空",groups = SsoLoginFormDTO.SsoLoginForm.class) + private String client; +} + diff --git a/epmet-auth/src/main/java/com/epmet/dto/form/SsoLoginFormDTO.java b/epmet-auth/src/main/java/com/epmet/dto/form/SsoLoginFormDTO.java index b50818d3cc..eea5394ed5 100644 --- a/epmet-auth/src/main/java/com/epmet/dto/form/SsoLoginFormDTO.java +++ b/epmet-auth/src/main/java/com/epmet/dto/form/SsoLoginFormDTO.java @@ -29,11 +29,14 @@ public class SsoLoginFormDTO implements Serializable { private String appId; /** - * app类型 resi;居民段,work:工作端 + * app类型 resi;居民段,gov:工作端 */ @NotBlank(message = "app不能为空",groups = SsoLoginForm.class) private String app; + /** + * app;居民段,app:工作端 + */ @NotBlank(message = "client不能为空",groups = SsoLoginForm.class) private String client; } diff --git a/epmet-auth/src/main/java/com/epmet/service/SsoService.java b/epmet-auth/src/main/java/com/epmet/service/SsoService.java index 3cbd2b9af2..a2986482ab 100644 --- a/epmet-auth/src/main/java/com/epmet/service/SsoService.java +++ b/epmet-auth/src/main/java/com/epmet/service/SsoService.java @@ -1,7 +1,9 @@ package com.epmet.service; +import com.epmet.dto.form.SsoEnteOrgFormDTO; import com.epmet.dto.form.SsoLoginFormDTO; import com.epmet.dto.result.SsoLoginResultDTO; +import com.epmet.dto.result.UserTokenResultDTO; /** * @Author zxc @@ -17,4 +19,17 @@ public interface SsoService { */ SsoLoginResultDTO ssoLogin(SsoLoginFormDTO formDTO); + /** + * @param formDTO + * @Author sun + * @Description 1、ticket自动登录获取内部token + **/ + UserTokenResultDTO ssoWorkLogin(SsoLoginFormDTO formDTO); + + /** + * @param formDTO + * @Author sun + * @Description 4、自动进入组织-返回token + **/ + UserTokenResultDTO enterOrg(SsoEnteOrgFormDTO formDTO); } diff --git a/epmet-auth/src/main/java/com/epmet/service/impl/SsoServiceImpl.java b/epmet-auth/src/main/java/com/epmet/service/impl/SsoServiceImpl.java index ede5acd988..67d00ea4e6 100644 --- a/epmet-auth/src/main/java/com/epmet/service/impl/SsoServiceImpl.java +++ b/epmet-auth/src/main/java/com/epmet/service/impl/SsoServiceImpl.java @@ -2,20 +2,20 @@ package com.epmet.service.impl; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; +import com.epmet.common.token.constant.LoginConstant; import com.epmet.commons.thirdplat.apiservice.AbstractApiService; import com.epmet.commons.thirdplat.bean.ThirdPlatUserInfo; import com.epmet.commons.tools.exception.EpmetErrorCode; +import com.epmet.commons.tools.exception.ExceptionUtils; import com.epmet.commons.tools.exception.RenException; +import com.epmet.commons.tools.security.dto.GovTokenDto; import com.epmet.commons.tools.security.dto.TokenDto; import com.epmet.commons.tools.utils.*; -import com.epmet.dto.PaCustomerDTO; -import com.epmet.dto.UserDTO; -import com.epmet.dto.form.ApiServiceFormDTO; -import com.epmet.dto.form.SsoLoginFormDTO; -import com.epmet.dto.form.UserInfoFormDTO; -import com.epmet.dto.result.SsoLoginResultDTO; -import com.epmet.dto.result.ThirdplatApiserviceResultDTO; +import com.epmet.dto.*; +import com.epmet.dto.form.*; +import com.epmet.dto.result.*; import com.epmet.feign.EpmetUserOpenFeignClient; +import com.epmet.feign.GovOrgOpenFeignClient; import com.epmet.feign.OperCrmOpenFeignClient; import com.epmet.jwt.JwtTokenProperties; import com.epmet.jwt.JwtTokenUtils; @@ -27,9 +27,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; /** * @Author zxc @@ -56,6 +60,12 @@ public class SsoServiceImpl implements SsoService { @Autowired private OperCrmOpenFeignClient operCrmOpenFeignClient; + @Autowired + private GovOrgOpenFeignClient govOrgOpenFeignClient; + + @Autowired + private CpUserDetailRedis cpUserDetailRedis; + /** * @Description 0、入口:得到token * @Param formDTO @@ -182,4 +192,278 @@ public class SsoServiceImpl implements SsoService { log.info("小程序登陆third服务获取客户用户信息PaCustomerDTO->" + customer); return customer.getId(); } + + /** + * @param formDTO + * @Author sun + * @Description 1、ticket自动登录获取内部token + **/ + @Override + public UserTokenResultDTO ssoWorkLogin(SsoLoginFormDTO formDTO) { + + //1.根据appId查询客户id + String customerId = getCustomerId(formDTO.getAppId()); + + //2.客户Id换取第三方apiService,根据ticket换取华为Id + Result apiServiceResult = operCrmOpenFeignClient.getApiServiceByCustomerId(new ApiServiceFormDTO(customerId)); + if (!apiServiceResult.success()) { + throw new RenException("【SSO登录】调用OperCrm获取ApiService接口失败:", apiServiceResult.getInternalMsg()); + } + if (apiServiceResult.getData() == null || StringUtils.isBlank(apiServiceResult.getData().getApiServiceName())) { + throw new RenException("【SSO登录】调用OperCrm获取ApiService,查询到的结果为空:", apiServiceResult.toString()); + } + ThirdPlatUserInfo userInfo; + try { + AbstractApiService apiService = (AbstractApiService) SpringContextUtils.getBean(apiServiceResult.getData().getApiServiceName()); + userInfo = apiService.getUserInfoByTicket(formDTO.getTicket()); + } catch (Exception e) { + throw new RenException(e.getMessage()); + } + if (null == userInfo){ + throw new RenException(EpmetErrorCode.THIRD_PLAT_REQUEST_ERROR.getCode(), + "【SSO登录】调用第三方平台查询用户信息失败,用户信息为空"); + } + + //3.根据华为openId查询用户是否存在历史登陆信息 + Result latestStaffWechat = epmetUserOpenFeignClient.getLatestStaffWechatLoginRecord(userInfo.getOpenId()); + if (!latestStaffWechat.success() || null == latestStaffWechat.getData()) { + logger.error(String.format("没有获取到用户最近一次登录账户信息,code[%s],msg[%s]", EpmetErrorCode.PLEASE_LOGIN.getCode(), EpmetErrorCode.PLEASE_LOGIN.getMsg())); + throw new RenException(EpmetErrorCode.PLEASE_LOGIN.getCode()); + } + StaffLatestAgencyResultDTO staffLatestAgencyResultDTO = latestStaffWechat.getData(); + + //4.记录staff_wechat + this.savestaffwechat(staffLatestAgencyResultDTO.getStaffId(), userInfo.getOpenId()); + + //5.记录登录日志 + this.saveStaffLoginRecord(staffLatestAgencyResultDTO); + + //6.获取用户token + String token = this.generateGovWxmpToken(staffLatestAgencyResultDTO.getStaffId(), formDTO.getApp(), formDTO.getClient()); + + //7.保存到redis + this.saveLatestGovTokenDto(staffLatestAgencyResultDTO, userInfo, token); + UserTokenResultDTO userTokenResultDTO = new UserTokenResultDTO(); + userTokenResultDTO.setToken(token); + + return userTokenResultDTO; + + } + + /** + * @param userId openid + * @Author sun + * @Description 保存微信和当前登录用户关系 + **/ + private Result savestaffwechat(String userId, String openid) { + StaffWechatFormDTO staffWechatFormDTO = new StaffWechatFormDTO(); + staffWechatFormDTO.setUserId(userId); + staffWechatFormDTO.setWxOpenId(openid); + return epmetUserOpenFeignClient.saveStaffWechat(staffWechatFormDTO); + } + /** + * @param latestStaffWechatLoginDTO + * @Author sun + * @Description 保存登录日志 + **/ + private Result saveStaffLoginRecord(StaffLatestAgencyResultDTO latestStaffWechatLoginDTO) { + StaffLoginAgencyRecordFormDTO staffLoginAgencyRecordFormDTO = new StaffLoginAgencyRecordFormDTO(); + staffLoginAgencyRecordFormDTO.setCustomerId(latestStaffWechatLoginDTO.getCustomerId()); + staffLoginAgencyRecordFormDTO.setStaffId(latestStaffWechatLoginDTO.getStaffId()); + staffLoginAgencyRecordFormDTO.setWxOpenId(latestStaffWechatLoginDTO.getWxOpenId()); + staffLoginAgencyRecordFormDTO.setMobile(latestStaffWechatLoginDTO.getMobile()); + staffLoginAgencyRecordFormDTO.setAgencyId(latestStaffWechatLoginDTO.getAgencyId()); + Result staffLoginRecordResult = epmetUserOpenFeignClient.saveStaffLoginRecord(staffLoginAgencyRecordFormDTO); + return staffLoginRecordResult; + } + /** + * @Description 生成政府端小程序业务token Key + * @Author sun + **/ + private String generateGovWxmpToken(String staffId, String app, String client) { + Map map = new HashMap<>(); + map.put("app", app); + map.put("client", client); + map.put("userId", staffId); + String token = jwtTokenUtils.createToken(map); + logger.info("app:" + app + ";client:" + client + ";userId:" + staffId + ";生成token[" + token + "]"); + return token; + } + /** + * @Description 保存tokenDto到redis + * @Author sun + **/ + private void saveLatestGovTokenDto(StaffLatestAgencyResultDTO staffLatestAgency, ThirdPlatUserInfo userInfo, String token) { + int expire = jwtTokenProperties.getExpire(); + GovTokenDto govTokenDto = new GovTokenDto(); + govTokenDto.setApp(LoginConstant.APP_GOV); + govTokenDto.setClient(LoginConstant.CLIENT_WXMP); + govTokenDto.setUserId(staffLatestAgency.getStaffId()); + govTokenDto.setOpenId(userInfo.getOpenId()); + govTokenDto.setSessionKey(""); + govTokenDto.setUnionId(""); + govTokenDto.setToken(token); + govTokenDto.setUpdateTime(System.currentTimeMillis()); + govTokenDto.setExpireTime(jwtTokenUtils.getExpiration(token).getTime()); + govTokenDto.setRootAgencyId(staffLatestAgency.getAgencyId()); + govTokenDto.setCustomerId(staffLatestAgency.getCustomerId()); + + //设置部门,网格,角色列表 + govTokenDto.setDeptIdList(getDeptartmentIdList(staffLatestAgency.getStaffId())); + govTokenDto.setGridIdList(getGridIdList(staffLatestAgency.getStaffId())); + CustomerAgencyDTO agency = getAgencyByStaffId(staffLatestAgency.getStaffId()); + if (agency != null) { + govTokenDto.setAgencyId(agency.getId()); + govTokenDto.setRoleList(queryGovStaffRoles(staffLatestAgency.getStaffId(), agency.getId())); + } + govTokenDto.setOrgIdPath(getOrgIdPath(staffLatestAgency.getStaffId())); + + cpUserDetailRedis.set(govTokenDto, expire); + logger.info("截止时间:" + DateUtils.format(jwtTokenUtils.getExpiration(token), "yyyy-MM-dd HH:mm:ss")); + } + public Set getDeptartmentIdList(String staffId) { + try { + Result> deptListResult = govOrgOpenFeignClient.getDepartmentListByStaffId(staffId); + if (deptListResult.success()) { + if (!CollectionUtils.isEmpty(deptListResult.getData())) { + Set deptIdLists = deptListResult.getData().stream().map(dept -> dept.getDepartmentId()).collect(Collectors.toSet()); + return deptIdLists; + } + } else { + logger.error("登录:查询部门列表,远程调用返回错误:{}", deptListResult.getMsg()); + } + } catch (Exception e) { + String errorStackTrace = ExceptionUtils.getErrorStackTrace(e); + logger.error("登录:查询部门列表异常:{}", errorStackTrace); + } + return null; + } + /** + * 根据工作人员ID查询网格ID列表 + * @param staffId + */ + public Set getGridIdList(String staffId) { + Result> result = govOrgOpenFeignClient.listGridsbystaffid(staffId); + if (!result.success()) { + logger.error("登录:查询网格列表,远程调用返回错误:{}", result.getMsg()); + return null; + } else { + List grids = result.getData(); + return grids.stream().map(grid -> grid.getGridId()).collect(Collectors.toSet()); + } + } + /** + * 根据staffId查询所属的组织机构 + * + * @param staffId + */ + public CustomerAgencyDTO getAgencyByStaffId(String staffId) { + Result result = govOrgOpenFeignClient.getAgencyByStaff(staffId); + if (!result.success()) { + logger.error("登录:查询登录人所属的机关OrgIdPath失败:{}", result.getMsg()); + return null; + } + return result.getData(); + } + /** + * 查询人员在某机关单位下的角色列表 + * @param staffId orgId + */ + public List queryGovStaffRoles(String staffId, String orgId) { + StaffRoleFormDTO formDTO = new StaffRoleFormDTO(); + formDTO.setStaffId(staffId); + formDTO.setOrgId(orgId); + Result> gridResult = epmetUserOpenFeignClient.getRolesOfStaff(formDTO); + if (!CollectionUtils.isEmpty(gridResult.getData())) { + //return gridResult.getData().stream().map(role -> role.getId()).collect(Collectors.toSet()); + return ConvertUtils.sourceToTarget(gridResult.getData(), GovTokenDto.Role.class); + } + return null; + } + /** + * 查询工作人员的OrgIdPath + * @param staffId + */ + public String getOrgIdPath(String staffId) { + Result result = govOrgOpenFeignClient.getAgencyByStaff(staffId); + if (!result.success()) { + logger.error("登录:查询登录人所属的机关OrgIdPath失败:{}", result.getMsg()); + return null; + } + CustomerAgencyDTO agency = result.getData(); + if (agency != null) { + if ("0".equals(agency.getPid())) { + // 顶级 + return agency.getId(); + } else { + return agency.getPids().concat(":").concat(agency.getId()); + } + } + return null; + } + + /** + * @param formDTO + * @Author sun + * @Description 4、自动进入组织-返回token + **/ + @Override + public UserTokenResultDTO enterOrg(SsoEnteOrgFormDTO formDTO) { + //1、需要校验要登录的客户,是否被禁用 + CustomerStaffFormDTO customerStaffFormDTO = new CustomerStaffFormDTO(); + customerStaffFormDTO.setCustomerId(formDTO.getCustomerId()); + customerStaffFormDTO.setMobile(formDTO.getMobile()); + Result customerStaffDTOResult = epmetUserOpenFeignClient.getCustomerStaffInfo(customerStaffFormDTO); + if (!customerStaffDTOResult.success() || null == customerStaffDTOResult.getData()) { + logger.error(String.format("获取工作人员信息失败,手机号[%s],客户id:[%s],code[%s],msg[%s]", formDTO.getMobile(), formDTO.getCustomerId(), customerStaffDTOResult.getCode(), customerStaffDTOResult.getMsg())); + throw new RenException(customerStaffDTOResult.getCode()); + } + CustomerStaffDTO customerStaff = customerStaffDTOResult.getData(); + + //2.客户Id换取第三方apiService,根据ticket换取华为Id + Result apiServiceResult = operCrmOpenFeignClient.getApiServiceByCustomerId(new ApiServiceFormDTO(formDTO.getCustomerId())); + if (!apiServiceResult.success()) { + throw new RenException("【SSO登录】调用OperCrm获取ApiService接口失败:", apiServiceResult.getInternalMsg()); + } + if (apiServiceResult.getData() == null || StringUtils.isBlank(apiServiceResult.getData().getApiServiceName())) { + throw new RenException("【SSO登录】调用OperCrm获取ApiService,查询到的结果为空:", apiServiceResult.toString()); + } + ThirdPlatUserInfo userInfo; + try { + AbstractApiService apiService = (AbstractApiService) SpringContextUtils.getBean(apiServiceResult.getData().getApiServiceName()); + userInfo = apiService.getUserInfoByTicket(formDTO.getTicket()); + } catch (Exception e) { + throw new RenException(e.getMessage()); + } + if (null == userInfo){ + throw new RenException(EpmetErrorCode.THIRD_PLAT_REQUEST_ERROR.getCode(), + "【SSO登录】调用第三方平台查询用户信息失败,用户信息为空"); + } + + //3、记录staff_wechat,并记录用户激活状态,激活时间 + this.savestaffwechat(customerStaff.getUserId(), userInfo.getOpenId()); + + //4、记录登录日志 + StaffLatestAgencyResultDTO staffLatestAgencyResultDTO = new StaffLatestAgencyResultDTO(); + staffLatestAgencyResultDTO.setCustomerId(formDTO.getCustomerId()); + staffLatestAgencyResultDTO.setStaffId(customerStaff.getUserId()); + staffLatestAgencyResultDTO.setWxOpenId(userInfo.getOpenId()); + staffLatestAgencyResultDTO.setMobile(formDTO.getMobile()); + staffLatestAgencyResultDTO.setAgencyId(formDTO.getRootAgencyId()); + this.saveStaffLoginRecord(staffLatestAgencyResultDTO); + + //5.1、获取用户token + String token = this.generateGovWxmpToken(customerStaff.getUserId(), formDTO.getApp(), formDTO.getClient()); + //5.2、保存到redis + StaffLatestAgencyResultDTO staffLatestAgency = new StaffLatestAgencyResultDTO(); + staffLatestAgency.setAgencyId(formDTO.getRootAgencyId()); + staffLatestAgency.setCustomerId(formDTO.getCustomerId()); + staffLatestAgency.setStaffId(customerStaff.getUserId()); + this.saveLatestGovTokenDto(staffLatestAgency, userInfo, token); + + UserTokenResultDTO userTokenResultDTO = new UserTokenResultDTO(); + userTokenResultDTO.setToken(token); + return userTokenResultDTO; + } + } diff --git a/epmet-commons/epmet-common-clienttoken/src/main/java/com/epmet/common/token/constant/LoginConstant.java b/epmet-commons/epmet-common-clienttoken/src/main/java/com/epmet/common/token/constant/LoginConstant.java index 17cb456a1a..c10e346e9c 100644 --- a/epmet-commons/epmet-common-clienttoken/src/main/java/com/epmet/common/token/constant/LoginConstant.java +++ b/epmet-commons/epmet-common-clienttoken/src/main/java/com/epmet/common/token/constant/LoginConstant.java @@ -40,4 +40,9 @@ public interface LoginConstant { * E事通服务号 */ String CLIENT_MP = "mp"; + + /** + * 手机App + */ + String CLIENT_APP = "app"; }