forked from luyan/epmet-cloud-lingshan
				
			
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							409 lines
						
					
					
						
							16 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							409 lines
						
					
					
						
							16 KiB
						
					
					
				| package com.epmet.service.impl; | |
| 
 | |
| import cn.binarywang.wx.miniapp.api.WxMaService; | |
| import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; | |
| import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; | |
| import cn.binarywang.wx.miniapp.bean.WxMaUserInfo; | |
| import com.alibaba.fastjson.JSON; | |
| import com.epmet.common.token.constant.LoginConstant; | |
| import com.epmet.commons.tools.exception.EpmetErrorCode; | |
| import com.epmet.commons.tools.exception.RenException; | |
| import com.epmet.commons.tools.security.dto.TokenDto; | |
| import com.epmet.commons.tools.security.password.PasswordUtils; | |
| 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.ValidatorUtils; | |
| import com.epmet.dto.UserDTO; | |
| import com.epmet.dto.UserWechatDTO; | |
| import com.epmet.dto.form.*; | |
| import com.epmet.dto.result.PasswordLoginUserInfoResultDTO; | |
| import com.epmet.dto.result.UserTokenResultDTO; | |
| import com.epmet.feign.EpmetUserFeignClient; | |
| import com.epmet.feign.OperAccessOpenFeignClient; | |
| import com.epmet.jwt.JwtTokenProperties; | |
| import com.epmet.jwt.JwtTokenUtils; | |
| import com.epmet.redis.CustomerAppWxServiceUtil; | |
| import com.epmet.service.CaptchaService; | |
| import com.epmet.service.LoginService; | |
| import com.epmet.utils.WxMaServiceUtils; | |
| import lombok.extern.slf4j.Slf4j; | |
| import me.chanjar.weixin.common.error.WxErrorException; | |
| 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 java.util.HashMap; | |
| import java.util.Map; | |
| 
 | |
| /** | |
|  * @Description | |
|  * @Author yinzuomei | |
|  * @Date 2020/3/14 20:31 | |
|  */ | |
| @Slf4j | |
| @Service | |
| public class LoginServiceImpl implements LoginService { | |
| 	private static final Logger logger = LoggerFactory.getLogger(AuthServiceImpl.class); | |
| 
 | |
| 	@Autowired | |
| 	private EpmetUserFeignClient epmetUserFeignClient; | |
| 
 | |
| 	@Autowired | |
| 	private WxMaServiceUtils wxMaServiceUtils; | |
| 
 | |
| 	@Autowired | |
| 	private JwtTokenUtils jwtTokenUtils; | |
| 
 | |
| 	@Autowired | |
| 	private JwtTokenProperties jwtTokenProperties; | |
| 
 | |
| 	@Autowired | |
| 	private CpUserDetailRedis cpUserDetailRedis; | |
| 
 | |
| 	@Autowired | |
| 	private CaptchaService captchaService; | |
| 
 | |
| 	@Autowired | |
| 	private OperAccessOpenFeignClient operAccessOpenFeignClient; | |
| 
 | |
| 	/** | |
| 	 * 居民端微信小程序登录 | |
| 	 * | |
| 	 * @param formDTO | |
| 	 * @return com.epmet.commons.tools.utils.Result<com.epmet.dto.UserTokenResultDTO> | |
| 	 * @author yinzuomei | |
| 	 * @since 2020/3/14 19:34 | |
| 	 */ | |
| 	@Override | |
| 	public Result<UserTokenResultDTO> loginByWxCode(LoginByWxCodeFormDTO formDTO) { | |
| 		if(!(LoginConstant.APP_RESI.equals(formDTO.getApp())&&LoginConstant.CLIENT_WXMP.equals(formDTO.getClient()))){ | |
| 			logger.error("当前接口只适用于居民端微信小程序登录"); | |
| 			throw new RenException("参数错误"); | |
| 		} | |
| 		//1、根据wxCode获取微信信息 | |
| 		WxMaJscode2SessionResult wxMaJscode2SessionResult = this.getWxMaUser(formDTO.getApp(),formDTO.getWxCode(),formDTO.getAppId()); | |
| 		logger.info("openId=[" + wxMaJscode2SessionResult.getOpenid() + "]unionId=[" + wxMaJscode2SessionResult.getUnionid() + "]"); | |
| 		//2、根据openId查询数据库,没有则直接插入一条记录 | |
| 		String userId = this.getUserId(formDTO, wxMaJscode2SessionResult); | |
| 		if (StringUtils.isNotBlank(userId)) { | |
| 			//3、封装token且存到redis | |
| 			String token=this.generateToken(formDTO,userId); | |
| 			this.saveTokenDto(formDTO,userId,wxMaJscode2SessionResult,token); | |
| 			UserTokenResultDTO userTokenResultDTO = new UserTokenResultDTO(); | |
| 			userTokenResultDTO.setToken(token); | |
| 			return new Result<UserTokenResultDTO>().ok(userTokenResultDTO); | |
| 		}else{ | |
| 			logger.error("登录失败userId为空"); | |
| 			throw new RenException("登录失败"); | |
| 		} | |
| 	} | |
| 
 | |
| 	/** | |
| 	 * 解析微信code获取小程序用户信息 | |
| 	 * | |
| 	 * @param app | |
| 	 * @param wxCode | |
| 	 * @return cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult | |
| 	 * @author yinzuomei | |
| 	 * @date 2020/3/14 20:16 | |
| 	 */ | |
| 	@Override | |
| 	public WxMaJscode2SessionResult getWxMaUser(String app,String wxCode,String appId) { | |
| 		WxMaJscode2SessionResult wxMaJscode2SessionResult = null; | |
| 		try { | |
| 			if (StringUtils.isNotBlank(appId)){ | |
| 				WxMaService wxMaService = CustomerAppWxServiceUtil.getWxMaService(appId); | |
| 				if (wxMaService == null){ | |
| 					throw new RenException("解析微信用户信息失败"); | |
| 				} | |
| 				wxMaJscode2SessionResult = wxMaService.jsCode2SessionInfo(wxCode); | |
| 			}else{ | |
| 				if (LoginConstant.APP_GOV.equals(app)) { | |
| 					wxMaJscode2SessionResult = wxMaServiceUtils.govWxMaService().jsCode2SessionInfo(wxCode); | |
| 				} else if (LoginConstant.APP_OPER.equals(app)) { | |
| 					wxMaJscode2SessionResult = wxMaServiceUtils.operWxMaService().jsCode2SessionInfo(wxCode); | |
| 				} else if (LoginConstant.APP_RESI.equals(app)) { | |
| 					wxMaJscode2SessionResult = wxMaServiceUtils.resiWxMaService().jsCode2SessionInfo(wxCode); | |
| 				} | |
| 			} | |
| 		} catch (WxErrorException e) { | |
| 			log.error("->[getMaOpenId]::error[{}]", "解析微信code失败",e); | |
| 		} | |
| 		if (null == wxMaJscode2SessionResult) { | |
| 			log.error(String.format("解析微信用户信息失败,app[%s],wxCode[%s],result:[%S]",app,wxCode, JSON.toJSONString(wxMaJscode2SessionResult))); | |
| 			throw new RenException("解析微信用户信息失败"); | |
| 		} else if (StringUtils.isBlank(wxMaJscode2SessionResult.getOpenid())) { | |
| 			log.error(String.format("获取微信openid失败,app[%s],wxCode[%s]",app,wxCode)); | |
| 			throw new RenException("获取微信openid失败"); | |
| 		} | |
| 		return wxMaJscode2SessionResult; | |
| 	} | |
| 
 | |
| 	@Override | |
| 	public String getResiWxPhone(ResiWxPhoneFormDTO formDTO) { | |
| 		String phone=""; | |
| 		try { | |
| 			ValidatorUtils.validateEntity(formDTO, ResiWxPhoneFormDTO.AddUserInternalGroup.class); | |
| 			WxMaService wxMaService = null; | |
| 			if (StringUtils.isNotBlank(formDTO.getAppId())){ | |
| 				wxMaService = CustomerAppWxServiceUtil.getWxMaService(formDTO.getAppId()); | |
| 			}else{ | |
| 				wxMaService = wxMaServiceUtils.resiWxMaService(); | |
| 			} | |
| 			WxMaJscode2SessionResult wxMaJscode2SessionResult = wxMaService.jsCode2SessionInfo(formDTO.getWxCode()); | |
| 			WxMaPhoneNumberInfo phoneNoInfo = wxMaService.getUserService().getPhoneNoInfo(wxMaJscode2SessionResult.getSessionKey(), | |
| 					formDTO.getEncryptedData(), | |
| 					formDTO.getIv()); | |
| 			if (null != phoneNoInfo) { | |
| 				phone= phoneNoInfo.getPurePhoneNumber(); | |
| 			} | |
| 		} catch (WxErrorException e) { | |
| 			log.error("method exception", e); | |
| 			log.error(String.format("获取用户微信绑定的手机号接口异常%s",e.getMessage())); | |
| 		} catch(Exception e){ | |
| 			log.error("method exception", e); | |
| 			log.error(String.format("获取用户微信绑定的手机号接口异常%s",e.getMessage())); | |
| 		} | |
| 		return phone; | |
| 	} | |
| 
 | |
| 	/** | |
| 	 * 根据openId查询用户id | |
| 	 * | |
| 	 * @param formDTO | |
| 	 * @param wxMaJscode2SessionResult | |
| 	 * @return java.lang.String | |
| 	 * @author yinzuomei | |
| 	 * @since 2020/3/14 19:34 | |
| 	 */ | |
| 	private String getUserId(LoginByWxCodeFormDTO formDTO, WxMaJscode2SessionResult wxMaJscode2SessionResult) { | |
| 		WxLoginUserInfoFormDTO wxLoginUserInfoFormDTO = new WxLoginUserInfoFormDTO(); | |
| 		wxLoginUserInfoFormDTO.setApp(formDTO.getApp()); | |
| 		wxLoginUserInfoFormDTO.setOpenId(wxMaJscode2SessionResult.getOpenid()); | |
| 		//1、先根据app、client、openId查询 | |
| 		Result<UserDTO> userResult = epmetUserFeignClient.selecWxLoginUserInfo(wxLoginUserInfoFormDTO); | |
| 		String userId = ""; | |
| 		if (!userResult.success()) { | |
| 			logger.error("根据openId、app获取用户信息失败" + userResult.getMsg()); | |
| 			throw new RenException("获取用户信息失败" + userResult.getMsg()); | |
| 		} | |
| 		if(null!=userResult.getData()&&StringUtils.isNotBlank(userResult.getData().getId())){ | |
| 			userId = userResult.getData().getId(); | |
| 		} | |
| 		//2、如果已经存在userId,则更新微信信息 | |
| 		if (StringUtils.isNotBlank(userId) && StringUtils.isNotBlank(formDTO.getEncryptedData()) && StringUtils.isNotBlank(formDTO.getIv())) { | |
| 			this.updateWxInfO(userId,formDTO,wxMaJscode2SessionResult); | |
| 		} | |
| 		//3、数据库不存在此用户则创建此用户 | |
| 		if (StringUtils.isBlank(userId)) { | |
| 			userId = createUser(formDTO, wxMaJscode2SessionResult); | |
| 		} | |
| 		return userId; | |
| 	} | |
| 
 | |
| 	/** | |
| 	 * @return com.epmet.commons.tools.utils.Result | |
| 	 * @param userId | |
| 	 * @param wxMaJscode2SessionResult | |
| 	 * @Author yinzuomei | |
| 	 * @Description 获取用户微信基本信息更新到本地 | |
| 	 * @Date 2020/3/20 19:51 | |
| 	 **/ | |
| 	private Result updateWxInfO(String userId, | |
| 								LoginByWxCodeFormDTO formDTO, | |
| 								WxMaJscode2SessionResult wxMaJscode2SessionResult) { | |
| 		WxMaUserInfo wxMaUserInfo = wxMaServiceUtils.resiWxMaService().getUserService() | |
| 				.getUserInfo(wxMaJscode2SessionResult.getSessionKey(), | |
| 						formDTO.getEncryptedData(), | |
| 						formDTO.getIv()); | |
| 		UserWechatDTO userWechatDTO = this.packageCustomerUserDTO(wxMaUserInfo); | |
| 		userWechatDTO.setUserId(userId); | |
| 		Result<UserDTO> updateUserDtoResult=epmetUserFeignClient.saveOrUpdateUserWechatDTO(userWechatDTO); | |
| 		return new Result(); | |
| 	} | |
| 
 | |
| 	/** | |
| 	 * @param formDTO | |
| 	 * @param wxMaJscode2SessionResult | |
| 	 * @return java.lang.String | |
| 	 * @Author yinzuomei | |
| 	 * @Description 陌生人首次授权,创建用户信息 | |
| 	 * @Date 2020/3/20 19:42 | |
| 	 **/ | |
| 	private String createUser(LoginByWxCodeFormDTO formDTO, WxMaJscode2SessionResult wxMaJscode2SessionResult) { | |
| 		String userId = ""; | |
| 		//查询customer_user | |
| 		UserWechatDTO userWechatDTO = new UserWechatDTO(); | |
| 		if (StringUtils.isNotBlank(formDTO.getIv()) && StringUtils.isNotBlank(formDTO.getEncryptedData())) { | |
| 			WxMaUserInfo wxMaUserInfo = wxMaServiceUtils.resiWxMaService().getUserService() | |
| 					.getUserInfo(wxMaJscode2SessionResult.getSessionKey(), | |
| 							formDTO.getEncryptedData(), | |
| 							formDTO.getIv()); | |
| 			userWechatDTO = this.packageCustomerUserDTO(wxMaUserInfo); | |
| 		} else { | |
| 			userWechatDTO.setWxOpenId(wxMaJscode2SessionResult.getOpenid()); | |
| 			userWechatDTO.setUnionId(wxMaJscode2SessionResult.getUnionid()); | |
| 		} | |
| 		Result<UserDTO> saveUserWechatResult = epmetUserFeignClient.saveOrUpdateUserWechatDTO(userWechatDTO); | |
| 		if (!saveUserWechatResult.success()||null==saveUserWechatResult.getData()) { | |
| 			throw new RenException("创建用户失败" + saveUserWechatResult.getMsg()); | |
| 		} | |
| 		userId = saveUserWechatResult.getData().getId(); | |
| 		return userId; | |
| 	} | |
| 
 | |
| 	/** | |
| 	 * @param wxMaUserInfo | |
| 	 * @return com.epmet.dto.UserWechatDTO | |
| 	 * @Author yinzuomei | |
| 	 * @Description 微信信息封装为customer_user记录 | |
| 	 * @Date 2020/3/17 18:22 | |
| 	 **/ | |
| 	private UserWechatDTO packageCustomerUserDTO(WxMaUserInfo wxMaUserInfo) { | |
| 		UserWechatDTO userWechatDTO = new UserWechatDTO(); | |
| 		userWechatDTO.setCity(wxMaUserInfo.getCity()); | |
| 		userWechatDTO.setWxOpenId(wxMaUserInfo.getOpenId()); | |
| 		userWechatDTO.setUnionId(wxMaUserInfo.getUnionId()); | |
| 		userWechatDTO.setNickname(wxMaUserInfo.getNickName()); | |
| 		userWechatDTO.setCountry(wxMaUserInfo.getCountry()); | |
| 		userWechatDTO.setHeadImgUrl(wxMaUserInfo.getAvatarUrl()); | |
| 		userWechatDTO.setProvince(wxMaUserInfo.getProvince()); | |
| 		userWechatDTO.setSex(Integer.valueOf(wxMaUserInfo.getGender())); | |
| 		return userWechatDTO; | |
| 	} | |
| 
 | |
| 
 | |
| 	/** | |
| 	 * 手机号+密码登录接口 | |
| 	 * | |
| 	 * @param formDTO | |
| 	 * @return com.epmet.commons.tools.utils.Result<com.epmet.dto.UserTokenResultDTO> | |
| 	 * @author yinzuomei | |
| 	 * @since 2020/3/14 19:34 | |
| 	 */ | |
| 	@Override | |
| 	public Result<UserTokenResultDTO> loginByPassword(LoginByPassWordFormDTO formDTO) { | |
| 		if(!(LoginConstant.APP_OPER.equals(formDTO.getApp())&&LoginConstant.CLIENT_WEB.equals(formDTO.getClient()))){ | |
| 			logger.error("当前接口只适用于运营端管理后台"); | |
| 			throw new RenException("当前接口只适用于运营端管理后台"); | |
| 		} | |
| 		//1、验证码是否正确 | |
| 		boolean flag = captchaService.validate(formDTO.getUuid(), formDTO.getCaptcha()); | |
| 		if (!flag) { | |
| 			logger.warn(String.format("用户%s登录,验证码输入错误", formDTO.getPhone())); | |
| 			//2020-05-21去除验证码校验 | |
| 			//return new Result<UserTokenResultDTO>().error(EpmetErrorCode.ERR10019.getCode()); | |
| 		} | |
| 		//2、账号是否存在 | |
| 		//获取用户信息 | |
| 		PasswordLoginUserInfoFormDTO passwordLoginUserInfoFormDTO = new PasswordLoginUserInfoFormDTO(); | |
| 		passwordLoginUserInfoFormDTO.setApp(formDTO.getApp()); | |
| 		passwordLoginUserInfoFormDTO.setPhone(formDTO.getPhone()); | |
| 		Result<PasswordLoginUserInfoResultDTO> userInfoResult = epmetUserFeignClient.selectLoginUserInfoByPassword(passwordLoginUserInfoFormDTO); | |
| 		if (!userInfoResult.success() || null == userInfoResult.getData()) { | |
| 			// logger.error("根据手机号查询运营人员信息失败,返回10003账号不存在"); | |
| 			throw new RenException(EpmetErrorCode.ERR10003.getCode()); | |
| 		} | |
| 		//3、密码是否正确 | |
| 		//密码错误 | |
| 		if (!PasswordUtils.matches(formDTO.getPassword(), userInfoResult.getData().getPassWord())) { | |
| 			throw new RenException(EpmetErrorCode.ERR10004.getCode()); | |
| 		} | |
| 		//4、生成token返回,且将TokenDto存到redis | |
| 		UserTokenResultDTO userTokenResultDTO = new UserTokenResultDTO(); | |
| 		userTokenResultDTO.setToken(this.packagingUserToken(formDTO, userInfoResult.getData().getUserId())); | |
| 		return new Result<UserTokenResultDTO>().ok(userTokenResultDTO); | |
| 	} | |
| 
 | |
| 	/** | |
| 	 * 封装用户token值 | |
| 	 * | |
| 	 * @param formDTO | |
| 	 * @param userId | |
| 	 * @return java.lang.String | |
| 	 * @author yinzuomei | |
| 	 * @since 2020/3/14 19:34 | |
| 	 */ | |
| 	private String packagingUserToken(LoginByPassWordFormDTO formDTO, | |
| 									  String userId) { | |
| 		// 生成token | |
| 		Map<String, Object> map = new HashMap<>(); | |
| 		map.put("app", formDTO.getApp()); | |
| 		map.put("client", formDTO.getClient()); | |
| 		map.put("userId", userId); | |
| 		String token = jwtTokenUtils.createToken(map); | |
| 		logger.info("app:"+formDTO.getApp()+";client:"+formDTO.getClient()+";userId:"+userId+";生成token["+token+"]"); | |
| 		int expire = jwtTokenProperties.getExpire(); | |
| 		TokenDto tokenDto = new TokenDto(); | |
| 		tokenDto.setApp(formDTO.getApp()); | |
| 		tokenDto.setClient(formDTO.getClient()); | |
| 		tokenDto.setUserId(userId); | |
| 		tokenDto.setToken(token); | |
| 		tokenDto.setUpdateTime(System.currentTimeMillis()); | |
| 		tokenDto.setExpireTime(jwtTokenUtils.getExpiration(token).getTime()); | |
| 		cpUserDetailRedis.set(tokenDto, expire); | |
| 		logger.info("截止时间:"+ DateUtils.format(jwtTokenUtils.getExpiration(token),"yyyy-MM-dd HH:mm:ss")); | |
| 		return token; | |
| 	} | |
| 
 | |
| 
 | |
| 	@Override | |
| 	public Result logoutByToken(TokenDto tokenDto) { | |
| 		//记录登出日志 | |
| 		//删除redis | |
| 		if (null == tokenDto) { | |
| 			logger.error("运营端用户退出系统错误:账号不存在,接口继续执行返回成功"); | |
| 			return new Result(); | |
| 		} | |
| 		cpUserDetailRedis.logout(tokenDto.getApp(), tokenDto.getClient(), tokenDto.getUserId()); | |
| 		//web端清空菜单栏和权限 | |
| 		Result operAccessResult = operAccessOpenFeignClient.clearOperUserAccess(); | |
| 		if (operAccessResult.success()) { | |
| 			logger.info(String.format("运营人员%s退出成功,清空菜单和权限redis成功", tokenDto.getUserId())); | |
| 		} else { | |
| 			logger.error(String.format("运营人员%s退出成功,清空菜单和权限redis异常", tokenDto.getUserId())); | |
| 		} | |
| 		return new Result(); | |
| 	} | |
| 
 | |
| 	/** | |
| 	 * @Description  生成token | |
| 	 * @Date 2020/4/18 23:04 | |
| 	 **/ | |
| 	private String generateToken(LoginCommonFormDTO formDTO,String userId){ | |
| 		Map<String, Object> map = new HashMap<>(); | |
| 		map.put("app", formDTO.getApp()); | |
| 		map.put("client", formDTO.getClient()); | |
| 		map.put("userId", userId); | |
| 		String token = jwtTokenUtils.createToken(map); | |
| 		logger.info("app:"+formDTO.getApp()+";client:"+formDTO.getClient()+";userId:"+userId+";生成token["+token+"]"); | |
| 		return token; | |
| 	} | |
| 
 | |
| 	/** | |
| 	 * @Description  生成token | |
| 	 * @Date 2020/4/18 23:04 | |
| 	 **/ | |
| 	private String saveTokenDto(LoginCommonFormDTO formDTO, | |
| 								String userId, | |
| 								WxMaJscode2SessionResult wxMaJscode2SessionResult, | |
| 								String token) { | |
| 		int expire = jwtTokenProperties.getExpire(); | |
| 		TokenDto tokenDto = new TokenDto(); | |
| 		tokenDto.setApp(formDTO.getApp()); | |
| 		tokenDto.setClient(formDTO.getClient()); | |
| 		tokenDto.setUserId(userId); | |
| 		tokenDto.setOpenId(wxMaJscode2SessionResult.getOpenid()); | |
| 		tokenDto.setSessionKey(wxMaJscode2SessionResult.getSessionKey()); | |
| 		tokenDto.setUnionId(wxMaJscode2SessionResult.getUnionid()); | |
| 		tokenDto.setToken(token); | |
| 		tokenDto.setUpdateTime(System.currentTimeMillis()); | |
| 		tokenDto.setExpireTime(jwtTokenUtils.getExpiration(token).getTime()); | |
| 		cpUserDetailRedis.set(tokenDto, expire); | |
| 		logger.info("截止时间:"+ DateUtils.format(jwtTokenUtils.getExpiration(token),"yyyy-MM-dd HH:mm:ss")); | |
| 		return token; | |
| 	} | |
| }
 | |
| 
 |