Ver Fonte

Merge remote-tracking branch 'origin/dev0.0.1' into dev0.0.1

xufeng há 2 anos atrás
pai
commit
a9e4ea5cd2
30 ficheiros alterados com 1760 adições e 402 exclusões
  1. 6 0
      game-module/game-sdk/pom.xml
  2. 68 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/common/constant/ApiUrlConstant.java
  3. 6 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/common/constant/RedisKeyConstant.java
  4. 54 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/common/util/RedisUtils.java
  5. 132 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/common/util/RegisterUtils.java
  6. 91 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/controller/RegisterLoginController.java
  7. 8 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/controller/SmsController.java
  8. 7 30
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/controller/UserController.java
  9. 106 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/domain/dto/UserOauthDTO.java
  10. 24 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/domain/params/QqLoginCallbackParam.java
  11. 12 26
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/domain/params/UpdatePasswordParam.java
  12. 24 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/domain/params/UserDetailParam.java
  13. 2 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/domain/vo/UserLoginVO.java
  14. 61 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/domain/vo/UserVO.java
  15. 4 2
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/filter/CORSFilter.java
  16. 19 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/IQqApiService.java
  17. 84 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/IRegisterLoginService.java
  18. 9 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/ISmsService.java
  19. 31 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/IUserOauthService.java
  20. 12 40
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/IUserService.java
  21. 11 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/IUserTokenService.java
  22. 19 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/IVxApiService.java
  23. 443 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/Impl/RegisterLoginServiceImpl.java
  24. 31 1
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/Impl/SmsServiceImpl.java
  25. 62 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/Impl/UserOauthServiceImpl.java
  26. 42 303
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/Impl/UserServiceImpl.java
  27. 19 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/Impl/UserTokenServiceImpl.java
  28. 146 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/Impl/auth/QqApiServiceImpl.java
  29. 221 0
      game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/Impl/auth/VxApiServiceImpl.java
  30. 6 0
      game-module/game-sdk/src/main/resources/bootstrap.yml

+ 6 - 0
game-module/game-sdk/pom.xml

@@ -63,6 +63,12 @@
             <artifactId>weixin-popular</artifactId>
             <version>2.8.16</version>
         </dependency>
+        <!-- 谷歌http工具类 -->
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.8.0.M1</version>
+        </dependency>
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-bootstrap</artifactId>

+ 68 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/common/constant/ApiUrlConstant.java

@@ -0,0 +1,68 @@
+package com.zanxiang.sdk.common.constant;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-06-21
+ * @description : 第三方api通用url
+ */
+public class ApiUrlConstant {
+
+    //-------------------- 扣扣api --------------------
+
+    /**
+     * QQ授权重定向地址
+     */
+    public static final String QQ_AUTH_URL = "https://graph.qq.com/oauth2.0/authorize";
+
+    /**
+     * QQ授权回调地址
+     */
+    public static final String QQ_REDIRECT_URL = "http://127.0.0.1:8080/qqCallback";
+
+    /**
+     * QQ网页获取授权token地址
+     */
+    public static final String QQ_WEB_TOKEN_URL = "https://graph.qq.com/oauth2.0/token";
+
+    /**
+     * QQ获取用户openId地址
+     */
+    public static final String QQ_USER_OPENID_URL = "https://graph.qq.com/oauth2.0/me";
+
+    /**
+     * QQ获取用户信息地址
+     */
+    public static final String QQ_USER_INFO_URL = "https://graph.qq.com/user/get_user_info";
+
+    //-------------------- 微信api --------------------
+
+    /**
+     * VX授权重定向地址
+     */
+    public static final String VX_AUTH_URL = "https://open.weixin.qq.com/connect/qrconnect";
+
+    /**
+     * VX授权回调地址
+     */
+    public static final String VX_REDIRECT_URL = "http://127.0.0.1:8080/vxCallback";
+
+    /**
+     * VX网页获取授权token地址
+     */
+    public static final String VX_WEB_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token";
+
+    /**
+     * VX网页获取刷新token地址
+     */
+    public static final String VX_WEB_TOKEN_REFRESH_URL = "https://api.weixin.qq.com/sns/oauth2/refresh_token";
+
+    /**
+     * VX网页检测token地址
+     */
+    public static final String VX_WEB_TOKEN_CHECK_URL = "https://api.weixin.qq.com/sns/auth";
+
+    /**
+     * VX网页授权获取用户信息
+     */
+    public static final String VX_WEB_USER_INFO_URL = "https://api.weixin.qq.com/sns/userinfo";
+}

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

@@ -26,4 +26,10 @@ public class RedisKeyConstant {
      * 手机验证码缓存key
      */
     public static final String SMS_PHONE_KEY = RedisKeyConstant.REDIS_PREFIX + "sms_phone";
+
+    /**
+     * 手机验证码缓存key
+     */
+    public static final String AUTH_STATE_KEY = RedisKeyConstant.REDIS_PREFIX + "auth_state";
+
 }

+ 54 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/common/util/RedisUtils.java

@@ -3,6 +3,7 @@ package com.zanxiang.sdk.common.util;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.SetOperations;
 import org.springframework.data.redis.core.ValueOperations;
 import org.springframework.stereotype.Component;
 
@@ -91,4 +92,57 @@ public class RedisUtils<T> {
         }
         return false;
     }
+
+    /**
+     * set集合添加元素
+     *
+     * @param key : 缓存key
+     * @param t   : 需要添加的元素
+     * @return : 返回是否添加成功
+     */
+    public boolean addToSet(String key, T... t) {
+        try {
+            SetOperations<String, T> setOperations = redisTemplate.opsForSet();
+            Long add = setOperations.add(key, t);
+            return add != null && add >= 1;
+        } catch (Exception e) {
+            log.error("Set添加失败,key : " + key + " e :" + e.toString());
+        }
+        return false;
+    }
+
+    /**
+     * set集合删除元素
+     *
+     * @param key : 缓存key
+     * @param t   : 需要删除的元素
+     * @return : 返回是否删除成功
+     */
+    public boolean removeOfSet(String key, T... t) {
+        try {
+            SetOperations<String, T> setOperations = redisTemplate.opsForSet();
+            Long remove = setOperations.remove(key, t);
+            return remove != null && remove >= 1;
+        } catch (Exception e) {
+            log.error("Set删除失败,key : " + key + " e :" + e.toString());
+        }
+        return false;
+    }
+
+    /**
+     * 判断元素是否存在于set集合
+     *
+     * @param key : 缓存key
+     * @param t   : 需要判断的元素
+     * @return : 判断元素是否存在
+     */
+    public boolean isMemberInSet(String key, T t) {
+        try {
+            SetOperations<String, T> setOperations = redisTemplate.opsForSet();
+            return setOperations.isMember(key, t);
+        } catch (Exception e) {
+            log.error("Set元素是否存在,key : " + key + " e :" + e.toString());
+        }
+        return false;
+    }
 }

+ 132 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/common/util/RegisterUtils.java

@@ -0,0 +1,132 @@
+package com.zanxiang.sdk.common.util;
+
+import com.alibaba.nacos.common.utils.MD5Utils;
+import com.zanxiang.common.enums.HttpStatusEnum;
+import com.zanxiang.common.exception.BaseException;
+import org.apache.logging.log4j.util.Strings;
+
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-06-22
+ * @description : 用户注册工具类
+ */
+public class RegisterUtils {
+
+    /**
+     * 密码加密盐值
+     */
+    private static final String CMF_PASSWORD_SALT = "ZX_PASSWORD_SALT";
+
+    /**
+     * 用户名最小长度
+     */
+    private static final int USER_NAME_LENGTH_MIN = 4;
+
+    /**
+     * 用户名最大长度
+     */
+    private static final int USER_NAME_LENGTH_MAX = 32;
+
+    /**
+     * 密码最小长度
+     */
+    private static final int PASSWORD_LENGTH_MIN = 6;
+
+    /**
+     * 密码最大长度
+     */
+    private static final int PASSWORD_LENGTH_MAX = 32;
+
+    /**
+     * 用户名合规检测
+     *
+     * @param userName : 用户名验证
+     * @return : 返回验证结果
+     */
+    public static HttpStatusEnum checkUserName(String userName) {
+        if (Strings.isBlank(userName)) {
+            return HttpStatusEnum.USERNAME_EMPTY;
+        }
+        //用户名长度验证
+        if (userName.length() < USER_NAME_LENGTH_MIN) {
+            return HttpStatusEnum.USERNAME_TOO_SHORT;
+        }
+        if (userName.length() > USER_NAME_LENGTH_MAX) {
+            return HttpStatusEnum.USERNAME_TOO_LONG;
+        }
+//        boolean matches = username.matches("[\\s]");
+//        if (!username.matches("/^[a-zA-Z0-9]+$/i")){
+//            return HttpStatusEnum.USERNAME_BAD_CHAR;
+//        }
+//        //合规验证
+//        if (username.matches("/\\s/") || username.matches("/^ZN/i") || !username.matches("^[a-zA-Z0-9]+$")) {
+//            return HttpStatusEnum.USERNAME_BAD_CHAR;
+//        }
+//        //用户名不是手机号, 用户名只能是数字和字母
+//        if (!StringUtils.checkPhone(username) && !username.matches("/^(?![^a-zA-Z]+$).{4,32}$/")) {
+//            return HttpStatusEnum.USERNAME_BAD_CHAR;
+//        }
+        //密码验证
+        return HttpStatusEnum.SUCCESS;
+    }
+
+    /**
+     * 密码合规检测
+     *
+     * @param password : 密码验证
+     * @return : 返回验证结果
+     */
+    public static HttpStatusEnum checkPassword(String password) {
+        if (Strings.isBlank(password)) {
+            return HttpStatusEnum.PASSWORD_EMPTY;
+        }
+        if (password.length() < PASSWORD_LENGTH_MIN) {
+            return HttpStatusEnum.PASSWORD_TOO_SHORT;
+        }
+        if (password.length() > PASSWORD_LENGTH_MAX) {
+            return HttpStatusEnum.PASSWORD_TOO_LONG;
+        }
+//        if (password.matches("/\\s/") || !password.matches("A([a-zA-Z0-9~`#$%^&*!@.,()\\\\{}|:;?<>]){6,32}$")) {
+//            return HttpStatusEnum.PASSWORD_BAD_CHAR;
+//        }
+        return HttpStatusEnum.SUCCESS;
+    }
+
+    /**
+     * 用户昵称合规检测
+     *
+     * @param nickname : 用户昵称
+     * @return : 检测结果
+     */
+    private HttpStatusEnum checkNickname(String nickname) {
+        if (Strings.isBlank(nickname)) {
+            return HttpStatusEnum.NICKNAME_EMPTY;
+        }
+        if (nickname.length() < 4) {
+            return HttpStatusEnum.NICKNAME_TOO_SHORT;
+        }
+        if (nickname.length() > 32) {
+            return HttpStatusEnum.NICKNAME_TOO_LONG;
+        }
+        //敏感词检测
+        return HttpStatusEnum.SUCCESS;
+    }
+
+    /**
+     * 密码cfm加密
+     *
+     * @param password : 密码
+     * @return : 返回加密完的密码
+     */
+    public static String cmfPassword(String password) {
+        String passwordSalt = password + CMF_PASSWORD_SALT;
+        try {
+            return "###" + MD5Utils.md5Hex(MD5Utils.md5Hex(passwordSalt.getBytes()).getBytes());
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+            throw new BaseException("密码加密异常");
+        }
+    }
+}

+ 91 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/controller/RegisterLoginController.java

@@ -0,0 +1,91 @@
+package com.zanxiang.sdk.controller;
+
+import com.zanxiang.common.domain.ResultVo;
+import com.zanxiang.sdk.domain.params.*;
+import com.zanxiang.sdk.domain.vo.UserLoginVO;
+import com.zanxiang.sdk.service.IRegisterLoginService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-06-21
+ * @description : 用户注册登录
+ */
+@Api(tags = "注册登录接口")
+@CrossOrigin
+@RestController
+@RequestMapping(value = "/api/user")
+public class RegisterLoginController {
+
+    @Autowired
+    private IRegisterLoginService registerPassword;
+
+    @ApiOperation(value = "用户普通注册")
+    @PostMapping("/register/password")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = UserLoginVO.class)})
+    public ResultVo<UserLoginVO> registerPassword(@Validated @RequestBody RegisterPasswordParam registerPasswordParam,
+                                                  HttpServletRequest request) {
+        return registerPassword.registerPassword(registerPasswordParam, request);
+    }
+
+    @ApiOperation(value = "用户手机注册")
+    @PostMapping("/register/mobile")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = UserLoginVO.class)})
+    public ResultVo<UserLoginVO> registerMobile(@Validated @RequestBody RegisterMobileParam registerMobileParam,
+                                                HttpServletRequest request) {
+        return registerPassword.registerMobile(registerMobileParam, request);
+    }
+
+    @ApiOperation(value = "用户名密码登录")
+    @PostMapping("/login/password")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = UserLoginVO.class)})
+    public ResultVo<UserLoginVO> loginPassword(@Validated @RequestBody LoginPasswordParam userLoginParam, HttpServletRequest request) {
+        return registerPassword.loginPassword(userLoginParam, request);
+    }
+
+    @ApiOperation(value = "用户手机号登录")
+    @PostMapping("/login/mobile")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = UserLoginVO.class)})
+    public ResultVo<UserLoginVO> loginMobile(@Validated @RequestBody LoginMobileParam loginMobileParam, HttpServletRequest request) {
+        return registerPassword.loginMobile(loginMobileParam, request);
+    }
+
+    @ApiOperation(value = "用户QQ授权登录")
+    @GetMapping("/register/login/qq")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = UserLoginVO.class)})
+    public ResultVo qqLoginAuth(HttpServletResponse response) {
+        registerPassword.qqLoginAuth(response);
+        return ResultVo.ok();
+    }
+
+    @ApiOperation(value = "用户QQ授权登录回调接口")
+    @PostMapping("/register/login/qq/call/back")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = UserLoginVO.class)})
+    public ResultVo<UserLoginVO> qqLoginCallback(@Validated @RequestBody QqLoginCallbackParam qqLoginCallbackParam, HttpServletRequest request) {
+        return registerPassword.qqLoginCallback(qqLoginCallbackParam, request);
+    }
+
+    @ApiOperation(value = "用户微信授权登录")
+    @GetMapping("/register/login/vx")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = UserLoginVO.class)})
+    public ResultVo getUserDetail(HttpServletResponse response) {
+        registerPassword.vxLoginAuth(response);
+        return ResultVo.ok();
+    }
+
+    @ApiOperation(value = "用户微信授权登录回调接口")
+    @PostMapping("/register/login/vx/call/back")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = UserLoginVO.class)})
+    public ResultVo<UserLoginVO> vxLoginCallback(@Validated @RequestBody QqLoginCallbackParam qqLoginCallbackParam, HttpServletRequest request) {
+        return registerPassword.vxLoginCallback(qqLoginCallbackParam, request);
+    }
+}

+ 8 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/controller/SmsController.java

@@ -1,6 +1,7 @@
 package com.zanxiang.sdk.controller;
 
 import com.zanxiang.common.domain.ResultVo;
+import com.zanxiang.sdk.domain.params.SmsCheckParam;
 import com.zanxiang.sdk.domain.params.SmsSendParam;
 import com.zanxiang.sdk.domain.vo.UserLoginVO;
 import com.zanxiang.sdk.service.ISmsService;
@@ -32,4 +33,11 @@ public class SmsController {
     public ResultVo<Boolean> smsSend(@Validated @RequestBody SmsSendParam smsSendParam) {
         return smsService.smsSend(smsSendParam);
     }
+
+    @ApiOperation(value = "验证码校验")
+    @PostMapping("/check/msg")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = UserLoginVO.class)})
+    public ResultVo<String> smsCheck(@Validated @RequestBody SmsCheckParam smsCheckParam) {
+        return smsService.smsCheck(smsCheckParam);
+    }
 }

+ 7 - 30
game-module/game-sdk/src/main/java/com/zanxiang/sdk/controller/UserController.java

@@ -28,40 +28,17 @@ public class UserController {
     @Autowired
     private IUserService userService;
 
-    @ApiOperation(value = "用户普通注册")
-    @PostMapping("/register/password")
-    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = UserLoginVO.class)})
-    public ResultVo<UserLoginVO> registerPassword(@Validated @RequestBody RegisterPasswordParam registerPasswordParam,
-                                                  HttpServletRequest request) {
-        return userService.registerPassword(registerPasswordParam, request);
-    }
-
-    @ApiOperation(value = "用户手机注册")
-    @PostMapping("/register/mobile")
-    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = UserLoginVO.class)})
-    public ResultVo<UserLoginVO> registerMobile(@Validated @RequestBody RegisterMobileParam registerMobileParam,
-                                                HttpServletRequest request) {
-        return userService.registerMobile(registerMobileParam, request);
-    }
-
-    @ApiOperation(value = "用户名密码登录")
-    @PostMapping("/login/password")
-    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = UserLoginVO.class)})
-    public ResultVo<UserLoginVO> loginPassword(@Validated @RequestBody LoginPasswordParam userLoginParam, HttpServletRequest request) {
-        return userService.loginPassword(userLoginParam, request);
-    }
-
-    @ApiOperation(value = "用户手机号登录")
-    @PostMapping("/login/mobile")
-    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = UserLoginVO.class)})
-    public ResultVo<UserLoginVO> loginMobile(@Validated @RequestBody LoginMobileParam loginMobileParam, HttpServletRequest request) {
-        return userService.loginMobile(loginMobileParam, request);
-    }
-
     @ApiOperation(value = "用户重置密码")
     @PostMapping("/update/password")
     @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = UserLoginVO.class)})
     public ResultVo updatePassword(@Validated @RequestBody UpdatePasswordParam updatePasswordParam) {
         return userService.updatePassword(updatePasswordParam);
     }
+
+    @ApiOperation(value = "用户获取信息详情")
+    @PostMapping("/get/user/detail")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = UserLoginVO.class)})
+    public ResultVo getUserDetail(@Validated @RequestBody UserDetailParam userDetailParam) {
+        return userService.getUserDetail(userDetailParam);
+    }
 }

+ 106 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/domain/dto/UserOauthDTO.java

@@ -0,0 +1,106 @@
+package com.zanxiang.sdk.domain.dto;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-06-21
+ * @description : 用户授权信息
+ */
+@Data
+@Builder
+public class UserOauthDTO {
+
+    /**
+     * 主键id
+     */
+    private Long id;
+
+    /**
+     * 关联的本站用户id
+     */
+    private Long userId;
+
+    /**
+     * 用户来源(微信/QQ/华为)
+     */
+    private String from;
+
+    /**
+     * 配置ID
+     */
+    private String confId;
+
+    /**
+     * 第三方open id
+     */
+    private String openid;
+
+    /**
+     * 第三方秘钥
+     */
+    private String accessToken;
+
+    /**
+     * 第三方唯一用户id
+     */
+    private String unionid;
+
+    /**
+     * 第三方昵称
+     */
+    private String nickname;
+
+    /**
+     * 国家
+     */
+    private String country;
+
+    /**
+     * 省份
+     */
+    private String province;
+
+    /**
+     * 城市
+     */
+    private String city;
+
+    /**
+     * 1 男 2 女 3 未知
+     */
+    private Boolean six;
+
+    /**
+     * 头像
+     */
+    private String avatar;
+
+    /**
+     * access_token过期时间
+     */
+    private Long expiresIn;
+
+    /**
+     * 扩展信息
+     */
+    private String more;
+
+    /**
+     * 最后登录ip
+     */
+    private String lastLoginIp;
+
+    /**
+     * 最后登录时间
+     */
+    private Long lastLoginTime;
+
+    /**
+     * 绑定时间
+     */
+    private LocalDateTime createTime;
+}

+ 24 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/domain/params/QqLoginCallbackParam.java

@@ -0,0 +1,24 @@
+package com.zanxiang.sdk.domain.params;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-06-21
+ * @description : QQ授权回调参数
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class QqLoginCallbackParam extends CommonParam{
+
+    /**
+     * 授权code
+     */
+    private String code;
+
+    /**
+     * 接口密钥
+     */
+    private String state;
+}

+ 12 - 26
game-module/game-sdk/src/main/java/com/zanxiang/sdk/domain/params/UpdatePasswordParam.java

@@ -3,6 +3,7 @@ package com.zanxiang.sdk.domain.params;
 import com.fasterxml.jackson.annotation.JsonAlias;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
+import lombok.EqualsAndHashCode;
 
 import javax.validation.constraints.NotBlank;
 
@@ -12,14 +13,23 @@ import javax.validation.constraints.NotBlank;
  * @description : 修改密码参数
  */
 @Data
-public class UpdatePasswordParam {
+@EqualsAndHashCode(callSuper = true)
+public class UpdatePasswordParam extends CommonParam{
+
+    /**
+     * 用户token
+     */
+    @ApiModelProperty(notes = "token")
+    @JsonAlias("verify_token")
+    @NotBlank(message = "注册用户名字不可为空")
+    private String token;
 
     /**
      * 用户名
      */
     @ApiModelProperty(notes = "用户名")
     @JsonAlias("mem-username")
-    @NotBlank(message = "注册用户名字不可为空")
+    @NotBlank(message = "用户名字不可为空")
     private String username;
 
     /**
@@ -29,28 +39,4 @@ public class UpdatePasswordParam {
     @NotBlank(message = "新密码不可为空")
     @JsonAlias("mem-password")
     private String password;
-
-    /**
-     * 验证码类型
-     */
-    @ApiModelProperty(notes = "验证码类型")
-    @NotBlank(message = "验证码类型不可为空")
-    @JsonAlias("sms-type")
-    private Integer type;
-
-    /**
-     * 手机号
-     */
-    @ApiModelProperty(notes = "手机号")
-    @NotBlank(message = "手机号不可为空")
-    @JsonAlias("sms-mobile")
-    private String mobile;
-
-    /**
-     * 验证码
-     */
-    @ApiModelProperty(notes = "验证码")
-    @NotBlank(message = "验证码不可为空")
-    @JsonAlias("sms-code")
-    private String code;
 }

+ 24 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/domain/params/UserDetailParam.java

@@ -0,0 +1,24 @@
+package com.zanxiang.sdk.domain.params;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-06-17
+ * @description : 用户详情参数
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class UserDetailParam extends CommonParam {
+
+    /**
+     * 用户token
+     */
+    @ApiModelProperty(notes = "token")
+    @NotBlank(message = "注册用户名字不可为空")
+    private String token;
+}

+ 2 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/domain/vo/UserLoginVO.java

@@ -1,5 +1,6 @@
 package com.zanxiang.sdk.domain.vo;
 
+import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 /**
@@ -13,6 +14,7 @@ public class UserLoginVO {
     /**
      * 登录授权的token
      */
+    @ApiModelProperty(notes = "登录授权的token")
     private String token;
 
     /**

+ 61 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/domain/vo/UserVO.java

@@ -0,0 +1,61 @@
+package com.zanxiang.sdk.domain.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-06-17
+ * @description : 用户信息
+ */
+@Data
+public class UserVO {
+
+    /**
+     * 用户id
+     */
+    @ApiModelProperty(notes = "用户id")
+    private Long id;
+
+    /**
+     * 用户名
+     */
+    @ApiModelProperty(notes = "用户名")
+    private String username;
+
+    /**
+     * 昵称
+     */
+    @ApiModelProperty(notes = "昵称")
+    private String nickname;
+
+    /**
+     * 注册手机号
+     */
+    @ApiModelProperty(notes = "注册手机号")
+    private String regMobile;
+
+    /**
+     * 注册邮箱
+     */
+    @ApiModelProperty(notes = "注册邮箱")
+    private String regEmail;
+
+    /**
+     * 绑定邮箱
+     */
+    @ApiModelProperty(notes = "绑定邮箱")
+    private String email;
+
+    /**
+     * 绑定手机号码
+     */
+    @ApiModelProperty(notes = "绑定手机号码")
+    private String mobile;
+
+    /**
+     * 头像
+     */
+    @ApiModelProperty(notes = "头像")
+    private String avatar;
+}

+ 4 - 2
game-module/game-sdk/src/main/java/com/zanxiang/sdk/filter/CORSFilter.java

@@ -4,6 +4,7 @@ import org.springframework.context.annotation.Configuration;
 
 import javax.servlet.*;
 import javax.servlet.annotation.WebFilter;
+import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 
@@ -19,11 +20,12 @@ public class CORSFilter implements Filter {
     @Override
     public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
         HttpServletResponse response = (HttpServletResponse) res;
-        response.setHeader("Access-Control-Allow-Origin", "*");
+        HttpServletRequest request = (HttpServletRequest) req;
+        response.setHeader("Access-Control-Allow-Origin", request.getHeader("origin"));
         response.setHeader("Access-Control-Allow-Credentials", "true");
         response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT, OPTION");
         response.setHeader("Access-Control-Max-Age", "3600");
-        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
+        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, cookie, token");
         chain.doFilter(req, res);
     }
 

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

@@ -0,0 +1,19 @@
+package com.zanxiang.sdk.service;
+
+import java.util.Map;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-06-21
+ * @description :
+ */
+public interface IQqApiService {
+
+    /**
+     * QQ授权获取用户信息
+     *
+     * @param code : 前端授权code
+     * @return : 返回用户信息
+     */
+    Map<String, String> qqAuthUserInfo(String code);
+}

+ 84 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/IRegisterLoginService.java

@@ -0,0 +1,84 @@
+package com.zanxiang.sdk.service;
+
+import com.zanxiang.common.domain.ResultVo;
+import com.zanxiang.sdk.domain.params.*;
+import com.zanxiang.sdk.domain.vo.UserLoginVO;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-06-22
+ * @description :
+ */
+public interface IRegisterLoginService {
+
+    /**
+     * QQ授权登录
+     *
+     * @param response : 返回体
+     */
+    void qqLoginAuth(HttpServletResponse response);
+
+    /**
+     * QQ授权登录回调
+     *
+     * @param qqLoginCallbackParam : 回调参数
+     * @param request              : request
+     * @return : 返回登录token
+     */
+    ResultVo<UserLoginVO> qqLoginCallback(QqLoginCallbackParam qqLoginCallbackParam, HttpServletRequest request);
+
+    /**
+     * 微信授权登录
+     *
+     * @param response : 返回体
+     */
+    void vxLoginAuth(HttpServletResponse response);
+
+    /**
+     * 微信回调方法
+     *
+     * @param qqLoginCallbackParam : 回调参数
+     * @param request              : request
+     * @return : 返回登录token
+     */
+    ResultVo<UserLoginVO> vxLoginCallback(QqLoginCallbackParam qqLoginCallbackParam, HttpServletRequest request);
+
+    /**
+     * 用户名密码注册
+     *
+     * @param registerPasswordParam : 用户名密码注册参数
+     * @param request               : request
+     * @return : 返回注册结果
+     */
+    ResultVo<UserLoginVO> registerPassword(RegisterPasswordParam registerPasswordParam, HttpServletRequest request);
+
+    /**
+     * 手机注册
+     *
+     * @param registerMobileParam : 手机注册参数
+     * @param request             : HttpServletRequest
+     * @return : 返回注册结果
+     */
+    ResultVo<UserLoginVO> registerMobile(RegisterMobileParam registerMobileParam, HttpServletRequest request);
+
+    /**
+     * 用户名密码登录
+     *
+     * @param userLoginParam : 登录参数
+     * @param request        : HttpServletRequest
+     * @return : 返回登录token
+     */
+    ResultVo<UserLoginVO> loginPassword(LoginPasswordParam userLoginParam, HttpServletRequest request);
+
+    /**
+     * 手机号登录
+     *
+     * @param loginMobileParam : 手机号登录参数
+     * @param request          : HttpServletRequest
+     * @return : 返回登录信息
+     */
+    ResultVo<UserLoginVO> loginMobile(LoginMobileParam loginMobileParam, HttpServletRequest request);
+}

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

@@ -2,6 +2,7 @@ package com.zanxiang.sdk.service;
 
 import com.zanxiang.common.domain.ResultVo;
 import com.zanxiang.common.enums.HttpStatusEnum;
+import com.zanxiang.sdk.domain.params.SmsCheckParam;
 import com.zanxiang.sdk.domain.params.SmsSendParam;
 
 /**
@@ -18,6 +19,14 @@ public interface ISmsService {
      */
     ResultVo<Boolean> smsSend(SmsSendParam smsSendParam);
 
+    /**
+     * 前端校验短信验证码
+     *
+     * @param smsCheckParam : 参数
+     * @return : 返回验证结果和token
+     */
+    ResultVo<String> smsCheck(SmsCheckParam smsCheckParam);
+
     /**
      * 校验短信验证码
      *

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

@@ -0,0 +1,31 @@
+package com.zanxiang.sdk.service;
+
+import com.zanxiang.mybatis.entity.User;
+import com.zanxiang.sdk.domain.dto.UserOauthDTO;
+
+import java.util.Map;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-06-21
+ * @description : 用户第三方授权信息
+ */
+public interface IUserOauthService {
+
+    /**
+     * 根据openid查询用户授权信息
+     *
+     * @param openId : 用户第三方授权信息
+     * @return : 返回用户授权信息
+     */
+    UserOauthDTO getUserOauthByOpenId(String openId);
+
+    /**
+     * 创建用户授权信息
+     *
+     * @param user : 用户信息
+     * @param map  : 第三方用户信息
+     * @return : 返回用户授权信息
+     */
+    UserOauthDTO createUserOauth(User user, Map<String, String> map);
+}

+ 12 - 40
game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/IUserService.java

@@ -4,10 +4,9 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.zanxiang.common.domain.ResultVo;
 import com.zanxiang.mybatis.entity.User;
 import com.zanxiang.sdk.domain.dto.UserDTO;
-import com.zanxiang.sdk.domain.params.*;
-import com.zanxiang.sdk.domain.vo.UserLoginVO;
-
-import javax.servlet.http.HttpServletRequest;
+import com.zanxiang.sdk.domain.params.UpdatePasswordParam;
+import com.zanxiang.sdk.domain.params.UserDetailParam;
+import com.zanxiang.sdk.domain.vo.UserVO;
 
 /**
  * @author : lingfeng
@@ -16,41 +15,6 @@ import javax.servlet.http.HttpServletRequest;
  */
 public interface IUserService extends IService<User> {
 
-    /**
-     * 普通注册
-     *
-     * @param registerPasswordParam : 用户名密码注册参数
-     * @return : 返回注册结果
-     */
-    ResultVo<UserLoginVO> registerPassword(RegisterPasswordParam registerPasswordParam, HttpServletRequest request);
-
-    /**
-     * 手机注册
-     *
-     * @param registerMobileParam : 手机注册参数
-     * @param request             : HttpServletRequest
-     * @return : 返回注册结果
-     */
-    ResultVo<UserLoginVO> registerMobile(RegisterMobileParam registerMobileParam, HttpServletRequest request);
-
-    /**
-     * 用户名密码登录
-     *
-     * @param userLoginParam : 登录参数
-     * @param request        : HttpServletRequest
-     * @return : 返回登录token
-     */
-    ResultVo<UserLoginVO> loginPassword(LoginPasswordParam userLoginParam, HttpServletRequest request);
-
-    /**
-     * 手机号登录
-     *
-     * @param loginMobileParam : 手机号登录参数
-     * @param request          : HttpServletRequest
-     * @return : 返回登录信息
-     */
-    ResultVo<UserLoginVO> loginMobile(LoginMobileParam loginMobileParam, HttpServletRequest request);
-
     /**
      * 用户重置密码
      *
@@ -60,7 +24,15 @@ public interface IUserService extends IService<User> {
     ResultVo updatePassword(UpdatePasswordParam updatePasswordParam);
 
     /**
-     * 检查用户手机号是否存在
+     * 获取用户信息
+     *
+     * @param userDetailParam : 用户详情参数
+     * @return : 返回用户信息
+     */
+    ResultVo<UserVO> getUserDetail(UserDetailParam userDetailParam);
+
+    /**
+     * 根据手机号获取用户信息
      *
      * @param mobile : 用户手机号
      * @return : 返回用户信息

+ 11 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/IUserTokenService.java

@@ -1,6 +1,7 @@
 package com.zanxiang.sdk.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.common.enums.HttpStatusEnum;
 import com.zanxiang.mybatis.entity.UserToken;
 import com.zanxiang.sdk.domain.dto.UserTokenDTO;
 
@@ -29,6 +30,16 @@ public interface IUserTokenService extends IService<UserToken> {
      */
     UserTokenDTO getTokenInfoByUserDevice(Long userId, String deviceType);
 
+    /**
+     * 用户token校验
+     *
+     * @param token      : 用户token
+     * @param userId     : 用户id
+     * @param deviceType : 设备类型
+     * @return : 返回token校验结果
+     */
+    HttpStatusEnum checkUserToken(String token, Long userId, String deviceType);
+
     /**
      * 获取用户token
      *

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

@@ -0,0 +1,19 @@
+package com.zanxiang.sdk.service;
+
+import java.util.Map;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-06-21
+ * @description : 微信授权api
+ */
+public interface IVxApiService {
+
+    /**
+     * QQ授权获取用户信息
+     *
+     * @param code : 前端授权code
+     * @return : 返回用户信息
+     */
+    Map<String, String> vxAuthUserInfo(String code);
+}

+ 443 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/Impl/RegisterLoginServiceImpl.java

@@ -0,0 +1,443 @@
+package com.zanxiang.sdk.service.Impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.zanxiang.common.domain.ResultVo;
+import com.zanxiang.common.enums.AccountStatusEnum;
+import com.zanxiang.common.enums.HttpStatusEnum;
+import com.zanxiang.common.exception.BaseException;
+import com.zanxiang.common.text.UUID;
+import com.zanxiang.common.utils.IpUtils;
+import com.zanxiang.common.utils.JsonUtil;
+import com.zanxiang.common.utils.StringUtils;
+import com.zanxiang.common.utils.URIUtil;
+import com.zanxiang.mybatis.entity.User;
+import com.zanxiang.sdk.common.constant.ApiUrlConstant;
+import com.zanxiang.sdk.common.constant.RedisKeyConstant;
+import com.zanxiang.sdk.common.util.RedisUtils;
+import com.zanxiang.sdk.common.util.RegisterUtils;
+import com.zanxiang.sdk.domain.dto.UserOauthDTO;
+import com.zanxiang.sdk.domain.params.*;
+import com.zanxiang.sdk.domain.vo.UserLoginVO;
+import com.zanxiang.sdk.service.*;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-06-22
+ * @description : 注册登录逻辑
+ */
+@Slf4j
+@Service
+public class RegisterLoginServiceImpl implements IRegisterLoginService {
+
+    @Autowired
+    private RedisUtils<String> redisUtils;
+
+    @Autowired
+    private IQqApiService qqApiService;
+
+    @Autowired
+    private IVxApiService vxApiService;
+
+    @Autowired
+    private IUserOauthService userOauthService;
+
+    @Autowired
+    private IUserTokenService userTokenService;
+
+    @Autowired
+    private IUserLoginLogService userLoginLogService;
+
+    @Autowired
+    private IUserService userService;
+
+    @Autowired
+    private ISmsService smsService;
+
+    @Autowired
+    private IWordCheckService wordCheckService;
+
+    /**
+     * QQ开发者应用id
+     */
+    @Value("${auth.qq-appId}")
+    private String qqAppId;
+
+    /**
+     * 微信开发者应用id
+     */
+    @Value("${auth.vx-appId}")
+    private String vxAppId;
+
+    /**
+     * QQ授权注册登录
+     *
+     * @param response : 返回体
+     */
+    @Override
+    public void qqLoginAuth(HttpServletResponse response) {
+        //获取state
+        String state = this.getState();
+        //传递参数
+        Map<String, String> paramMap = new HashMap<>(4);
+        paramMap.put("response_type", "code");
+        paramMap.put("client_id", qqAppId);
+        paramMap.put("state", state);
+        paramMap.put("redirect_uri", ApiUrlConstant.QQ_REDIRECT_URL);
+        //重定向到QQ授权页面
+        try {
+            response.sendRedirect(URIUtil.fillUrlParams(ApiUrlConstant.QQ_AUTH_URL, paramMap, Boolean.TRUE));
+        } catch (Exception e) {
+            log.error("QQ授权登录重定向跳转异常");
+            throw new BaseException("QQ授权登录重定向跳转异常");
+        }
+    }
+
+    /**
+     * QQ授权注册登录回调
+     *
+     * @param qqLoginCallbackParam : 回调参数
+     * @param request              : request
+     * @return : 返回登录token
+     */
+    @Override
+    public ResultVo<UserLoginVO> qqLoginCallback(QqLoginCallbackParam qqLoginCallbackParam, HttpServletRequest request) {
+        String code = qqLoginCallbackParam.getCode();
+        String state = qqLoginCallbackParam.getState();
+        String deviceType = qqLoginCallbackParam.getDeviceType();
+        //验证state,如果不一致,可能被CSRF攻击
+        this.checkState(state);
+        //获取用户信息
+        Map<String, String> userInfoMap = qqApiService.qqAuthUserInfo(code);
+        //查询用户授权信息是否存在
+        UserOauthDTO userOauthDTO = userOauthService.getUserOauthByOpenId(userInfoMap.get("openId"));
+        //获取用户信息
+        User user = this.getUserByUserOauth(deviceType, userInfoMap, userOauthDTO);
+        //用户登录成功
+        String userToken = userTokenService.getUserToken(userOauthDTO.getId(), deviceType);
+        //登录的ip
+        String realIp = IpUtils.getRealIp(request);
+        //插入用户登录记录
+        userLoginLogService.addUserLoginLog(realIp, user, qqLoginCallbackParam.getGameId());
+        //移出state
+        redisUtils.removeOfSet(RedisKeyConstant.AUTH_STATE_KEY, state);
+        //构造返回
+        return new ResultVo<>(new UserLoginVO(userToken));
+    }
+
+    /**
+     * 微信授权注册登录
+     *
+     * @param response : 返回体
+     */
+    @Override
+    public void vxLoginAuth(HttpServletResponse response) {
+        //获取state
+        String state = this.getState();
+        //传递参数
+        Map<String, String> paramMap = new HashMap<>(6);
+        paramMap.put("appid", qqAppId);
+        paramMap.put("redirect_uri", URIUtil.encodeURIComponent(ApiUrlConstant.VX_REDIRECT_URL));
+        paramMap.put("response_type", "code");
+        paramMap.put("scope", "snsapi_login");
+        paramMap.put("state", state);
+        paramMap.put("lang", "cn");
+        //重定向到QQ授权页面
+        try {
+            response.sendRedirect(URIUtil.fillUrlParams(ApiUrlConstant.VX_AUTH_URL, paramMap, Boolean.TRUE));
+        } catch (Exception e) {
+            log.error("微信授权登录重定向跳转异常");
+            throw new BaseException("微信授权登录重定向跳转异常");
+        }
+    }
+
+    /**
+     * 微信授权注册登录回调
+     *
+     * @param qqLoginCallbackParam : 回调参数
+     * @param request              : request
+     * @return : 返回登录token
+     */
+    @Override
+    public ResultVo<UserLoginVO> vxLoginCallback(QqLoginCallbackParam qqLoginCallbackParam, HttpServletRequest request) {
+        String deviceType = qqLoginCallbackParam.getDeviceType();
+        String code = qqLoginCallbackParam.getCode();
+        String state = qqLoginCallbackParam.getState();
+        //验证state,如果不一致,可能被CSRF攻击
+        this.checkState(state);
+        //获取用户信息
+        Map<String, String> userInfoMap = vxApiService.vxAuthUserInfo(code);
+        //查询用户授权信息是否存在
+        UserOauthDTO userOauthDTO = userOauthService.getUserOauthByOpenId(userInfoMap.get("openId"));
+        //获取用户信息
+        User user = this.getUserByUserOauth(deviceType, userInfoMap, userOauthDTO);
+        //登录的ip
+        String realIp = IpUtils.getRealIp(request);
+        //用户登录成功
+        String userToken = userTokenService.getUserToken(userOauthDTO.getId(), deviceType);
+        //插入用户登录记录
+        userLoginLogService.addUserLoginLog(realIp, user, qqLoginCallbackParam.getGameId());
+        //移出state
+        redisUtils.removeOfSet(RedisKeyConstant.AUTH_STATE_KEY, state);
+        //构造返回
+        return new ResultVo<>(new UserLoginVO(userToken));
+    }
+
+
+    /**
+     * 用户名密码注册
+     *
+     * @param registerPasswordParam : 用户名密码注册参数
+     * @param request               : request
+     * @return : 返回注册结果
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public ResultVo<UserLoginVO> registerPassword(RegisterPasswordParam registerPasswordParam, HttpServletRequest request) {
+        String username = registerPasswordParam.getUsername();
+        String password = registerPasswordParam.getPassword();
+        //用户名密码校验
+        HttpStatusEnum checkRegisterEnum = this.checkRegister(username, password);
+        if (!Objects.equals(checkRegisterEnum, HttpStatusEnum.SUCCESS)) {
+            return new ResultVo<>(checkRegisterEnum);
+        }
+        //创建用户信息
+        User user = User.builder()
+                .username(registerPasswordParam.getUsername())
+                .password(RegisterUtils.cmfPassword(password))
+                .deviceId(registerPasswordParam.getDeviceId())
+                .deviceType(registerPasswordParam.getDeviceType())
+                .status(AccountStatusEnum.NORMAL_STATUS.getStatus())
+                .createTime(LocalDateTime.now())
+                .updateTime(LocalDateTime.now())
+                .build();
+        userService.save(user);
+        //登录的ip
+        String realIp = IpUtils.getRealIp(request);
+        //插入用户登录记录
+        userLoginLogService.addUserLoginLog(realIp, user, registerPasswordParam.getGameId());
+        //获取token
+        String userToken = userTokenService.getUserToken(user.getId(), registerPasswordParam.getDeviceType());
+        //返回用户token
+        return new ResultVo<>(new UserLoginVO(userToken));
+    }
+
+    /**
+     * 手机号注册
+     *
+     * @param registerMobileParam : 手机注册参数
+     * @param request             : HttpServletRequest
+     * @return : 返回注册结果
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public ResultVo<UserLoginVO> registerMobile(RegisterMobileParam registerMobileParam, HttpServletRequest request) {
+        Integer type = registerMobileParam.getType();
+        String mobile = registerMobileParam.getMobile();
+        String code = registerMobileParam.getCode();
+        String password = registerMobileParam.getPassword();
+        //校验手机验证码
+        HttpStatusEnum codeCheckEnum = smsService.smsCheck(type, mobile, code);
+        if (!Objects.equals(codeCheckEnum, HttpStatusEnum.SUCCESS)) {
+            return new ResultVo<>(codeCheckEnum);
+        }
+        //判断手机号是否已经注册
+        if (userService.count(new LambdaQueryWrapper<User>().eq(User::getMobile, mobile)) > 0) {
+            return new ResultVo<>(HttpStatusEnum.PHONE_IS_REG);
+        }
+        //验证密码是否合规
+        HttpStatusEnum passwordCheckEnum = RegisterUtils.checkPassword(password);
+        if (!Objects.equals(passwordCheckEnum, HttpStatusEnum.SUCCESS)) {
+            return new ResultVo<>(passwordCheckEnum);
+        }
+        //创建用户信息
+        User user = User.builder()
+                .username(mobile)
+                .regMobile(mobile)
+                .mobile(mobile)
+                .password(RegisterUtils.cmfPassword(password))
+                .deviceId(registerMobileParam.getDeviceId())
+                .deviceType(registerMobileParam.getDeviceType())
+                .status(AccountStatusEnum.NORMAL_STATUS.getStatus())
+                .createTime(LocalDateTime.now())
+                .updateTime(LocalDateTime.now())
+                .build();
+        userService.save(user);
+        //获取token
+        String userToken = userTokenService.getUserToken(user.getId(), registerMobileParam.getDeviceType());
+        //登录的ip
+        String realIp = IpUtils.getRealIp(request);
+        //插入用户登录记录
+        userLoginLogService.addUserLoginLog(realIp, user, registerMobileParam.getGameId());
+        //返回用户token
+        return new ResultVo<>(new UserLoginVO(userToken));
+    }
+
+    /**
+     * 用户名密码登录
+     *
+     * @param userLoginParam : 登录参数
+     * @param request        : HttpServletRequest
+     * @return : 返回登录token
+     */
+    @Override
+    public ResultVo<UserLoginVO> loginPassword(LoginPasswordParam userLoginParam, HttpServletRequest request) {
+        //用户名
+        String username = userLoginParam.getUsername();
+        //密码
+        String password = userLoginParam.getPassword();
+        //用户信息
+        User user;
+        //验证用户名是否为手机号
+        if (StringUtils.checkPhone(username)) {
+            user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getMobile, username));
+        } else {
+            user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
+        }
+        //用户信息不存在
+        if (user == null) {
+            return new ResultVo<>(HttpStatusEnum.USERNAME_OR_PASSWORD_ERR);
+        }
+        //判断账号是否停用
+        if (Objects.equals(AccountStatusEnum.FROZEN_STATUS.getStatus(), user.getStatus())) {
+            return new ResultVo<>(HttpStatusEnum.ACCOUNT_HALT);
+        }
+        //验证密码
+        if (!Objects.equals(RegisterUtils.cmfPassword(password), user.getPassword())) {
+            return new ResultVo<>(HttpStatusEnum.USERNAME_OR_PASSWORD_ERR);
+        }
+        //验证通过, 获取token
+        String userToken = userTokenService.getUserToken(user.getId(), userLoginParam.getDeviceType());
+        //登录的ip
+        String realIp = IpUtils.getRealIp(request);
+        //插入用户登录记录
+        userLoginLogService.addUserLoginLog(realIp, user, userLoginParam.getGameId());
+        //构造返回
+        return new ResultVo<>(new UserLoginVO(userToken));
+    }
+
+
+    /**
+     * 手机号登录
+     *
+     * @param loginMobileParam : 手机号登录参数
+     * @param request          : HttpServletRequest
+     * @return : 返回登录信息
+     */
+    @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 = userService.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(), loginMobileParam.getDeviceType());
+        //登录的ip
+        String realIp = IpUtils.getRealIp(request);
+        //插入用户登录记录
+        userLoginLogService.addUserLoginLog(realIp, user, loginMobileParam.getGameId());
+        //构造返回
+        return new ResultVo<>(new UserLoginVO(userToken));
+    }
+
+    /**
+     * 根据用户授权信息获取用户
+     *
+     * @param deviceType   : 设备类型
+     * @param userInfoMap  : 第三方用户信息
+     * @param userOauthDTO : 用户授权信息
+     * @return : 返回应用用户信息
+     */
+    private User getUserByUserOauth(String deviceType, Map<String, String> userInfoMap, UserOauthDTO userOauthDTO) {
+        if (userOauthDTO != null) {
+            return userService.getById(userOauthDTO.getUserId());
+        }
+        //创建用户信息
+        User user = User.builder()
+                .nickname(userInfoMap.get("nickname"))
+                .avatar(userInfoMap.get("avatar"))
+                .deviceType(deviceType)
+                .createTime(LocalDateTime.now())
+                .updateTime(LocalDateTime.now())
+                .build();
+        userService.save(user);
+        //创建用户授权信息
+        userOauthDTO = userOauthService.createUserOauth(user, userInfoMap);
+        log.info("用户授权信息, userOauthDTO : {}", JsonUtil.toString(userOauthDTO));
+        //返回用户信息
+        return user;
+    }
+
+    /**
+     * 登录用户名密码合规检测
+     *
+     * @param username : 用户名验证
+     * @param password : 密码验证
+     * @return : 返回验证结果
+     */
+    private HttpStatusEnum checkRegister(String username, String password) {
+        //用户名合规检测
+        HttpStatusEnum checkUserNameEnum = RegisterUtils.checkUserName(username);
+        if (Objects.equals(checkUserNameEnum, HttpStatusEnum.SUCCESS)) {
+            return checkUserNameEnum;
+        }
+        //判断用户名是否存在敏感词
+        if (wordCheckService.hasWord(username)) {
+            return HttpStatusEnum.USERNAME_SENSITIVE;
+        }
+        //判断用户名是否已存在
+        if (userService.count(new LambdaQueryWrapper<User>().eq(User::getUsername, username)) > 0) {
+            return HttpStatusEnum.USERNAME_EXISTS;
+        }
+        //密码验证
+        return RegisterUtils.checkPassword(password);
+    }
+
+    /**
+     * 生成随机密钥并添加到redis中
+     *
+     * @return : 返回随机密钥
+     */
+    private String getState() {
+        String state = UUID.randomUUID().toString();
+        redisUtils.addToSet(RedisKeyConstant.AUTH_STATE_KEY, state);
+        return state;
+    }
+
+    /**
+     * state参数检测
+     *
+     * @param state : 随机密钥
+     */
+    private void checkState(String state) {
+        if (!redisUtils.isMemberInSet(RedisKeyConstant.AUTH_STATE_KEY, state)) {
+            throw new BaseException("State验证失败");
+        }
+    }
+}

+ 31 - 1
game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/Impl/SmsServiceImpl.java

@@ -3,14 +3,16 @@ 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.enums.SmsTypeEnum;
 import com.zanxiang.common.utils.StringUtils;
 import com.zanxiang.sdk.common.constant.RedisKeyConstant;
 import com.zanxiang.sdk.common.util.RedisUtils;
 import com.zanxiang.sdk.domain.dto.UserDTO;
-import com.zanxiang.common.enums.SmsTypeEnum;
+import com.zanxiang.sdk.domain.params.SmsCheckParam;
 import com.zanxiang.sdk.domain.params.SmsSendParam;
 import com.zanxiang.sdk.service.ISmsService;
 import com.zanxiang.sdk.service.IUserService;
+import com.zanxiang.sdk.service.IUserTokenService;
 import com.zanxiangnet.module.sms.pojo.SendResult;
 import com.zanxiangnet.module.sms.service.impl.AliSmsService;
 import lombok.extern.slf4j.Slf4j;
@@ -39,6 +41,9 @@ public class SmsServiceImpl implements ISmsService {
     @Autowired
     private AliSmsService aliSmsService;
 
+    @Autowired
+    private IUserTokenService userTokenService;
+
     /**
      * 发送短信验证码
      *
@@ -90,6 +95,31 @@ public class SmsServiceImpl implements ISmsService {
         return new ResultVo<>(HttpStatusEnum.SUCCESS, Boolean.TRUE);
     }
 
+    /**
+     * 前端校验短信验证码
+     *
+     * @param smsCheckParam : 参数
+     * @return : 返回验证结果和token
+     */
+    @Override
+    public ResultVo<String> smsCheck(SmsCheckParam smsCheckParam) {
+        //校验短信验证码
+        HttpStatusEnum httpStatusEnum = this.smsCheck(smsCheckParam.getType(), smsCheckParam.getMobile(), smsCheckParam.getCode());
+        //校验不通过
+        if (!Objects.equals(httpStatusEnum, HttpStatusEnum.SUCCESS)) {
+            return new ResultVo<>(httpStatusEnum);
+        }
+        //查询用户信息
+        UserDTO userDTO = userService.getUserInfoByMobile(smsCheckParam.getMobile());
+        if (userDTO == null) {
+            return new ResultVo<>(HttpStatusEnum.PHONE_NOT_REG);
+        }
+        //获取token
+        String userToken = userTokenService.getUserToken(userDTO.getId(), userDTO.getDeviceType());
+        //返回
+        return new ResultVo<>(HttpStatusEnum.SUCCESS, userToken);
+    }
+
     /**
      * 校验短信验证码
      *

+ 62 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/Impl/UserOauthServiceImpl.java

@@ -0,0 +1,62 @@
+package com.zanxiang.sdk.service.Impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zanxiang.common.utils.bean.BeanUtils;
+import com.zanxiang.mybatis.entity.User;
+import com.zanxiang.mybatis.entity.UserOauth;
+import com.zanxiang.mybatis.mapper.UserOauthMapper;
+import com.zanxiang.sdk.domain.dto.UserOauthDTO;
+import com.zanxiang.sdk.service.IUserOauthService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-06-21
+ * @description : 用户第三方授权信息
+ */
+@Slf4j
+@Service
+public class UserOauthServiceImpl extends ServiceImpl<UserOauthMapper, UserOauth> implements IUserOauthService {
+
+    /**
+     * 根据openid查询用户授权信息
+     *
+     * @param openId : 用户第三方授权信息
+     * @return : 返回用户授权信息
+     */
+    @Override
+    public UserOauthDTO getUserOauthByOpenId(String openId) {
+        //根据用户第三方唯一查询
+        UserOauth userOauth = super.getOne(new LambdaQueryWrapper<UserOauth>().eq(UserOauth::getOpenid, openId));
+        //直接查到了信息
+        if (userOauth != null) {
+            return BeanUtils.copy(userOauth, UserOauthDTO.class);
+        }
+        return null;
+    }
+
+    /**
+     * 创建用户授权信息
+     *
+     * @param user : 用户信息
+     * @param map  : 第三方用户信息
+     * @return : 返回用户授权信息
+     */
+    @Override
+    public UserOauthDTO createUserOauth(User user, Map<String, String> map) {
+        UserOauth userOauth = UserOauth.builder()
+                .userId(user.getId())
+                .openid(map.get("openId"))
+                .accessToken(map.get("accessToken"))
+                .unionid(map.get("openId"))
+                .nickname(map.get("nickname"))
+                .avatar(map.get("avatar"))
+                .build();
+        super.save(userOauth);
+        return BeanUtils.copy(userOauth, UserOauthDTO.class);
+    }
+}

+ 42 - 303
game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/Impl/UserServiceImpl.java

@@ -1,31 +1,27 @@
 package com.zanxiang.sdk.service.Impl;
 
-import com.alibaba.nacos.common.utils.MD5Utils;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 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.mybatis.entity.User;
 import com.zanxiang.mybatis.mapper.UserMapper;
+import com.zanxiang.sdk.common.util.RegisterUtils;
 import com.zanxiang.sdk.domain.dto.UserDTO;
-import com.zanxiang.common.enums.AccountStatusEnum;
-import com.zanxiang.common.enums.CmfSaltEnum;
-import com.zanxiang.sdk.domain.params.*;
-import com.zanxiang.sdk.domain.vo.UserLoginVO;
-import com.zanxiang.sdk.service.*;
+import com.zanxiang.sdk.domain.dto.UserTokenDTO;
+import com.zanxiang.sdk.domain.params.UpdatePasswordParam;
+import com.zanxiang.sdk.domain.params.UserDetailParam;
+import com.zanxiang.sdk.domain.vo.UserVO;
+import com.zanxiang.sdk.service.IUserService;
+import com.zanxiang.sdk.service.IUserTokenService;
 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 org.springframework.transaction.annotation.Transactional;
 
-import javax.servlet.http.HttpServletRequest;
-import java.security.NoSuchAlgorithmException;
 import java.time.LocalDateTime;
 import java.util.Objects;
 
@@ -41,272 +37,6 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IU
     @Autowired
     private IUserTokenService userTokenService;
 
-    @Autowired
-    private ISmsService smsService;
-
-    @Autowired
-    private IUserLoginLogService userLoginLogService;
-
-    @Autowired
-    private IWordCheckService wordCheckService;
-
-    /**
-     * 普通注册
-     *
-     * @param registerPasswordParam : 用户名密码注册参数
-     * @return : 返回注册结果
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public ResultVo<UserLoginVO> registerPassword(RegisterPasswordParam registerPasswordParam, HttpServletRequest request) {
-        String username = registerPasswordParam.getUsername();
-        String password = registerPasswordParam.getPassword();
-        //用户名密码校验
-        HttpStatusEnum checkRegisterEnum = this.checkRegister(username, password);
-        if (!Objects.equals(checkRegisterEnum, HttpStatusEnum.SUCCESS)) {
-            return new ResultVo<>(checkRegisterEnum);
-        }
-        //创建用户信息
-        User user = User.builder()
-                .username(registerPasswordParam.getUsername())
-                .password(this.cmfPassword(password))
-                .deviceId(registerPasswordParam.getDeviceId())
-                .deviceType(registerPasswordParam.getDeviceType())
-                .status(AccountStatusEnum.NORMAL_STATUS.getStatus())
-                .createTime(LocalDateTime.now())
-                .updateTime(LocalDateTime.now())
-                .build();
-        super.save(user);
-        //登录的ip
-        String realIp = IpUtils.getRealIp(request);
-        //插入用户登录记录
-        userLoginLogService.addUserLoginLog(realIp, user, registerPasswordParam.getGameId());
-        //获取token
-        String userToken = userTokenService.getUserToken(user.getId(), user.getDeviceType());
-        //返回用户token
-        return new ResultVo<>(new UserLoginVO(userToken));
-    }
-
-    /**
-     * 手机注册
-     *
-     * @param registerMobileParam : 手机注册参数
-     * @param request             : HttpServletRequest
-     * @return : 返回注册结果
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public ResultVo<UserLoginVO> registerMobile(RegisterMobileParam registerMobileParam, HttpServletRequest request) {
-        Integer type = registerMobileParam.getType();
-        String mobile = registerMobileParam.getMobile();
-        String code = registerMobileParam.getCode();
-        String password = registerMobileParam.getPassword();
-        //校验手机验证码
-        HttpStatusEnum codeCheckEnum = smsService.smsCheck(type, mobile, code);
-        if (!Objects.equals(codeCheckEnum, HttpStatusEnum.SUCCESS)) {
-            return new ResultVo<>(codeCheckEnum);
-        }
-        //判断手机号是否已经注册
-        if (super.count(new LambdaQueryWrapper<User>().eq(User::getMobile, mobile)) > 0) {
-            return new ResultVo<>(HttpStatusEnum.PHONE_IS_REG);
-        }
-        //验证密码是否合规
-        HttpStatusEnum passwordCheckEnum = this.checkPassword(password);
-        if (!Objects.equals(passwordCheckEnum, HttpStatusEnum.SUCCESS)) {
-            return new ResultVo<>(passwordCheckEnum);
-        }
-        //创建用户信息
-        User user = User.builder()
-                .username(mobile)
-                .regMobile(mobile)
-                .mobile(mobile)
-                .password(this.cmfPassword(password))
-                .deviceId(registerMobileParam.getDeviceId())
-                .deviceType(registerMobileParam.getDeviceType())
-                .status(AccountStatusEnum.NORMAL_STATUS.getStatus())
-                .createTime(LocalDateTime.now())
-                .updateTime(LocalDateTime.now())
-                .build();
-        super.save(user);
-        //获取token
-        String userToken = userTokenService.getUserToken(user.getId(), user.getDeviceType());
-        //登录的ip
-        String realIp = IpUtils.getRealIp(request);
-        //插入用户登录记录
-        userLoginLogService.addUserLoginLog(realIp, user, registerMobileParam.getGameId());
-        //返回用户token
-        return new ResultVo<>(new UserLoginVO(userToken));
-    }
-
-    /**
-     * 登录用户名密码合规检测
-     *
-     * @param username : 用户名验证
-     * @param password : 密码验证
-     * @return : 返回验证结果
-     */
-    private HttpStatusEnum checkRegister(String username, String password) {
-        if (Strings.isBlank(username)) {
-            return HttpStatusEnum.USERNAME_EMPTY;
-        }
-        //用户名长度验证
-        if (username.length() < 4) {
-            return HttpStatusEnum.USERNAME_TOO_SHORT;
-        }
-        if (username.length() > 32) {
-            return HttpStatusEnum.USERNAME_TOO_LONG;
-        }
-//        boolean matches = username.matches("[\\s]");
-//        if (!username.matches("/^[a-zA-Z0-9]+$/i")){
-//            return HttpStatusEnum.USERNAME_BAD_CHAR;
-//        }
-//        //合规验证
-//        if (username.matches("/\\s/") || username.matches("/^ZN/i") || !username.matches("^[a-zA-Z0-9]+$")) {
-//            return HttpStatusEnum.USERNAME_BAD_CHAR;
-//        }
-//        //用户名不是手机号, 用户名只能是数字和字母
-//        if (!StringUtils.checkPhone(username) && !username.matches("/^(?![^a-zA-Z]+$).{4,32}$/")) {
-//            return HttpStatusEnum.USERNAME_BAD_CHAR;
-//        }
-        //判断用户名是否存在敏感词
-        if (wordCheckService.hasWord(username)) {
-            return HttpStatusEnum.USERNAME_SENSITIVE;
-        }
-        //判断用户名是否已存在
-        if (super.count(new LambdaQueryWrapper<User>().eq(User::getUsername, username)) > 0) {
-            return HttpStatusEnum.USERNAME_EXISTS;
-        }
-        //密码验证
-        return this.checkPassword(password);
-    }
-
-    /**
-     * 密码合规检测
-     *
-     * @param password : 密码验证
-     * @return : 返回验证结果
-     */
-    private HttpStatusEnum checkPassword(String password) {
-        if (Strings.isBlank(password)) {
-            return HttpStatusEnum.PASSWORD_EMPTY;
-        }
-        if (password.length() < 6) {
-            return HttpStatusEnum.PASSWORD_TOO_SHORT;
-        }
-        if (password.length() > 32) {
-            return HttpStatusEnum.PASSWORD_TOO_LONG;
-        }
-//        if (password.matches("/\\s/") || !password.matches("A([a-zA-Z0-9~`#$%^&*!@.,()\\\\{}|:;?<>]){6,32}$")) {
-//            return HttpStatusEnum.PASSWORD_BAD_CHAR;
-//        }
-        return HttpStatusEnum.SUCCESS;
-    }
-
-    /**
-     * 用户昵称合规检测
-     *
-     * @param nickname : 用户昵称
-     * @return : 检测结果
-     */
-    private HttpStatusEnum checkNickname(String nickname) {
-        if (Strings.isBlank(nickname)) {
-            return HttpStatusEnum.NICKNAME_EMPTY;
-        }
-        if (nickname.length() < 4) {
-            return HttpStatusEnum.NICKNAME_TOO_SHORT;
-        }
-        if (nickname.length() > 32) {
-            return HttpStatusEnum.NICKNAME_TOO_LONG;
-        }
-        //判断昵称是否存在敏感词
-        if (wordCheckService.hasWord(nickname)) {
-            return HttpStatusEnum.NICKNAME_SENSITIVE;
-        }
-        return HttpStatusEnum.SUCCESS;
-    }
-
-    /**
-     * 用户名密码登录
-     *
-     * @param userLoginParam : 登录参数
-     * @param request        : HttpServletRequest
-     * @return : 返回登录token
-     */
-    @Override
-    public ResultVo<UserLoginVO> loginPassword(LoginPasswordParam userLoginParam, HttpServletRequest request) {
-        //用户名
-        String username = userLoginParam.getUsername();
-        //密码
-        String password = userLoginParam.getPassword();
-        //用户信息
-        User user;
-        //验证用户名是否为手机号
-        if (StringUtils.checkPhone(username)) {
-            user = super.getOne(new LambdaQueryWrapper<User>().eq(User::getMobile, username));
-        } else {
-            user = super.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
-        }
-        //用户信息不存在
-        if (user == null) {
-            return new ResultVo<>(HttpStatusEnum.USERNAME_OR_PASSWORD_ERR);
-        }
-        //判断账号是否停用
-        if (Objects.equals(AccountStatusEnum.FROZEN_STATUS.getStatus(), user.getStatus())) {
-            return new ResultVo<>(HttpStatusEnum.ACCOUNT_HALT);
-        }
-        //验证密码
-        if (!Objects.equals(this.cmfPassword(password), user.getPassword())) {
-            return new ResultVo<>(HttpStatusEnum.USERNAME_OR_PASSWORD_ERR);
-        }
-        //验证通过, 获取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));
-    }
-
-
-    /**
-     * 手机号登录
-     *
-     * @param loginMobileParam : 手机号登录参数
-     * @param request          : HttpServletRequest
-     * @return : 返回登录信息
-     */
-    @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));
-    }
-
     /**
      * 用户重置密码
      *
@@ -316,55 +46,64 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IU
     @Override
     @Transactional(rollbackFor = Exception.class)
     public ResultVo<Boolean> updatePassword(UpdatePasswordParam updatePasswordParam) {
-        String mobile = updatePasswordParam.getMobile();
-        Integer type = updatePasswordParam.getType();
-        String code = updatePasswordParam.getCode();
-        String username = updatePasswordParam.getUsername();
+        String token = updatePasswordParam.getToken();
         String password = updatePasswordParam.getPassword();
-        //根据用户名查询用户信息
-        User user = super.getOne(new LambdaQueryWrapper<User>()
-                .eq(User::getUsername, username)
-                .eq(User::getMobile, mobile));
+        String username = updatePasswordParam.getUsername();
+        //查询用户信息
+        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
+        if (StringUtils.checkPhone(username)) {
+            queryWrapper.eq(User::getMobile, username);
+        } else {
+            queryWrapper.eq(User::getUsername, username);
+        }
+        User user = super.getOne(queryWrapper);
         if (user == null) {
             return new ResultVo<>(HttpStatusEnum.USERNAME_NOT_EXISTS);
         }
-        //短信验证码校验
-        HttpStatusEnum httpStatusEnum = smsService.smsCheck(type, mobile, code);
-        if (!Objects.equals(httpStatusEnum, HttpStatusEnum.SUCCESS)) {
-            return new ResultVo<>(httpStatusEnum);
+        //验证token是否存在
+        HttpStatusEnum checkUserTokenEnum = userTokenService.checkUserToken(token, user.getId(), updatePasswordParam.getDeviceType());
+        if (!Objects.equals(HttpStatusEnum.SUCCESS, checkUserTokenEnum)) {
+            return new ResultVo<>(checkUserTokenEnum);
         }
         //密码校验
-        HttpStatusEnum checkPasswordEnum = this.checkPassword(password);
+        HttpStatusEnum checkPasswordEnum = RegisterUtils.checkPassword(password);
         if (!Objects.equals(checkPasswordEnum, HttpStatusEnum.SUCCESS)) {
             return new ResultVo<>(checkPasswordEnum);
         }
         //修改用户密码
         super.update(new LambdaUpdateWrapper<User>()
-                .set(User::getPassword, this.cmfPassword(password))
+                .set(User::getPassword, RegisterUtils.cmfPassword(password))
                 .set(User::getUpdateTime, LocalDateTime.now())
-                .eq(User::getId, user.getId()));
+                .eq(User::getUsername, username));
         //返回修改成功
         return new ResultVo<>(HttpStatusEnum.SUCCESS, Boolean.TRUE);
     }
 
     /**
-     * 密码cfm加密
+     * 获取用户信息
      *
-     * @param password : 密码
-     * @return : 返回加密完的密码
+     * @param userDetailParam : 用户详情参数
+     * @return : 返回用户信息
      */
-    private String cmfPassword(String password) {
-        String passwordSalt = password + CmfSaltEnum.CMF_PASSWORD.getSalt();
-        try {
-            return "###" + MD5Utils.md5Hex(MD5Utils.md5Hex(passwordSalt.getBytes()).getBytes());
-        } catch (NoSuchAlgorithmException e) {
-            e.printStackTrace();
-            throw new BaseException("密码加密异常");
+    @Override
+    public ResultVo<UserVO> getUserDetail(UserDetailParam userDetailParam) {
+        String token = userDetailParam.getToken();
+        String deviceType = userDetailParam.getDeviceType();
+        UserTokenDTO userTokenDTO = userTokenService.getTokenInfoByTokenDevice(token, deviceType);
+        if (userTokenDTO == null) {
+            return new ResultVo<>(HttpStatusEnum.INVALID_PARAMS);
+        }
+        //查询用户信息
+        User user = super.getById(userTokenDTO.getUserId());
+        if (user == null) {
+            return new ResultVo<>(HttpStatusEnum.UNKNOWN_ERROR);
         }
+        UserVO userVO = BeanUtils.copy(user, UserVO.class);
+        return new ResultVo<>(HttpStatusEnum.SUCCESS, userVO);
     }
 
     /**
-     * 检查用户手机号是否存在
+     * 根据手机号获取用户信息
      *
      * @param mobile : 用户手机号
      * @return : 返回用户信息

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

@@ -5,6 +5,7 @@ import com.alibaba.nacos.common.utils.MD5Utils;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.zanxiang.common.enums.ExpireTimeEnum;
+import com.zanxiang.common.enums.HttpStatusEnum;
 import com.zanxiang.common.exception.BaseException;
 import com.zanxiang.common.text.UUID;
 import com.zanxiang.common.utils.DateUtils;
@@ -22,6 +23,7 @@ import org.springframework.stereotype.Service;
 import java.security.NoSuchAlgorithmException;
 import java.time.LocalDateTime;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * @author : lingfeng
@@ -97,6 +99,23 @@ public class UserTokenServiceImpl extends ServiceImpl<UserTokenMapper, UserToken
         return BeanUtils.copy(userToken, UserTokenDTO.class);
     }
 
+    /**
+     * 用户token校验
+     *
+     * @param token      : 用户token
+     * @param userId     : 用户id
+     * @param deviceType : 设备类型
+     * @return : 返回token校验结果
+     */
+    @Override
+    public HttpStatusEnum checkUserToken(String token, Long userId, String deviceType) {
+        UserTokenDTO userTokenDTO = this.getTokenInfoByUserDevice(userId, deviceType);
+        if (userTokenDTO != null && Objects.equals(userTokenDTO.getToken(), token)) {
+            return HttpStatusEnum.SUCCESS;
+        }
+        return HttpStatusEnum.INVALID_PARAMS;
+    }
+
     /**
      * 获取用户token
      *

+ 146 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/Impl/auth/QqApiServiceImpl.java

@@ -0,0 +1,146 @@
+package com.zanxiang.sdk.service.Impl.auth;
+
+import cn.hutool.http.HttpUtil;
+import com.zanxiang.common.exception.BaseException;
+import com.zanxiang.common.utils.URIUtil;
+import com.zanxiang.sdk.common.constant.ApiUrlConstant;
+import com.zanxiang.sdk.service.IQqApiService;
+import com.zanxiangnet.module.util.JsonUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-06-20
+ * @description : QQ Api接口
+ */
+@Slf4j
+@Service
+public class QqApiServiceImpl implements IQqApiService {
+
+    /**
+     * QQ开发者应用id
+     */
+    @Value("${auth.qq-appId}")
+    private String qqAppId;
+
+    /**
+     * QQ开发者应用key
+     */
+    @Value("${auth.qq-appKey}")
+    private String qqAppKey;
+
+    /**
+     * QQ授权获取用户信息
+     *
+     * @param code : 前端授权code
+     * @return : 返回用户信息
+     */
+    @Override
+    public Map<String, String> qqAuthUserInfo(String code) {
+        // 向QQ认证服务器申请令牌
+        String accessToken = this.getAccessTokenApi(code);
+        if (Strings.isBlank(accessToken)) {
+            throw new BaseException("获取token失败");
+        }
+        // 通过accessToken获取用户openId
+        String openId = this.getUserOpenIdApi(accessToken);
+        if (Strings.isBlank(openId)) {
+            throw new BaseException("获取openId失败");
+        }
+        // 获取用户信息
+        Map<String, String> userInfo = this.getUserInfoApi(accessToken, openId);
+        if (userInfo.isEmpty()) {
+            throw new BaseException("获取用户信息失败");
+        }
+        //构造返回信息
+        Map<String, String> map = new HashMap<>(3);
+        map.put("openId", openId);
+        map.put("accessToken", accessToken);
+        map.put("nickname", userInfo.get("nickname"));
+        map.put("avatar", userInfo.get("figureurl_qq_1"));
+        map.put("six", userInfo.get("gender"));
+        return map;
+    }
+
+    /**
+     * 获取用户授权token
+     *
+     * @param code : 用户授权code
+     * @return : 返回token
+     */
+    private String getAccessTokenApi(String code) {
+        Map<String, String> paramMap = new HashMap<>(5);
+        paramMap.put("grant_type", "authorization_code");
+        paramMap.put("code", code);
+        paramMap.put("redirect_uri", ApiUrlConstant.QQ_REDIRECT_URL);
+        paramMap.put("client_id", qqAppId);
+        paramMap.put("client_secret", qqAppKey);
+        //拼接url请求参数
+        Map<String, String> resultMap = new HashMap<>();
+        try {
+            String uri = URIUtil.fillUrlParams(ApiUrlConstant.QQ_WEB_TOKEN_URL, paramMap, Boolean.TRUE);
+            String result = HttpUtil.get(uri);
+            if (Strings.isNotBlank(result)) {
+                resultMap = JsonUtil.toMap(result, Map.class, String.class);
+            }
+        } catch (Exception e) {
+            log.error("QQ获取用户授权token异常");
+            throw new BaseException("QQ获取用户授权token异常");
+        }
+        return resultMap.get("access_token");
+    }
+
+    /**
+     * 获取用户openId
+     *
+     * @param accessToken : 用户token密钥
+     * @return : 返回用户openId
+     */
+    private String getUserOpenIdApi(String accessToken) {
+        //拼接url请求参数
+        Map<String, String> paramMap = new HashMap<>(1);
+        paramMap.put("access_token", accessToken);
+        Map<String, String> resultMap = new HashMap<>();
+        try {
+            String uri = URIUtil.fillUrlParams(ApiUrlConstant.QQ_USER_OPENID_URL, paramMap, Boolean.TRUE);
+            String result = HttpUtil.get(uri);
+            if (Strings.isNotBlank(result)) {
+                resultMap = JsonUtil.toMap(result, Map.class, String.class);
+            }
+        } catch (Exception e) {
+            log.error("");
+        }
+        return resultMap.get("openid");
+    }
+
+    /**
+     * 获取用户openId
+     *
+     * @param accessToken : 用户token密钥
+     * @return : 返回用户openId
+     */
+    private Map<String, String> getUserInfoApi(String accessToken, String openId) {
+        //拼接url请求参数
+        Map<String, String> paramMap = new HashMap<>(3);
+        paramMap.put("access_token", accessToken);
+        paramMap.put("oauth_consumer_key", qqAppId);
+        paramMap.put("openid", openId);
+        Map<String, String> resultMap = new HashMap<>();
+        try {
+            String uri = URIUtil.fillUrlParams(ApiUrlConstant.QQ_USER_INFO_URL, paramMap, Boolean.TRUE);
+            String result = HttpUtil.get(uri);
+            if (Strings.isNotBlank(result)) {
+                resultMap = JsonUtil.toMap(result, Map.class, String.class);
+            }
+        } catch (Exception e) {
+            log.error("");
+        }
+        return resultMap;
+    }
+}

+ 221 - 0
game-module/game-sdk/src/main/java/com/zanxiang/sdk/service/Impl/auth/VxApiServiceImpl.java

@@ -0,0 +1,221 @@
+package com.zanxiang.sdk.service.Impl.auth;
+
+import cn.hutool.http.HttpUtil;
+import com.zanxiang.common.exception.BaseException;
+import com.zanxiang.common.utils.URIUtil;
+import com.zanxiang.sdk.common.constant.ApiUrlConstant;
+import com.zanxiang.sdk.service.IVxApiService;
+import com.zanxiangnet.module.util.JsonUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-06-20
+ * @description : 微信api接口
+ */
+@Slf4j
+@Service
+public class VxApiServiceImpl implements IVxApiService {
+
+    /**
+     * 微信开发者应用id
+     */
+    @Value("${auth.vx-appId}")
+    private String vxAppId;
+
+    /**
+     * 微信开发者应用key
+     */
+    @Value("${auth.vx-appSecret}")
+    private String vxAppSecret;
+
+    /**
+     * QQ授权获取用户信息
+     *
+     * @param code : 前端授权code
+     * @return : 返回用户信息
+     */
+    @Override
+    public Map<String, String> vxAuthUserInfo(String code) {
+        // 向QQ认证服务器申请令牌
+        Map<String, String> tokenResultMap = this.getAccessTokenApi(code);
+        if (tokenResultMap.isEmpty()) {
+            throw new BaseException("获取token失败");
+        }
+        // 获取用户信息
+        Map<String, String> userInfoMap = this.getUserInfoApi(tokenResultMap.get("access_token"), tokenResultMap.get("openid"));
+        if (userInfoMap.isEmpty()) {
+            throw new BaseException("获取用户信息失败");
+        }
+        //构造返回信息
+        Map<String, String> map = new HashMap<>(3);
+        map.put("openId", tokenResultMap.get("openid"));
+        map.put("accessToken", tokenResultMap.get("access_token"));
+        map.put("nickname", userInfoMap.get("nickname"));
+        map.put("avatar", userInfoMap.get("headimgurl"));
+        map.put("six", userInfoMap.get("six"));
+        return map;
+    }
+
+
+    /**
+     * web获取用户授权token
+     * <p>
+     * 成功示例 :
+     * {
+     * "access_token":"ACCESS_TOKEN",
+     * "expires_in":7200,
+     * "refresh_token":"REFRESH_TOKEN",
+     * "openid":"OPENID",
+     * "scope":"SCOPE"
+     * }
+     * <p>
+     * 错误返回样例:
+     * {
+     * "errcode":40029,"errmsg":"invalid code"
+     * }
+     *
+     * @param code : 用户授权code
+     * @return : 返回token
+     */
+    private Map<String, String> getAccessTokenApi(String code) {
+        Map<String, String> paramMap = new HashMap<>(4);
+        paramMap.put("appid", vxAppId);
+        paramMap.put("secret", vxAppSecret);
+        paramMap.put("code", code);
+        paramMap.put("grant_type", "authorization_code");
+        //拼接url请求参数
+        Map<String, String> resultMap = new HashMap<>();
+        try {
+            String uri = URIUtil.fillUrlParams(ApiUrlConstant.VX_WEB_TOKEN_URL, paramMap, Boolean.TRUE);
+            String result = HttpUtil.get(uri);
+            if (Strings.isNotBlank(result)) {
+                resultMap = JsonUtil.toMap(result, Map.class, String.class);
+            }
+        } catch (Exception e) {
+            log.error("微信获取用户授权token异常");
+            throw new BaseException("微信获取用户授权token异常");
+        }
+        return resultMap;
+    }
+
+    /**
+     * web刷新用户token
+     * <p>
+     * 成功示例 :
+     * {
+     * "access_token":"ACCESS_TOKEN",
+     * "expires_in":7200,
+     * "refresh_token":"REFRESH_TOKEN",
+     * "openid":"OPENID",
+     * "scope":"SCOPE"
+     * }
+     * <p>
+     * 错误返回样例:
+     * {
+     * "errcode":40030,"errmsg":"invalid refresh_token"
+     * }
+     *
+     * @param refreshToken : 刷新token密钥
+     * @return : 返回新的token
+     */
+    private Map<String, String> refreshTokenApi(String refreshToken) {
+        Map<String, String> paramMap = new HashMap<>(4);
+        paramMap.put("appid", vxAppId);
+        paramMap.put("grant_type", "refresh_token");
+        paramMap.put("refresh_token", refreshToken);
+        //拼接url请求参数
+        Map<String, String> resultMap = new HashMap<>();
+        try {
+            String uri = URIUtil.fillUrlParams(ApiUrlConstant.VX_WEB_TOKEN_REFRESH_URL, paramMap, Boolean.TRUE);
+            String result = HttpUtil.get(uri);
+            if (Strings.isNotBlank(result)) {
+                resultMap = JsonUtil.toMap(result, Map.class, String.class);
+            }
+        } catch (Exception e) {
+            log.error("微信刷新用户token异常");
+            throw new BaseException("微信刷新用户token异常");
+        }
+        return resultMap;
+    }
+
+    /**
+     * web用户token校验是否有效
+     *
+     * @param openid      : 用户在微信应用的唯一id
+     * @param accessToken : 密钥
+     * @return : 返回token是否有效, true : 有效, false : 无效
+     */
+    private Boolean tokenCheckApi(String openid, String accessToken) {
+        Map<String, String> paramMap = new HashMap<>(2);
+        paramMap.put("accessToken", accessToken);
+        paramMap.put("openid", openid);
+        //拼接url请求参数
+        Map<String, String> resultMap = new HashMap<>();
+        try {
+            String uri = URIUtil.fillUrlParams(ApiUrlConstant.VX_WEB_TOKEN_CHECK_URL, paramMap, Boolean.TRUE);
+            String result = HttpUtil.get(uri);
+            if (Strings.isNotBlank(result)) {
+                resultMap = JsonUtil.toMap(result, Map.class, String.class);
+            }
+        } catch (Exception e) {
+            log.error("微信刷新用户token异常");
+            throw new BaseException("微信刷新用户token异常");
+        }
+        return Objects.equals(resultMap.get("errcode"), "0");
+    }
+
+
+    /**
+     * web获取用户信息
+     * <p>
+     * 成功示例 :
+     * {
+     * "openid":"OPENID",
+     * "nickname":"NICKNAME",
+     * "sex":1,
+     * "province":"PROVINCE",
+     * "city":"CITY",
+     * "country":"COUNTRY",
+     * "headimgurl": "headimgurl",
+     * "privilege":["PRIVILEGE1","PRIVILEGE2"],
+     * "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
+     * }
+     * <p>
+     * 错误返回样例:
+     * {
+     * "errcode":40003,"errmsg":"invalid openid"
+     * }
+     *
+     * @param openid      : 用户在微信应用的唯一id
+     * @param accessToken : 密钥
+     * @return : 返回token是否有效, true : 有效, false : 无效
+     */
+    private Map<String, String> getUserInfoApi(String accessToken, String openid) {
+        Map<String, String> paramMap = new HashMap<>(3);
+        paramMap.put("accessToken", accessToken);
+        paramMap.put("openid", openid);
+        paramMap.put("lang", "zh_CN");
+        //拼接url请求参数
+        Map<String, String> resultMap = new HashMap<>();
+        try {
+            String uri = URIUtil.fillUrlParams(ApiUrlConstant.VX_WEB_USER_INFO_URL, paramMap, Boolean.TRUE);
+            String result = HttpUtil.get(uri);
+            if (Strings.isNotBlank(result)) {
+                resultMap = JsonUtil.toMap(result, Map.class, String.class);
+            }
+        } catch (Exception e) {
+            log.error("web获取用户信息异常");
+            throw new BaseException("web获取用户信息异常");
+        }
+        return resultMap;
+    }
+
+}

+ 6 - 0
game-module/game-sdk/src/main/resources/bootstrap.yml

@@ -49,6 +49,12 @@ ali-sms:
   defaultSignName: 赞象
   defaultVerifyCodeTemplate: SMS_232080189
 
+auth:
+  qq-appId: 101933357
+  qq-appKey: 900292039ed5408d941dad762ab68383
+  vx-appId :
+  vx-appSecret:
+
 logging:
   level:
     root: warn