package com.epmet.service.impl; import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; import com.epmet.common.token.constant.LoginConstant; import com.epmet.commons.tools.constant.AppClientConstant; import com.epmet.commons.tools.constant.ServiceConstant; 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.feign.ResultDataResolver; import com.epmet.commons.tools.security.dto.GovTokenDto; import com.epmet.commons.tools.security.dto.TokenDto; import com.epmet.commons.tools.security.password.PasswordUtils; import com.epmet.commons.tools.utils.ConvertUtils; import com.epmet.commons.tools.utils.CpUserDetailRedis; import com.epmet.commons.tools.utils.DateUtils; import com.epmet.commons.tools.utils.Result; import com.epmet.commons.tools.validator.PhoneValidatorUtils; import com.epmet.constant.SmsTemplateConstant; import com.epmet.dto.CustomerAgencyDTO; import com.epmet.dto.CustomerStaffDTO; import com.epmet.dto.GovStaffRoleDTO; import com.epmet.dto.form.*; import com.epmet.dto.result.*; import com.epmet.feign.EpmetMessageOpenFeignClient; import com.epmet.feign.EpmetUserFeignClient; import com.epmet.feign.EpmetUserOpenFeignClient; import com.epmet.feign.GovOrgFeignClient; import com.epmet.jwt.JwtTokenProperties; import com.epmet.jwt.JwtTokenUtils; import com.epmet.redis.CaptchaRedis; import com.epmet.service.GovLoginService; import com.epmet.service.LoginService; 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.*; import java.util.stream.Collectors; /** * @Description 政府端登录服务 * @Author yinzuomei * @Date 2020/4/20 10:56 */ @Service public class GovLoginServiceImpl implements GovLoginService, ResultDataResolver { private static final Logger logger = LoggerFactory.getLogger(GovLoginServiceImpl.class); private static final String SEND_SMS_CODE_ERROR = "发送短信验证码异常,手机号[%s],code[%s],msg[%s]"; @Autowired private LoginService loginService; @Autowired private EpmetUserFeignClient epmetUserFeignClient; @Autowired private CaptchaRedis captchaRedis; @Autowired private JwtTokenUtils jwtTokenUtils; @Autowired private JwtTokenProperties jwtTokenProperties; @Autowired private CpUserDetailRedis cpUserDetailRedis; @Autowired private GovOrgFeignClient govOrgFeignClient; @Autowired private EpmetMessageOpenFeignClient epmetMessageOpenFeignClient; @Autowired private EpmetUserOpenFeignClient userOpenFeignClient; /** * @param formDTO * @return com.epmet.commons.tools.utils.Result * @Author yinzuomei * @Description 政府端微信小程序登录-发送验证码 * @Date 2020/4/18 10:59 **/ @Override public void sendSmsCode(SendSmsCodeFormDTO formDTO) { //1、校验手机号是否符合规范 if (!PhoneValidatorUtils.isMobile(formDTO.getMobile())) { logger.warn(String.format(SEND_SMS_CODE_ERROR, formDTO.getMobile(), EpmetErrorCode.ERROR_PHONE.getCode(), EpmetErrorCode.ERROR_PHONE.getMsg())); throw new RenException(EpmetErrorCode.ERROR_PHONE.getCode()); } //2、根据手机号校验用户是否存在 Result> customerStaffResult = epmetUserFeignClient.checkCustomerStaff(formDTO.getMobile()); if (!customerStaffResult.success()) { logger.warn(String.format(SEND_SMS_CODE_ERROR, formDTO.getMobile(), customerStaffResult.getCode(), customerStaffResult.getMsg())); throw new RenException(customerStaffResult.getCode()); } //3、发送短信验证码 SendVerificationCodeFormDTO sendVerificationCodeFormDTO=new SendVerificationCodeFormDTO(); sendVerificationCodeFormDTO.setMobile(formDTO.getMobile()); sendVerificationCodeFormDTO.setAliyunTemplateCode(SmsTemplateConstant.LGOIN_CONFIRM); Result smsCodeResult=epmetMessageOpenFeignClient.sendVerificationCode(sendVerificationCodeFormDTO); if (!smsCodeResult.success()) { logger.warn(String.format(SEND_SMS_CODE_ERROR, formDTO.getMobile(), smsCodeResult.getCode(), smsCodeResult.getMsg())); throw new RenException(smsCodeResult.getCode()); } //4、保存短信验证码(删除现有短信验证码、将新的短信验证码存入Redis) captchaRedis.saveSmsCode(formDTO, smsCodeResult.getData().getCode()); logger.info(String.format("发送短信验证码成功,手机号[%s]", formDTO.getMobile())); } /** * @param formDTO * @return com.epmet.commons.tools.utils.Result * @Author yinzuomei * @Description 3、手机验证码获取组织 * @Date 2020/4/18 21:11 **/ @Override public List getMyOrg(StaffOrgsFormDTO formDTO) { //1、根据手机号查询到用户信息 Result> customerStaffResult = epmetUserFeignClient.checkCustomerStaff(formDTO.getMobile()); if (!customerStaffResult.success()) { logger.warn(String.format("手机验证码登录异常,手机号[%s],code[%s],msg[%s]", formDTO.getMobile(), customerStaffResult.getCode(), customerStaffResult.getMsg())); throw new RenException(customerStaffResult.getCode()); } //2、验证码是否正确 String rightSmsCode = captchaRedis.getSmsCode(formDTO.getMobile()); if (!formDTO.getSmsCode().equals(rightSmsCode)) { logger.warn(String.format("验证码错误code[%s],msg[%s]",EpmetErrorCode.MOBILE_CODE_ERROR.getCode(),EpmetErrorCode.MOBILE_CODE_ERROR.getMsg())); throw new RenException(EpmetErrorCode.MOBILE_CODE_ERROR.getCode()); } //3、查询用户所有的组织信息 List customerIdList = new ArrayList<>(); for (CustomerStaffDTO customerStaffDTO : customerStaffResult.getData()) { customerIdList.add(customerStaffDTO.getCustomerId()); } StaffOrgFormDTO staffOrgFormDTO = new StaffOrgFormDTO(); staffOrgFormDTO.setCustomerIdList(customerIdList); Result> result = govOrgFeignClient.getStaffOrgList(staffOrgFormDTO); if(result.success()&&null!=result.getData()){ return result.getData(); } logger.warn(String .format("手机验证码获取组织,调用%s服务失败,入参手机号%s,验证码%s,返回错误码%s,错误提示信息%s", ServiceConstant.GOV_ORG_SERVER,formDTO.getMobile(),formDTO.getSmsCode(),result.getCode(),result.getMsg())); return new ArrayList<>(); } @Override public UserTokenResultDTO loginByWxCode(GovWxmpFormDTO formDTO) { //1、解析微信用户 WxMaJscode2SessionResult wxMaJscode2SessionResult = loginService.getWxMaUser(formDTO.getApp(), formDTO.getWxCode(), formDTO.getAppId()); if(null!=wxMaJscode2SessionResult){ logger.info(String.format("app=%s,wxCode=%s,openId=%s",formDTO.getApp(),formDTO.getWxCode(),wxMaJscode2SessionResult.getOpenid())); } Result latestStaffWechat = epmetUserFeignClient.getLatestStaffWechatLoginRecord(wxMaJscode2SessionResult.getOpenid()); if (!latestStaffWechat.success() || null == latestStaffWechat.getData()) { logger.warn(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(); //2、记录staff_wechat this.savestaffwechat(staffLatestAgencyResultDTO.getStaffId(), wxMaJscode2SessionResult.getOpenid(), staffLatestAgencyResultDTO.getCustomerId()); //3、记录登录日志 this.saveStaffLoginRecord(staffLatestAgencyResultDTO); //4、获取用户token String token = this.generateGovWxmpToken(staffLatestAgencyResultDTO.getStaffId()); //5、保存到redis this.saveLatestGovTokenDto(staffLatestAgencyResultDTO, wxMaJscode2SessionResult, token); UserTokenResultDTO userTokenResultDTO = new UserTokenResultDTO(); userTokenResultDTO.setToken(token); return userTokenResultDTO; } //保存tokenDto到redis private void saveLatestGovTokenDto(StaffLatestAgencyResultDTO staffLatestAgency, WxMaJscode2SessionResult wxMaJscode2SessionResult, 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(wxMaJscode2SessionResult.getOpenid()); govTokenDto.setSessionKey(wxMaJscode2SessionResult.getSessionKey()); govTokenDto.setUnionId(wxMaJscode2SessionResult.getUnionid()); 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")); } /** * 查询人员在某机关单位下的角色列表 * @param staffId * @param orgId * @return */ public List queryGovStaffRoles(String staffId, String orgId) { StaffRoleFormDTO formDTO = new StaffRoleFormDTO(); formDTO.setStaffId(staffId); formDTO.setOrgId(orgId); Result> gridResult = epmetUserFeignClient.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; } /** * 根据工作人员ID查询网格ID列表 * @param staffId * @return */ public Set getGridIdList(String staffId) { Result> result = govOrgFeignClient.listGridsbystaffid(staffId); if (!result.success()) { logger.warn("登录:查询网格列表,远程调用返回错误:{}", result.getMsg()); return null; } else { List grids = result.getData(); return grids.stream().map(grid -> grid.getGridId()).collect(Collectors.toSet()); } } public Set getDeptartmentIdList(String staffId) { try { Result> deptListResult = govOrgFeignClient.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.warn("登录:查询部门列表,远程调用返回错误:{}", deptListResult.getMsg()); } } catch (Exception e) { String errorStackTrace = ExceptionUtils.getErrorStackTrace(e); logger.warn("登录:查询部门列表异常:{}", errorStackTrace); } return null; } //保存登录日志 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 = epmetUserFeignClient.saveStaffLoginRecord(staffLoginAgencyRecordFormDTO); return staffLoginRecordResult; } @Override public UserTokenResultDTO enterOrg(GovWxmpEnteOrgFormDTO formDTO) { //1、需要校验要登录的客户,是否被禁用 CustomerStaffFormDTO customerStaffFormDTO = new CustomerStaffFormDTO(); customerStaffFormDTO.setCustomerId(formDTO.getCustomerId()); customerStaffFormDTO.setMobile(formDTO.getMobile()); Result customerStaffDTOResult = epmetUserFeignClient.getCustomerStaffInfo(customerStaffFormDTO); if (!customerStaffDTOResult.success() || null == customerStaffDTOResult.getData()) { logger.warn(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、解析微信用户 WxMaJscode2SessionResult wxMaJscode2SessionResult = loginService.getWxMaUser(LoginConstant.APP_GOV, formDTO.getWxCode(), formDTO.getAppId()); //3、记录staff_wechat,并记录用户激活状态,激活时间 this.savestaffwechat(customerStaff.getUserId(), wxMaJscode2SessionResult.getOpenid(), formDTO.getCustomerId()); //4、记录登录日志 this.saveStaffLoginRecord(formDTO, customerStaff.getUserId(), wxMaJscode2SessionResult.getOpenid()); //5.1、获取用户token String token = this.generateGovWxmpToken(customerStaff.getUserId()); //5.2、保存到redis this.saveGovTokenDto(formDTO.getRootAgencyId(), formDTO.getCustomerId(), customerStaff.getUserId(), wxMaJscode2SessionResult, token); UserTokenResultDTO userTokenResultDTO = new UserTokenResultDTO(); userTokenResultDTO.setToken(token); return userTokenResultDTO; } @Override public void loginOut(TokenDto tokenDto) { if(null == tokenDto){ logger.warn("token解析失败,直接跳转重新登录即可"); throw new RenException("当前用户信息获取失败"); } cpUserDetailRedis.logout(tokenDto.getApp() , tokenDto.getClient() , tokenDto.getUserId()); } @Override public void updateCachedRoles(String staffId, String orgId, List roleIds) { GovTokenDto userDetails = cpUserDetailRedis.get(AppClientConstant.APP_GOV, AppClientConstant.CLIENT_WXMP, staffId, GovTokenDto.class); if (userDetails == null) { return; } GovStaffRoleFormDTO form = new GovStaffRoleFormDTO(); form.setRoleIdList(roleIds); Result> result = userOpenFeignClient.getByIds(form); if (!result.success()) { throw new RenException("更新缓存中的角色列表失败:" + result.getInternalMsg()); } List roles = result.getData().stream().map(roleDto -> { GovTokenDto.Role role = new GovTokenDto.Role(); role.setRoleName(roleDto.getRoleName()); role.setRoleKey(roleDto.getRoleKey()); role.setId(roleDto.getRoleId()); return role; }).collect(Collectors.toList()); userDetails.setRoleList(roles); cpUserDetailRedis.set(userDetails, jwtTokenProperties.getExpire()); } @Override public List getMyOrgByPassword(StaffOrgsFormDTO formDTO) { //1、根据手机号查询到用户信息 Result> customerStaffResult = epmetUserFeignClient.checkCustomerStaff(formDTO.getMobile()); if (!customerStaffResult.success()) { logger.warn(String.format("手机密码登录异常,手机号[%s],code[%s],msg[%s]", formDTO.getMobile(), customerStaffResult.getCode(), customerStaffResult.getMsg())); throw new RenException(customerStaffResult.getCode()); } //2、密码是否正确 List customerStaffList=customerStaffResult.getData(); //3、查询用户所有的组织信息 List customerIdList = new ArrayList<>(); //是否设置过密码 boolean havePasswordFlag=false; //密码是否正确 boolean passwordRightFlag=false; for (CustomerStaffDTO customerStaffDTO : customerStaffList) { if(StringUtils.isNotBlank(customerStaffDTO.getPassword())){ havePasswordFlag=true; }else{ logger.warn(String.format("当前用户:手机号%s,客户Id%s下未设置密码.",formDTO.getMobile(),customerStaffDTO.getCustomerId())); continue; } if (!PasswordUtils.matches(formDTO.getPassword(), customerStaffDTO.getPassword())) { logger.warn(String.format("当前用户:手机号%s,客户Id%s密码匹配错误.",formDTO.getMobile(),customerStaffDTO.getCustomerId())); }else{ logger.warn(String.format("当前用户:手机号%s,客户Id%s密码匹配正确.",formDTO.getMobile(),customerStaffDTO.getCustomerId())); passwordRightFlag=true; customerIdList.add(customerStaffDTO.getCustomerId()); } } //根据手机号查出来所有用户,密码都为空,表明用户未激活账户,未设置密码 if(!havePasswordFlag){ logger.warn(String.format("当前手机号(%s)下所有账户都未设置密码,请先使用验证码登录激活账户",formDTO.getMobile())); throw new RenException(EpmetErrorCode.PASSWORD_ERROR.getCode()); } //密码错误 if(!passwordRightFlag){ logger.warn(String.format("根据当前手机号(%s)密码未找到所属组织,密码错误",formDTO.getMobile())); throw new RenException(EpmetErrorCode.PASSWORD_ERROR.getCode()); } StaffOrgFormDTO staffOrgFormDTO = new StaffOrgFormDTO(); staffOrgFormDTO.setCustomerIdList(customerIdList); Result> result = govOrgFeignClient.getStaffOrgList(staffOrgFormDTO); if(result.success()&&null!=result.getData()){ return result.getData(); } logger.warn(String .format("手机验证码获取组织,调用%s服务失败,入参手机号%s,密码%s,返回错误码%s,错误提示信息%s", ServiceConstant.GOV_ORG_SERVER, formDTO.getMobile(), formDTO.getPassword(), result.getCode(), result.getMsg())); return new ArrayList<>(); } //保存登录日志 private Result saveStaffLoginRecord(GovWxmpEnteOrgFormDTO formDTO, String staffId, String openId) { StaffLoginAgencyRecordFormDTO staffLoginAgencyRecordFormDTO = new StaffLoginAgencyRecordFormDTO(); staffLoginAgencyRecordFormDTO.setCustomerId(formDTO.getCustomerId()); staffLoginAgencyRecordFormDTO.setStaffId(staffId); staffLoginAgencyRecordFormDTO.setWxOpenId(openId); staffLoginAgencyRecordFormDTO.setMobile(formDTO.getMobile()); staffLoginAgencyRecordFormDTO.setAgencyId(formDTO.getRootAgencyId()); Result staffLoginRecordResult = epmetUserFeignClient.saveStaffLoginRecord(staffLoginAgencyRecordFormDTO); return staffLoginRecordResult; } /** * @param userId * @param openid * @return com.epmet.commons.tools.utils.Result * @Author yinzuomei * @Description 保存微信和当前登录用户关系 * @Date 2020/4/18 22:54 **/ private Result savestaffwechat(String userId, String openid, String customerId) { StaffWechatFormDTO staffWechatFormDTO = new StaffWechatFormDTO(); staffWechatFormDTO.setUserId(userId); staffWechatFormDTO.setWxOpenId(openid); staffWechatFormDTO.setCustomerId(customerId); return epmetUserFeignClient.saveStaffWechat(staffWechatFormDTO); } /** * @Description 生成token * @Date 2020/4/18 23:04 **/ private String generateGovWxmpToken(String staffId) { Map map = new HashMap<>(); map.put("app", LoginConstant.APP_GOV); map.put("client", LoginConstant.CLIENT_WXMP); map.put("userId", staffId); String token = jwtTokenUtils.createToken(map); logger.info("app:" + LoginConstant.APP_GOV + ";client:" + LoginConstant.CLIENT_WXMP + ";userId:" + staffId + ";生成token[" + token + "]"); return token; } /** * @Description 生成token * @Date 2020/4/18 23:04 **/ private void saveGovTokenDto(String orgId, String customerId, String staffId, WxMaJscode2SessionResult wxMaJscode2SessionResult, String token) { int expire = jwtTokenProperties.getExpire(); GovTokenDto govTokenDto = new GovTokenDto(); govTokenDto.setApp(LoginConstant.APP_GOV); govTokenDto.setClient(LoginConstant.CLIENT_WXMP); govTokenDto.setUserId(staffId); govTokenDto.setOpenId(wxMaJscode2SessionResult.getOpenid()); govTokenDto.setSessionKey(wxMaJscode2SessionResult.getSessionKey()); govTokenDto.setUnionId(null == wxMaJscode2SessionResult.getUnionid() ? "" : wxMaJscode2SessionResult.getUnionid()); govTokenDto.setToken(token); govTokenDto.setUpdateTime(System.currentTimeMillis()); govTokenDto.setExpireTime(jwtTokenUtils.getExpiration(token).getTime()); govTokenDto.setRootAgencyId(orgId); govTokenDto.setCustomerId(customerId); //设置部门,网格,角色列表 govTokenDto.setDeptIdList(getDeptartmentIdList(staffId)); govTokenDto.setGridIdList(getGridIdList(staffId)); CustomerAgencyDTO agency = getAgencyByStaffId(staffId); if (agency != null) { govTokenDto.setAgencyId(agency.getId()); govTokenDto.setRoleList(queryGovStaffRoles(staffId, agency.getId())); } govTokenDto.setOrgIdPath(getOrgIdPath(staffId)); cpUserDetailRedis.set(govTokenDto, expire); logger.info("截止时间:" + DateUtils.format(jwtTokenUtils.getExpiration(token), "yyyy-MM-dd HH:mm:ss")); } /** * 查询工作人员的OrgIdPath * @param staffId * @return */ public String getOrgIdPath(String staffId) { Result result = govOrgFeignClient.getAgencyByStaff(staffId); if (!result.success()) { logger.warn("登录:查询登录人所属的机关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; } public CustomerAgencyDTO getAgencyByStaffId(String staffId) { Result result = govOrgFeignClient.getAgencyByStaff(staffId); if (!result.success()) { logger.warn("登录:查询登录人所属的机关OrgIdPath失败:{}", result.getMsg()); return null; } return result.getData(); } }