package com.xzx.gc.user.controller; import cn.hutool.core.codec.Base64; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.aliyuncs.exceptions.ClientException; import com.xzx.gc.common.Result; import com.xzx.gc.common.annotations.PassToken; import com.xzx.gc.common.annotations.valid.InsertExtend; import com.xzx.gc.common.constant.Constants; import com.xzx.gc.common.constant.PayEnum; import com.xzx.gc.common.constant.RedisKeyConstant; import com.xzx.gc.common.dto.CommonDto; import com.xzx.gc.common.dto.log.OperationAppLog; import com.xzx.gc.common.exception.RestException; import com.xzx.gc.common.request.BaseController; import com.xzx.gc.common.utils.*; import com.xzx.gc.common.utils.image.GraphicsUtils; import com.xzx.gc.common.utils.wxpay.WxUtil; import com.xzx.gc.entity.*; import com.xzx.gc.model.user.UserInfoVo; import com.xzx.gc.model.user.UserReq; import com.xzx.gc.user.dto.*; import com.xzx.gc.user.mapper.AccountMapper; import com.xzx.gc.user.mapper.OtherUserMapper; import com.xzx.gc.user.mapper.UserDeviceMapper; import com.xzx.gc.user.mapper.UserMapper; import com.xzx.gc.user.service.*; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import javax.servlet.http.HttpServletRequest; import java.security.NoSuchAlgorithmException; import java.security.spec.AlgorithmParameterSpec; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /** * @author:andylei * @title * @Description * @date 2018/11/22/022 * @修改历史 */ @Api(tags = "登录验证码相关") @RequestMapping("/") @RestController @Slf4j @Validated public class LoginController extends BaseController { @Autowired private BusinessUtil businessUtil; @Autowired private AccountService accountService; @Autowired private GraphicsUtils graphicsUtils; @Autowired public UserLoginService userLoginService; @Autowired public UserService userService; @Autowired private WxUtil wxUtil; @Autowired private RedisUtil redisUtil; @Autowired private TokenUtil tokenUtil; @Autowired private OtherUserService otherUserService; @Autowired private UserStatService userStatService; @Autowired private AccountMapper accountMapper; @Autowired private OtherUserMapper otherUserMapper; @Autowired private UserDeviceMapper userDeviceMapper; @Autowired private UserMapper userMapper; @Autowired private AccountBindService accountBindService; @Autowired private MqUtil mqUtil; /** * 用户密码登录 */ @ApiOperation( value = "手机号加密码登录") @PostMapping("/loginPwd") @PassToken public Result login(HttpServletRequest request,@Validated @RequestBody LoginPwdDto loginPwdDto) throws NoSuchAlgorithmException { Result result = new Result(); LoginPwdResDto loginPwdResDto = null; String openId = loginPwdDto.getOpenId(); if(StrUtil.isBlank(openId)) { try { loginPwdDto.setPwd(SecurityUtil.decrypt(Constants.PWD_DECRET, loginPwdDto.getPwd())); } catch (Exception e) { log.warn("解密失败:" + loginPwdDto.getPwd(), e); result.setCode(-1); result.setMsg("密码格式错误"); return result; } }else { //分两种情况 一种是带手机号及密码和openid的登录绑定 第二种是只有openId的判断是否绑定 if(StrUtil.isBlank(loginPwdDto.getPwd())){ List byOpenId = otherUserService.findByOpenId(openId); if(CollUtil.isNotEmpty(byOpenId)){ loginPwdDto.setMobile(byOpenId.get(0).getMobilePhone()); loginPwdDto.setPwd(SecurityUtil.decrypt(byOpenId.get(0).getSalt(), byOpenId.get(0).getPassword())); }else { loginPwdResDto=new LoginPwdResDto(); loginPwdResDto.setBindFlag(Convert.toShort(Constants.DEL_FLAG)); return Result.success(loginPwdResDto); } }else{ String decrypt = SecurityUtil.decrypt(Constants.PWD_DECRET, loginPwdDto.getPwd()); if(StrUtil.isBlank(decrypt)){ log.warn("解密失败:" + loginPwdDto.getPwd()); result.setCode(-1); result.setMsg("密码格式错误"); return result; }else { loginPwdDto.setPwd(decrypt); } } } if(StringUtils.isBlank(loginPwdDto.getDevCode())){ throw new RestException(-1,"设备标识不能为空"); } loginPwdResDto = otherUserService.findByMobileAndPwd(loginPwdDto.getMobile(), loginPwdDto.getPwd()); int flag = loginPwdResDto.getFlag(); if(flag==-1){ result.setCode(-1); result.setMsg("用户被禁用"); }else if(flag==-2){ result.setCode(-1); result.setMsg("用户名或密码不正确"); }else if(flag==-3){ result.setCode(-1); result.setMsg("用户不存在"); }else{ //openid绑定 if(StrUtil.isNotBlank(openId)){ otherUserService.updateOpenIdByMobile(openId,loginPwdResDto.getMobilePhone()); //自动绑定 String userId = loginPwdResDto.getUserId(); AccountInfo byUserId = accountService.findByUserId(userId); AccountBindInfo byAccountIdAndType = accountBindService.findByAccountIdAndType(byUserId.getAccountId(), Convert.toShort(PayEnum.微信.getValue())); if(byAccountIdAndType==null){ AccountBindInfo accountBindInfo=new AccountBindInfo(); accountBindInfo.setAccountId(byUserId.getAccountId()); accountBindInfo.setAccountType(Convert.toShort(PayEnum.微信.getValue())); accountBindInfo.setAccountNumber(openId); accountBindService.add(accountBindInfo); }else{ //openid不一致则更新绑定 if(!openId.equals(byAccountIdAndType.getAccountNumber())) { byAccountIdAndType.setAccountNumber(openId); accountBindService.updateById(byAccountIdAndType); } } } //设备绑定 if(StrUtil.isNotBlank(loginPwdDto.getDevCode())){ UserDevice userDevice=new UserDevice(); userDevice.setDeviceCode(loginPwdDto.getDevCode()); userDevice.setUserId(loginPwdResDto.getUserId()); List deviceList = userDeviceMapper.select(userDevice); if(CollUtil.isNotEmpty(deviceList)){ UserDevice select = deviceList.get(0); select.setCreateTime(DateUtil.now()); select.setDeviceVersion(loginPwdDto.getDeviceVersion()); select.setDeviceName(loginPwdDto.getDeviceName()); userDeviceMapper.updateByPrimaryKeySelective(select); }else { userDevice.setCreateTime(DateUtil.now()); userDevice.setDeviceVersion(loginPwdDto.getDeviceVersion()); userDevice.setDeviceName(loginPwdDto.getDeviceName()); userDeviceMapper.insertSelective(userDevice); } } //token String token=tokenUtil.generateToken(); redisUtil.setex(Constants.REDIS_USER_KEY+"token:"+loginPwdResDto.getUserId(),token,tokenUtil.getTimeOut()); loginPwdResDto.setToken(token); loginPwdResDto.setBindFlag(Convert.toShort(Constants.DEL_NOT_FLAG)); result.setData(loginPwdResDto); } return result; } @ApiOperation( value = "修改密码") @PostMapping("/updatePwd") public Result updatePwd(HttpServletRequest request,@Validated @RequestBody UpdatePwdDto updatePwdDto) { Result result=new Result(); if (decrptPwd(updatePwdDto, result)) return result; //检验手机是否是自己的 String mobile = updatePwdDto.getMobile(); String userId = getUserId(request); OtherUserInfo byId = otherUserService.findById(userId); if(byId==null||!byId.getMobilePhone().equals(mobile)){ return Result.error(-1,"手机号码不正确"); } otherUserService.pwdUpdate(updatePwdDto, result, mobile); String mobilePhone = userService.findOtherByUserId(getUserId(request),0); OperationAppLog build = OperationAppLog.builder().appPrograme(getFrontClient(request)).opreateName(mobilePhone) .methodName(Constants.USER_MODUL_NAME).operateAction("修改密码-"+getUserId(request)).build(); mqUtil.sendApp(build); return result; } @ApiOperation( value = "忘记密码") @PostMapping("/forgetPwd") @PassToken public Result forgetPwd(@Validated @RequestBody UpdatePwdDto updatePwdDto,HttpServletRequest request) { Result result=new Result(); if (decrptPwd(updatePwdDto, result)){ return result; } //检验手机是否是当前系统中的 String mobile = updatePwdDto.getMobile(); List select =accountService.findByMobile(mobile); if(CollUtil.isEmpty(select)){ return Result.error(-1,"手机号码不正确"); } otherUserService.pwdUpdate(updatePwdDto, result, mobile); String mobilePhone = userService.findOtherByUserId(getUserId(request),0); OperationAppLog build = OperationAppLog.builder().appPrograme(getFrontClient(request)).opreateName(mobilePhone) .methodName(Constants.USER_MODUL_NAME).operateAction("找回密码-"+getUserId(request)).build(); mqUtil.sendApp(build); return result; } private boolean decrptPwd(@Validated @RequestBody UpdatePwdDto updatePwdDto, Result result) { try { updatePwdDto.setNewPwd(SecurityUtil.decrypt(Constants.PWD_DECRET,updatePwdDto.getNewPwd())); updatePwdDto.setNewPwdSure(SecurityUtil.decrypt(Constants.PWD_DECRET,updatePwdDto.getNewPwdSure())); } catch (Exception e) { log.warn("解密失败:"+updatePwdDto.getNewPwd(),e); result.setCode(-1); result.setMsg("密码格式错误"); return true; } return false; } /** * 用户登录 * @param userReq */ @ApiOperation( value = "手机号+验证码登录") @PostMapping("/login") @PassToken public Result> login(HttpServletRequest request,@RequestBody UserReq userReq) throws NoSuchAlgorithmException { Result result = new Result(); int returnvalue = userLoginService.login(userReq); if (returnvalue==-1){ result.setCode(-1); result.setMsg("验证码已经失效,有效期两分钟"); }else if (returnvalue==-2){ result.setCode(-1); result.setMsg("验证码错误"); }else if (returnvalue==-3){ result.setCode(-1); result.setMsg("同一微信用户只能绑定一个手机号码,请用正确的手机号码登录"); }else if(returnvalue==-4){ result.setCode(-4); result.setMsg("用户OPENID不能为空"); }else if (returnvalue>=0){ //返回用户信息及token给前台 List userList = userService.queryUserInfo(userReq); UserInfoVo userInfoVo = userList.get(0); //保存token String token=tokenUtil.generateToken(); redisUtil.setex(Constants.REDIS_USER_KEY+"token:"+userInfoVo.getUserId(),token,tokenUtil.getTimeOut()); userInfoVo.setToken(token); redisUtil.hset(RedisKeyConstant.USER_INFO,userReq.getOpenId(),JSONUtil.toJsonStr(userInfoVo)); result.setData(userList); redisUtil.del(Constants.REDIS_USER_KEY + "code:channel:" + userReq.getMobilePhone()); } return result; } @ApiOperation( value = "获取用户信息",notes = "id为openId") @PostMapping("/login/getUserInfo") @PassToken public Result getUserInfo(HttpServletRequest request,@RequestBody CommonDto commonDto){ UserInfo byOpenId = userService.findByOpenId(commonDto.getId()); if(byOpenId!=null){ String userId = byOpenId.getUserId(); if(redisUtil.exists(RedisKeyConstant.TOKEN+userId)) { String hget = redisUtil.hget(RedisKeyConstant.USER_INFO, commonDto.getId()); if (StrUtil.isNotBlank(hget)) { UserInfoVo userInfoVo = JSONUtil.toBean(hget, UserInfoVo.class); userInfoVo.setNickName(StringUtils.decode(userInfoVo.getNickName())); userInfoVo.setAvatarUrl(userInfoVo.getAvatar()); return Result.success(userInfoVo); } } } return Result.error(-3,"用户不存在"); } /** * 根据手机号获取验证码 * @param userReq */ @ApiOperation( value = "根据手机号获取验证码") @PostMapping("/login/verifycode") @PassToken public Result getVerifyCode(HttpServletRequest request,@RequestBody UserReq userReq) throws ClientException { String phoneNum = userReq.getMobilePhone(); Result result = new Result(); if (phoneNum==null || "".equals(phoneNum)){ result.setCode(-1); result.setMsg("手机号为空"); } String key=""; key=Constants.REDIS_USER_KEY+"code:"+phoneNum; String code = redisUtil.get(key); if (StringUtils.isNotBlank(code)){ result.setCode(-1); result.setMsg("验证码需60秒后重新获取"); return result; } //忘记密码 if(userReq.getSmsType()==1) { List select = accountService.findByMobile(phoneNum); if (CollUtil.isEmpty(select)) { return Result.error(-1, "手机号码不正确"); } } String verifyCode = userLoginService.getVerifyCode(phoneNum, userReq.getSmsType()); if(Convert.toStr(Constants.RESULT_SUCCESS).equals(verifyCode)){ UserInfoVo userInfoVo = new UserInfoVo(); long currentTime = System.currentTimeMillis(); userInfoVo.setTimestamp(String.valueOf(currentTime)); result.setData(userInfoVo); return result; }else{ result.setCode(-1); result.setMsg(verifyCode); return result; } } @ApiOperation(value = "调用微信接口生成二维码") @PostMapping(value = "/acode") public Result getacodepost(HttpServletRequest request,@Validated(value = {InsertExtend.class}) @RequestBody AcodeDto acodeDto) { Result result=new Result(); String userId=getUserId(request); String path=null; //个人二维码 if(acodeDto.getType()==1){ //二维码图名称 String imgName="/user_" + userId + "_acode.jpg"; UserInfo userInfo = userMapper.selectByPrimaryKey(userId); if(userInfo!=null){ AtomicInteger atomicInteger=new AtomicInteger(1); while (1==1) { if(atomicInteger.get()>10){ break; } path = wxUtil.generateAcode("poster=" + userInfo.getMobilePhone(), "pages/login/login", imgName, "800px"); if(StrUtil.isNotBlank(path)){ break; } log.debug("小程序二维码格式异常,重新生成:{},重试次数:{}",acodeDto.getUserId(),atomicInteger.get()); atomicInteger.getAndIncrement(); } }else{ log.warn("用户不存在:{}",userId); } }else { //设置推广员的经纬度 AddressDto addressDto=new AddressDto(); // addressDto.setLatitude(acodeDto.getLatitude()); // addressDto.setLongitude(acodeDto.getLongitude()); // addressDto.setTime(System.currentTimeMillis()); addressDto.setUserId(acodeDto.getUserId()); String imgName="/promoter_" + acodeDto.getUserId() + "_acode.jpg"; AtomicInteger atomicInteger=new AtomicInteger(1); while (1==1) { if(atomicInteger.get()>10){ break; } path = wxUtil.generateAcode("scene=" + acodeDto.getUserId(), "pages/login/login", imgName, "430px"); if(StrUtil.isNotBlank(path)){ break; } log.debug("小程序二维码格式异常,重新生成:{},重试次数:{}",acodeDto.getUserId(),atomicInteger.get()); atomicInteger.getAndIncrement(); } } result.setData(path); return result; } /** * 获取微信用户openId */ @ApiOperation( value = "获取微信openId") @PostMapping("/login/openid") @PassToken public Result getOpenId(@RequestBody UserReq userReq) { //微信小程序传入的code String code = userReq.getCode(); Result result = wxUtil.getOpenId(code); if(result.getCode()==0){ UserInfoVo data = result.getData(); //会话密钥 session_key 是对用户数据进行 加密签名 的密钥。为了应用自身的数据安全,开发者服务器不应该把会话密钥下发到小程序,也不应该对外提供这个密钥。 data.setSessionKey(null); } return result; } @ApiOperation( value = "获取微信手机号") @PostMapping("/login/getWxInfo") @PassToken public Result getWxInfo(@RequestBody GetPhoneNumberDto getPhoneNumberDto) { Result result = wxUtil.getOpenId(getPhoneNumberDto.getCode()); if(result.getCode()==0) { UserInfoVo data = result.getData(); String sessionKey = data.getSessionKey(); byte[] decode = Base64.decode(sessionKey); byte[] decode1 = Base64.decode(getPhoneNumberDto.getEncryptedData()); String s1=null; try { // AES aes = new AES(Mode.CBC, Padding.PKCS5Padding, decode, Base64.decode(getPhoneNumberDto.getIv())); AlgorithmParameterSpec ivSpec = new IvParameterSpec(Base64.decode(getPhoneNumberDto.getIv())); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKeySpec keySpec = new SecretKeySpec(decode, "AES"); cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); s1 =new String(cipher.doFinal(decode1),"UTF-8"); // String s1 = aes.decryptStr(decode1); }catch (Exception e){ try { AlgorithmParameterSpec ivSpec = new IvParameterSpec(Base64.decode(getPhoneNumberDto.getIv())); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); SecretKeySpec keySpec = new SecretKeySpec(decode, "AES"); cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); s1 =new String(cipher.doFinal(decode1),"UTF-8"); } catch (Exception e1) { } } if(s1!=null) { JSONObject jsonObject = JSONUtil.parseObj(s1); String phoneNumber = jsonObject.getStr("phoneNumber"); if (StrUtil.isNotBlank(phoneNumber)) { return Result.success(phoneNumber); } } return Result.error(-1,"获取微信手机号失败"); }else { return Result.error(-1,result.getMsg()); } } /** * 获取微信用户openId */ @ApiOperation( value = "获取app授权openId") @PostMapping("/login/app/openid") @PassToken public Result getAppOpenId(@RequestBody CommonDto commonDto) { Result result=new Result(); String openId = wxUtil.getAppOpenId(commonDto.getExtra()); if(openId!=null){ result.setData(openId); }else{ result.setCode(-1); result.setMsg("获取openId失败"); } return result; } }