Browse Source

feat : 用户登录接口完成, 代码提交

bilingfeng 2 years ago
parent
commit
ab5d8526c8

+ 5 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/constant/RedisKeyConstant.java

@@ -21,4 +21,9 @@ public class RedisKeyConstant {
      * token缓存key
      */
     public static final String TOKEN_INFO_KEY = RedisKeyConstant.REDIS_PREFIX + "token_info";
+
+    /**
+     * 手机验证码缓存key
+     */
+    public static final String SMS_PHONE_KEY = RedisKeyConstant.REDIS_PREFIX + "sms_phone";
 }

+ 17 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/domain/entity/UserLoginLog.java

@@ -62,4 +62,21 @@ public class UserLoginLog {
      * 登录时间
      */
     private LocalDateTime loginTime;
+
+    /**
+     * 构造方法
+     *
+     * @param loginIp : 用户ip
+     * @param user    : 用户信息
+     * @param gameId  : 游戏id
+     */
+    public UserLoginLog(String loginIp, User user, Long gameId) {
+        this.userId = user.getId();
+        this.agentId = user.getAgentId();
+        this.fromDevice = user.getFromDevice();
+        this.deviceId = user.getDeviceId();
+        this.loginIp = loginIp;
+        this.gameId = gameId;
+        this.loginTime = LocalDateTime.now();
+    }
 }

+ 17 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/domain/enums/SmsTypeEnum.java

@@ -3,6 +3,9 @@ package com.zanxiang.sdk.domain.enums;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 
+import java.util.Arrays;
+import java.util.Objects;
+
 /**
  * @author : lingfeng
  * @time : 2022-06-07
@@ -56,4 +59,18 @@ public enum SmsTypeEnum {
      * 描述
      */
     private String describe;
+
+    /**
+     * 根据type获取枚举
+     *
+     * @return : 返回枚举对象
+     */
+    public static SmsTypeEnum getByType(Integer type) {
+        if (type == null) {
+            return null;
+        }
+        return Arrays.stream(SmsTypeEnum.values())
+                .filter(e -> Objects.equals(e.getType(), type))
+                .findFirst().orElse(null);
+    }
 }

+ 1 - 1
game-module/game-sdk/src/main/java/com/zanxiang/sdk/domain/params/CommonParam.java

@@ -11,7 +11,7 @@ public class CommonParam {
     private String token;
 
     @ApiModelProperty("游戏id")
-    private String gameId;
+    private Long gameId;
 
     //==============device 相关===============
     @ApiModelProperty("设备id")

+ 2 - 13
game-module/game-sdk/src/main/java/com/zanxiang/sdk/domain/params/LoginMobileParam.java

@@ -23,22 +23,11 @@ public class LoginMobileParam extends CommonParam {
      * 手机号
      */
     @JsonAlias("sms-mobile")
-    private Long mobile;
+    private String mobile;
 
     /**
      * 验证码
      */
     @JsonAlias("sms-code")
-    private Integer code;
-
-    /**
-     * 重定向地址
-     */
-    @JsonAlias("redirect_url")
-    private String redirectUrl;
-
-    /**
-     * json类型
-     */
-    private String format;
+    private String code;
 }

+ 37 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/domain/params/SmsCheckParam.java

@@ -0,0 +1,37 @@
+package com.zanxiang.sdk.domain.params;
+
+import com.fasterxml.jackson.annotation.JsonAlias;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-06-13
+ * @description : 短信验证码校验参数
+ */
+@Data
+public class SmsCheckParam {
+
+    /**
+     * 验证码类型
+     */
+    @JsonAlias("sms-type")
+    @NotNull(message = "验证码类型不可为空")
+    private Integer type;
+
+    /**
+     * 手机号码
+     */
+    @JsonAlias("sms-mobile")
+    @NotBlank(message = "手机号码不可为空")
+    private String mobile;
+
+    /**
+     * 手机验证码
+     */
+    @JsonAlias("sms-code")
+    @NotBlank(message = "手机验证码不可为空")
+    private String code;
+}

+ 30 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/ISmsService.java

@@ -0,0 +1,30 @@
+package com.zanxiang.sdk.service;
+
+import com.zanxiang.common.domain.ResultVo;
+import com.zanxiang.common.enums.HttpStatusEnum;
+import com.zanxiang.sdk.domain.params.SmsSendParam;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-06-13
+ * @description :
+ */
+public interface ISmsService {
+
+    /**
+     * 发送短信验证码
+     *
+     * @param smsSendParam : 获取短信验证码参数
+     */
+    ResultVo<Void> smsSend(SmsSendParam smsSendParam);
+
+    /**
+     * 校验短信验证码
+     *
+     * @param type   : 短信类型
+     * @param mobile : 手机号
+     * @param code   : 验证码
+     * @return : 返回验证结果
+     */
+    HttpStatusEnum smsCheck(Integer type, String mobile, String code);
+}

+ 19 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/IUserLoginLogService.java

@@ -0,0 +1,19 @@
+package com.zanxiang.sdk.service;
+
+import com.zanxiang.sdk.domain.entity.User;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-06-13
+ * @description :
+ */
+public interface IUserLoginLogService {
+
+    /**
+     * 添加用户登录日志
+     *
+     * @param user   : 用户信息
+     * @param gameId : 游戏id
+     */
+    void addUserLoginLog(String realIp, User user, Long gameId);
+}

+ 14 - 1
game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/IUserService.java

@@ -4,9 +4,12 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.zanxiang.common.domain.ResultVo;
 import com.zanxiang.sdk.domain.dto.UserDTO;
 import com.zanxiang.sdk.domain.entity.User;
+import com.zanxiang.sdk.domain.params.LoginMobileParam;
 import com.zanxiang.sdk.domain.params.LoginPasswordParam;
 import com.zanxiang.sdk.domain.vo.UserLoginVO;
 
+import javax.servlet.http.HttpServletRequest;
+
 /**
  * @author : lingfeng
  * @time : 2022-06-08
@@ -18,9 +21,19 @@ public interface IUserService extends IService<User> {
      * 用户名密码登录
      *
      * @param userLoginParam : 登录参数
+     * @param request        : HttpServletRequest
      * @return : 返回登录token
      */
-    ResultVo<UserLoginVO> loginPassword(LoginPasswordParam userLoginParam);
+    ResultVo<UserLoginVO> loginPassword(LoginPasswordParam userLoginParam, HttpServletRequest request);
+
+    /**
+     * 手机号登录
+     *
+     * @param loginMobileParam : 手机号登录参数
+     * @param request          : HttpServletRequest
+     * @return : 返回登录信息
+     */
+    ResultVo<UserLoginVO> loginMobile(LoginMobileParam loginMobileParam, HttpServletRequest request);
 
     /**
      * 检查用户手机号是否存在

+ 116 - 3
game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/Impl/SmsServiceImpl.java

@@ -1,11 +1,25 @@
 package com.zanxiang.sdk.service.Impl;
 
+import com.zanxiang.common.domain.ResultVo;
+import com.zanxiang.common.enums.ExpireTimeEnum;
+import com.zanxiang.common.enums.HttpStatusEnum;
+import com.zanxiang.common.utils.StringUtils;
+import com.zanxiang.sdk.constant.RedisKeyConstant;
+import com.zanxiang.sdk.domain.dto.UserDTO;
 import com.zanxiang.sdk.domain.enums.SmsTypeEnum;
 import com.zanxiang.sdk.domain.params.SmsSendParam;
+import com.zanxiang.sdk.service.ISmsService;
+import com.zanxiang.sdk.service.IUserService;
+import com.zanxiang.sdk.utils.RedisUtils;
+import com.zanxiangnet.module.sms.pojo.SendResult;
+import com.zanxiangnet.module.sms.service.impl.AliSmsService;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.util.Objects;
+import java.util.Random;
 
 /**
  * @author : lingfeng
@@ -14,21 +28,120 @@ import java.util.Objects;
  */
 @Slf4j
 @Service
-public class SmsServiceImpl {
+public class SmsServiceImpl implements ISmsService {
+
+    @Autowired
+    private IUserService userService;
+
+    @Autowired
+    private RedisUtils<String> redisUtils;
+
+    @Autowired
+    private AliSmsService aliSmsService;
 
     /**
      * 发送短信验证码
      *
      * @param smsSendParam : 获取短信验证码参数
      */
-    public void smsSend(SmsSendParam smsSendParam) {
+    @Override
+    public ResultVo<Void> smsSend(SmsSendParam smsSendParam) {
         //类型
         Integer type = smsSendParam.getType();
         //手机号码
         String mobile = smsSendParam.getMobile();
+        //根据手机号获取用户信息
+        UserDTO userDTO = userService.getUserInfoByMobile(mobile);
         //找回密码获取
-        if (Objects.equals(type, SmsTypeEnum.SMS_FIND_PWD.getType())){
+        if (Objects.equals(type, SmsTypeEnum.SMS_FIND_PWD.getType())) {
+            //手机号对应用户信息不存在
+            if (userDTO == null) {
+                return new ResultVo<>(HttpStatusEnum.USERNAME_NOT_EXISTS);
+            }
+        }
+        //用户注册获取
+        if (Objects.equals(type, SmsTypeEnum.SMS_REG.getType())) {
+            //判断手机号是否已注册
+            if (userDTO != null) {
+                return new ResultVo<>(HttpStatusEnum.PHONE_IS_REG);
+            }
+        }
+        //验证手机号
+        if (!StringUtils.checkPhone(mobile)) {
+            return new ResultVo<>(HttpStatusEnum.PHONE_ERROR);
+        }
+        //验证类型
+        SmsTypeEnum smsTypeEnum = SmsTypeEnum.getByType(type);
+        if (smsTypeEnum == null) {
+            return new ResultVo<>(HttpStatusEnum.CODE_TYPE_ERROR);
+        }
+        //判断是否已经发送
+        String cache = redisUtils.getCache(this.smsKey(mobile, type));
+        if (Strings.isNotBlank(cache)) {
+            return new ResultVo<>(HttpStatusEnum.PHONE_HAS_SEND);
+        }
+        //发送验证码
+        String randomCode = this.randomCode();
+        SendResult sendResult = aliSmsService.sendCode(randomCode, mobile);
+        //发送成功设置缓存, 时效5分钟
+        if (sendResult.isSuccess()) {
+            redisUtils.setCache(this.smsKey(mobile, type), randomCode, ExpireTimeEnum.FIVE_MIN.getTime());
+        }
+        return new ResultVo<>(HttpStatusEnum.SUCCESS);
+    }
 
+    /**
+     * 校验短信验证码
+     *
+     * @param type   : 短信类型
+     * @param mobile : 手机号
+     * @param code   : 验证码
+     * @return : 返回验证结果
+     */
+    @Override
+    public HttpStatusEnum smsCheck(Integer type, String mobile, String code) {
+        //验证类型
+        SmsTypeEnum smsTypeEnum = SmsTypeEnum.getByType(type);
+        if (smsTypeEnum == null) {
+            return HttpStatusEnum.CODE_TYPE_ERROR;
         }
+        //验证手机号
+        if (!StringUtils.checkPhone(mobile)) {
+            return HttpStatusEnum.PHONE_ERROR;
+        }
+        //获取缓存中的验证码
+        String smsKey = this.smsKey(mobile, type);
+        String cache = redisUtils.getCache(smsKey);
+        //验证码已过期
+        if (Strings.isBlank(cache)) {
+            return HttpStatusEnum.CODE_IS_EXPIRED;
+        }
+        //验证码错误
+        if (!Objects.equals(cache, code)) {
+            return HttpStatusEnum.CODE_ERROR;
+        }
+        //验证成功, 删除缓存
+        redisUtils.deleteCache(smsKey);
+        //返回成功
+        return HttpStatusEnum.SUCCESS;
+    }
+
+    /**
+     * 获取手机验证码
+     */
+    private String randomCode() {
+        Random random = new Random();
+        return String.valueOf(random.nextInt(999999) + 100000);
+    }
+
+    /**
+     * 手机验证码缓存key
+     *
+     * @param mobile : 手机号
+     * @param type   : 短信类型
+     * @return : 返回redis缓存key
+     */
+    private String smsKey(String mobile, Integer type) {
+        return RedisKeyConstant.SMS_PHONE_KEY + "_" + mobile + "_" + type;
     }
 }

+ 31 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/Impl/UserLoginLogServiceImpl.java

@@ -0,0 +1,31 @@
+package com.zanxiang.sdk.service.Impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zanxiang.sdk.domain.entity.User;
+import com.zanxiang.sdk.domain.entity.UserLoginLog;
+import com.zanxiang.sdk.mapper.UserLoginLogMapper;
+import com.zanxiang.sdk.service.IUserLoginLogService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-06-13
+ * @description : 用户登录日志
+ */
+@Slf4j
+@Service
+public class UserLoginLogServiceImpl extends ServiceImpl<UserLoginLogMapper, UserLoginLog> implements IUserLoginLogService {
+
+    /**
+     * 添加用户登录日志
+     *
+     * @param user   : 用户信息
+     * @param gameId : 游戏id
+     */
+    @Override
+    public void addUserLoginLog(String realIp, User user, Long gameId) {
+        UserLoginLog userLoginLog = new UserLoginLog(realIp, user, gameId);
+        super.save(userLoginLog);
+    }
+}

+ 45 - 6
game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/Impl/UserServiceImpl.java

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.zanxiang.common.domain.ResultVo;
 import com.zanxiang.common.enums.HttpStatusEnum;
 import com.zanxiang.common.exception.BaseException;
+import com.zanxiang.common.utils.IpUtils;
 import com.zanxiang.common.utils.StringUtils;
 import com.zanxiang.common.utils.bean.BeanUtils;
 import com.zanxiang.sdk.domain.dto.UserDTO;
@@ -16,13 +17,15 @@ import com.zanxiang.sdk.domain.params.LoginMobileParam;
 import com.zanxiang.sdk.domain.params.LoginPasswordParam;
 import com.zanxiang.sdk.domain.vo.UserLoginVO;
 import com.zanxiang.sdk.mapper.UserMapper;
+import com.zanxiang.sdk.service.ISmsService;
+import com.zanxiang.sdk.service.IUserLoginLogService;
 import com.zanxiang.sdk.service.IUserService;
 import com.zanxiang.sdk.service.IUserTokenService;
-import com.zanxiangnet.module.sms.service.impl.AliSmsService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import javax.servlet.http.HttpServletRequest;
 import java.security.NoSuchAlgorithmException;
 import java.util.Objects;
 
@@ -36,19 +39,23 @@ import java.util.Objects;
 public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
 
     @Autowired
-    private AliSmsService aliSmsService;
+    private IUserTokenService userTokenService;
 
     @Autowired
-    private IUserTokenService userTokenService;
+    private ISmsService smsService;
+
+    @Autowired
+    private IUserLoginLogService userLoginLogService;
 
     /**
      * 用户名密码登录
      *
      * @param userLoginParam : 登录参数
+     * @param request : HttpServletRequest
      * @return : 返回登录token
      */
     @Override
-    public ResultVo<UserLoginVO> loginPassword(LoginPasswordParam userLoginParam) {
+    public ResultVo<UserLoginVO> loginPassword(LoginPasswordParam userLoginParam, HttpServletRequest request) {
         //用户名
         String username = userLoginParam.getUsername();
         //密码
@@ -75,6 +82,10 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IU
         }
         //验证通过, 获取token
         String userToken = userTokenService.getUserToken(user.getId(), user.getDeviceType());
+        //登录的ip
+        String realIp = IpUtils.getRealIp(request);
+        //插入用户登录记录
+        userLoginLogService.addUserLoginLog(realIp, user, userLoginParam.getGameId());
         //构造返回
         return new ResultVo<>(new UserLoginVO(userToken));
     }
@@ -84,10 +95,38 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IU
      * 手机号登录
      *
      * @param loginMobileParam : 手机号登录参数
+     * @param request : HttpServletRequest
      * @return : 返回登录信息
      */
-    public ResultVo<UserLoginVO> loginMobile(LoginMobileParam loginMobileParam) {
-        return null;
+    @Override
+    public ResultVo<UserLoginVO> loginMobile(LoginMobileParam loginMobileParam, HttpServletRequest request) {
+        Integer type = loginMobileParam.getType();
+        String mobile = loginMobileParam.getMobile();
+        String code = loginMobileParam.getCode();
+        //验证码校验
+        HttpStatusEnum httpStatusEnum = smsService.smsCheck(type, mobile, code);
+        //验证不通过, 返回
+        if (!Objects.equals(httpStatusEnum, HttpStatusEnum.SUCCESS)) {
+            return new ResultVo<>(httpStatusEnum);
+        }
+        //获取用户信息
+        User user = super.getOne(new LambdaQueryWrapper<User>().eq(User::getMobile, mobile));
+        //用户信息不存在
+        if (user == null) {
+            return new ResultVo<>(HttpStatusEnum.PHONE_NOT_REG);
+        }
+        //判断账号是否停用
+        if (Objects.equals(AccountStatusEnum.FROZEN_STATUS.getStatus(), user.getStatus())) {
+            return new ResultVo<>(HttpStatusEnum.ACCOUNT_HALT);
+        }
+        //验证通过, 获取token
+        String userToken = userTokenService.getUserToken(user.getId(), user.getDeviceType());
+        //登录的ip
+        String realIp = IpUtils.getRealIp(request);
+        //插入用户登录记录
+        userLoginLogService.addUserLoginLog(realIp, user, loginMobileParam.getGameId());
+        //构造返回
+        return new ResultVo<>(new UserLoginVO(userToken));
     }
 
     /**