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.*; 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; import com.epmet.redis.SsoRedis; import com.epmet.service.SsoService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; 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 * @DateTime 2021/1/18 下午4:35 */ @Service @Slf4j public class SsoServiceImpl implements SsoService { Logger logger = LoggerFactory.getLogger(getClass()); @Autowired private SsoRedis ssoRedis; @Autowired private JwtTokenUtils jwtTokenUtils; @Autowired private JwtTokenProperties jwtTokenProperties; @Autowired private EpmetUserOpenFeignClient epmetUserOpenFeignClient; @Autowired private OperCrmOpenFeignClient operCrmOpenFeignClient; @Autowired private GovOrgOpenFeignClient govOrgOpenFeignClient; @Autowired private CpUserDetailRedis cpUserDetailRedis; /** * @Description 0、入口:得到token * @Param formDTO * @author zxc * @date 2021/1/18 下午4:59 */ @Override public SsoLoginResultDTO ssoLogin(SsoLoginFormDTO formDTO) { String customerId = getCustomerId(formDTO.getAppId()); //String customerId = "3a4f923665a7a07701bcb311aac9a156"; String userId = ""; 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.getCUserInfoByTicket(formDTO.getTicket()); } catch (Exception e) { throw new RenException(e.getMessage()); } if (null == userInfo){ throw new RenException(EpmetErrorCode.THIRD_PLAT_REQUEST_ERROR.getCode(), "【SSO登录】调用第三方平台查询用户信息失败,用户信息为空"); } UserInfoFormDTO userInfoFormDTO = new UserInfoFormDTO(); userInfoFormDTO.setApp(formDTO.getApp()); userInfoFormDTO.setUid(userInfo.getOpenId()); userInfoFormDTO.setName(userInfo.getName()); userInfoFormDTO.setMobile(userInfo.getMobile()); Result userDTOResult = epmetUserOpenFeignClient.saveUserInfo(userInfoFormDTO); if (!userDTOResult.success()){ throw new RenException("【SSO登录】新增或更新user_weChat失败"); } userId = userDTOResult.getData().getId(); if (StringUtils.isBlank(userId)){ throw new RenException("【SSO登录】userId为空,生成token失败"); } //生成业务token String token = this.generateToken(formDTO.getApp(),formDTO.getClient(), userId); //存放Redis if (StringUtils.isBlank(customerId)){ throw new RenException("【SSO登录】customerId为空,缓存放置token失败"); } this.disposeTokenDto(formDTO, userId, token, customerId); return new SsoLoginResultDTO(token); } /** * @Description token放缓存 * @Param formDTO * @Param userId * @Param token * @Param customerId * @author zxc * @date 2021/1/18 下午5:32 */ public void disposeTokenDto(SsoLoginFormDTO formDTO, String userId, String token, String customerId){ int expire = jwtTokenProperties.getExpire(); TokenDto tokenDto = new TokenDto(); tokenDto.setCustomerId(customerId); tokenDto.setApp(formDTO.getApp()); tokenDto.setClient(formDTO.getClient()); tokenDto.setUserId(userId); tokenDto.setToken(token); tokenDto.setUpdateTime(System.currentTimeMillis()); tokenDto.setExpireTime(jwtTokenUtils.getExpiration(token).getTime()); ssoRedis.set(tokenDto, expire); log.info("截止时间:" + DateUtils.format(jwtTokenUtils.getExpiration(token), "yyyy-MM-dd HH:mm:ss")); } /** * @Description 居民端登陆生成业务token的key * @Param app * @Param client * @Param userId * @author zxc * @date 2021/1/18 下午5:14 */ private String generateToken(String app,String client, String userId) { Map map = new HashMap<>(16); map.put("app", app); map.put("client", client); map.put("userId", userId); String token = jwtTokenUtils.createToken(map); log.info("app:" + app + ";client:" + client + ";userId:" + userId + ";生成token[" + token + "]"); return token; } /** * @Description 获取customerId * @Param appId * @author zxc * @date 2021/1/19 下午1:47 */ public String getCustomerId(String appId){ JSONObject jsonObject = new JSONObject(); String customerMsgUrl = "https://epmet-cloud.elinkservice.cn/api/third/customermp/getcustomermsg/"; String data = HttpClientManager.getInstance().sendPostByJSON(customerMsgUrl + appId, JSON.toJSONString(jsonObject)).getData(); log.info("调用third服务,根据appId查询客户信息:httpclient->url:" + customerMsgUrl + ",结果->" + data); JSONObject toResult = JSON.parseObject(data); Result mapToResult = ConvertUtils.mapToEntity(toResult, Result.class); if (null != toResult.get("code")) { mapToResult.setCode(((Integer) toResult.get("code")).intValue()); } if (!mapToResult.success()) { log.error(String.format("根据appId查询客户信息失败,对应appId->" + appId)); throw new RenException(mapToResult.getMsg()); } Object publicCustomerResultDTO = mapToResult.getData(); JSONObject json = JSON.parseObject(publicCustomerResultDTO.toString()); Map map = (Map) json.get("customer"); PaCustomerDTO customer = ConvertUtils.mapToEntity(map, PaCustomerDTO.class); log.info("小程序登陆third服务获取客户用户信息PaCustomerDTO->" + customer); return customer.getId(); } /** * @param formDTO * @Author sun * @Description 1、ticket自动登录获取内部token **/ @Override public UserTokenResultDTO ssoWorkLogin(SsoWorkLoginFormDTO formDTO) { //1.根据appId查询客户id String customerId = getCustomerId(formDTO.getAppId()); //String customerId = "3a4f923665a7a07701bcb311aac9a156"; //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.getGUserInfoBySSOToken(formDTO.getToken()); } 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.getGUserInfoBySSOToken(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; } }