chao 4 anni fa
parent
commit
582063153a

+ 45 - 12
src/main/java/com/caimei365/user/controller/LoginApi.java

@@ -3,10 +3,13 @@ package com.caimei365.user.controller;
 import com.caimei365.user.model.ResponseJson;
 import com.caimei365.user.model.vo.UserLoginVo;
 import com.caimei365.user.service.LoginService;
+import com.google.common.base.Verify;
 import lombok.RequiredArgsConstructor;
 import org.springframework.http.HttpHeaders;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.Map;
+
 /**
  * 登录API
  *
@@ -35,9 +38,9 @@ public class LoginApi {
     }
 
     /**
-     * 微信授权登录(小程序)
+     * 微信授权登录(小程序),用户数据存入Redis,key前缀:wxInfo:applets:
      *
-     * spi旧接口:/club/authorization
+     * spi旧接口:/club/authorization,小程序sessionKey(wxInfo)、PC端sessionKey(wxInfoMap)
      *
      * @param code          微信授权code
      * @param encryptedData 微信加密数据
@@ -62,9 +65,9 @@ public class LoginApi {
     }
 
     /**
-     * 微信公众号授权登录(www)
+     * 微信公众号授权登录(www),用户数据存入Redis,key前缀:wxInfo:website:
      *
-     * spi旧接口:/user/authorizationLogin
+     * spi旧接口:/user/authorizationLogin,小程序sessionKey(wxInfo)、PC端sessionKey(wxInfoMap)
      *
      * @param code  微信code
      * @param state 安全认证
@@ -75,23 +78,53 @@ public class LoginApi {
         return loginService.websiteAuthorization(code, state, mode, headers);
     }
 
-    /**
-     * 微信扫码登录
+    /*
+     * 微信扫码登录(www)
      *
      *   流程:1.前端页面中先引入JS文件(支持https):http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js
-     *        2.前端实例化JS对象(用于生成二维码): new WxLogin({self_redirect:true, id:"login_container", appid:"", scope:"", redirect_uri:"", state:"", style:"", href: ""});
-     *        3.后端提供接口返回参数appid,scope,redirect_uri,其余参数由前端自定义,详细参考微信文档:https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html
-     *        4.用户扫码:
+     *        2.后端提供接口(/user/login/auth/parameters)返回生成二维码的参数:appid,scope,redirect_uri,其余参数由前端自定义,详细参考微信文档:https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html
+     *        3.前端实例化JS对象(用于生成二维码): new WxLogin({self_redirect:true, id:"login_container", appid:"", scope:"", redirect_uri:"", state:"", style:"", href: ""});
+     *        4.用户扫码:用户使用微信扫码授权后,微信服务器回调:/user/login/auth/scan?code=CODE&state=STATE,后端接口根据code和state换取access_token,并通过access_token获取用户信息,并存入Redis.
+     *        5.后端提供长链接接口或轮询接口(/user/login/auth/result),前端访问(轮询)此接口判断是否扫码成功。
+     */
+
+    /**
+     * 获取生成微信二维码的参数
      *
+     * spi旧接口:/user/toWechatLogin
+     *
+     * @return Map(appId,redirectUri,state)
+     */
+    @GetMapping("/auth/parameters")
+    public ResponseJson<Map<String, String>> getAuthParameters(){
+        return loginService.getAuthParameters();
+    }
+
+    /**
+     * 微信用户扫码,微信服务器回调
      *
      * spi旧接口:/user/wechatLogin
      *
      * @param code      微信code
-     * @param state     安全认证
+     * @param state     安全认证key(第一步获取参数时自定义生成的uuid)
      */
     @GetMapping("/auth/scan")
-    public void qrCodeAuthorization(String code, String state) {
-        loginService.qrCodeAuthorization(code, state);
+    public void qrCodeAuthScan(String code, String state) {
+        loginService.qrCodeAuthScan(code, state);
+    }
+
+    /**
+     * 校验扫码结果(长链接),用户数据存入Redis,key前缀:wxInfo:website:
+     *
+     * spi旧接口:/user/polling,小程序sessionKey(wxInfo)、PC端sessionKey(wxInfoMap)
+     *
+     * @param state   安全认证key(第一步获取参数时自定义生成的uuid)
+     * @return UserLoginVo
+     */
+    @GetMapping("/auth/scan/check")
+    public ResponseJson<UserLoginVo> checkScanAuthResult(String state){
+        return loginService.checkScanAuthResult(state);
     }
 
+
 }

+ 18 - 7
src/main/java/com/caimei365/user/service/LoginService.java

@@ -4,6 +4,8 @@ import com.caimei365.user.model.ResponseJson;
 import com.caimei365.user.model.vo.UserLoginVo;
 import org.springframework.http.HttpHeaders;
 
+import java.util.Map;
+
 
 /**
  * Description
@@ -52,17 +54,26 @@ public interface LoginService {
     ResponseJson<UserLoginVo> websiteAuthorization(String code, String state, Integer mode, HttpHeaders headers);
 
     /**
-     * 微信扫码登录
+     * 获取生成微信二维码的参数(www)
+     *
+     * @return Map<String, Object>
+     */
+    ResponseJson<Map<String, String>> getAuthParameters();
+
+    /**
+     * 微信用户扫码,微信服务器回调
      *
      * @param code      微信code
-     * @param state     安全认证
+     * @param state     安全认证key(上一步获取参数时自定义生成的uuid)
      */
-    void qrCodeAuthorization(String code, String state);
+    void qrCodeAuthScan(String code, String state);
 
     /**
-     * netty长连接验证登录
-     * @param state     安全认证
-     * @return
+     * 校验扫码结果(长链接)
+     *
+     * @param state   安全认证key(第一步获取参数时自定义生成的uuid)
+     * @return UserLoginVo
      */
-    ResponseJson nettyAuthorization(String state);
+    ResponseJson<UserLoginVo> checkScanAuthResult(String state);
+
 }

+ 73 - 66
src/main/java/com/caimei365/user/service/impl/LoginServiceImpl.java

@@ -1,5 +1,6 @@
 package com.caimei365.user.service.impl;
 
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.caimei365.user.components.WeChatService;
 import com.caimei365.user.mapper.LoginMapper;
@@ -138,7 +139,7 @@ public class LoginServiceImpl implements LoginService {
 
     /**
      * 微信公众号授权登录(www)
-     * <p>
+     *
      * spi旧接口:user/authorizationLogin
      *
      * @param code              微信code
@@ -190,6 +191,7 @@ public class LoginServiceImpl implements LoginService {
 
     /**
      * 运营人员授权登录
+     *
      * @param openId 微信openId
      * @param unionId 微信unionId
      * @param source 来源:www网站, mini小程序
@@ -220,106 +222,111 @@ public class LoginServiceImpl implements LoginService {
     }
     /**
      * 登录校验
-     * @param baseUser 用户信息
-     * @return BaseUser
+     * @param loginUser 用户信息
+     * @return UserLoginVo
      */
-    private ResponseJson<UserLoginVo> logonVerify(UserLoginVo baseUser) {
+    private ResponseJson<UserLoginVo> logonVerify(UserLoginVo loginUser) {
         // 生成token给用户
-        String token = JwtUtil.createToken(baseUser.getUserId());
+        String token = JwtUtil.createToken(loginUser.getUserId());
         // 为了过期续签,将token存入redis,并设置超时时间
         redisService.set(token, token, JwtUtil.getExpireTime());
-        baseUser.setToken(token);
-        if (baseUser.getStatus() == 91) {
+        loginUser.setToken(token);
+        if (loginUser.getStatus() == 91) {
             //机构 / 供应商
             return ResponseJson.error(-2, "您的企业账号已被冻结,请联系客服处理", null);
         }
         // 供应商
-        if (baseUser.getUserIdentity() == 3) {
-            if (baseUser.getStatus() == 3) {
+        if (loginUser.getUserIdentity() == 3) {
+            if (loginUser.getStatus() == 3) {
                 return ResponseJson.error(-2, "您的企业账号正在加速审核中,审核通过后即可登录", null);
             }
-            if (baseUser.getStatus() == 92) {
-                return ResponseJson.error(-3, "您的企业账号审核未通过", baseUser);
+            if (loginUser.getStatus() == 92) {
+                return ResponseJson.error(-3, "您的企业账号审核未通过", loginUser);
             }
         }
-        return ResponseJson.success("登录成功", baseUser);
+        return ResponseJson.success("登录成功", loginUser);
     }
 
     /**
-     * 微信扫码登录
+     * 获取生成微信二维码的参数(www)
+     *
+     * @return Map<String, Object>
+     */
+    @Override
+    public ResponseJson<Map<String, String>> getAuthParameters() {
+        UUID state = UUID.randomUUID();
+        Map<String, String> dataMap = new HashMap<>(3);
+        dataMap.put("appId", weChatService.getAppId());
+        dataMap.put("redirectUri", weChatService.getRedirectUri());
+        dataMap.put("state", String.valueOf(state));
+        redisService.set("state:" + state, String.valueOf(state), 1800L);
+        return ResponseJson.success(dataMap);
+    }
+    /**
+     * 微信用户扫码,微信服务器回调
      *
      * @param code      微信code
-     * @param state     安全认证
+     * @param state     安全认证key(上一步获取参数时自定义生成的uuid)
      */
     @Override
-    public void qrCodeAuthorization(String code, String state) {
-        Map<String, Object> map = new HashMap<>();
+    public void qrCodeAuthScan(String code, String state) {
+        String errorMsg = "";
         // 简单验证,防止csrf攻击(跨站请求伪造攻击)
         String stateCache = (String) redisService.get("state:" + state);
-        if (stateCache == null) {
-            map.put("-1", "请从正确的途径打开链接");
+        if (StringUtils.isBlank(stateCache) || "null".equals(stateCache)) {
+            errorMsg = "请从正确的途径打开链接";
         }
         if (StringUtils.isEmpty(code)) {
-            map.put("-1", "请重新进行授权登录");
+            errorMsg = "请重新进行授权登录";
         }
-        Map<String, Object> tokenMap;
-        Map<String, Object> wxInfoMap = null;
         try {
-            tokenMap = weChatService.getInfoMapByWeb(code, "pc");
-            String access_token = (String) tokenMap.get("access_token");
+            // 用code换取access_token
+            Map<String, Object> tokenMap = weChatService.getInfoMapByWeb(code, "pc");
+            String accessToken = (String) tokenMap.get("access_token");
             String openid = (String) tokenMap.get("openid");
-            log.info("wx回调openid>>>>>" + openid);
-            log.info("wx回调access_token>>>>>" + access_token);
-            wxInfoMap = weChatService.getUserInfo(access_token, openid);
-            log.info("wx回调openid>>>>>" + wxInfoMap.get("openid"));
-            log.info("wx回调unionid>>>>>" + wxInfoMap.get("unionid"));
+            log.info(">>>>>wx回调openId:" + openid + " ,accessToken"+ accessToken);
+            // 用access_token获取微信用户信息
+            Map<String, Object> infoData = weChatService.getUserInfo(accessToken, openid);
+            log.info(">>>>>wx回调openId:" + infoData.get("openid") + " ,unionId"+ infoData.get("unionid"));
+            // 微信用户信息存入redis
+            redisService.setMap("scan:" + state, infoData);
         } catch (Exception e) {
-            map.put("-1", "获取微信用户信息失败");
+            errorMsg = "获取微信用户信息失败";
         }
-        redisService.setMap("error:" + state, map);
-        redisService.setMap(state, wxInfoMap);
+        // 错误信息存入Redis
+        redisService.set("error:" + state, errorMsg, 1800L);
     }
 
     /**
-     * netty长连接验证登录
-     * @param state     安全认证
-     * @return
+     * 校验扫码结果(长链接)
+     *
+     * @param state   安全认证key(第一步获取参数时自定义生成的uuid)
+     * @return UserLoginVo
      */
     @Override
-    public ResponseJson nettyAuthorization(String state) {
-        if (state == null) {
-            return ResponseJson.error("参数异常");
+    public ResponseJson<UserLoginVo> checkScanAuthResult(String state) {
+        if (StringUtils.isBlank(state)) {
+            return ResponseJson.error("参数异常", null);
         }
-        Map<Object, Object> error = redisService.getEntries("error:" + state);
-        if (null != error && error.size() > 0) {
-            return ResponseJson.error(-1, "错误信息", error);
+        String errorMsg = (String) redisService.get("error:" + state);
+        if (StringUtils.isNotBlank(errorMsg) || !"null".equals(errorMsg)) {
+            return ResponseJson.error("errorMsg", null);
         }
-        Map<Object, Object> wxInfoMap = redisService.getEntries(state);
-        if (null == wxInfoMap || wxInfoMap.size() == 0) {
-            return ResponseJson.error(-90, "redis缓存没有拿到");
+        Map<Object, Object> infoData = redisService.getEntries("scan:" + state);
+        if (null == infoData || infoData.size() == 0) {
+            return ResponseJson.error(-90, "redis缓存的扫码数据没有拿到", null);
         }
-        redisService.remove("state");
-        /*HttpSession session = request.getSession();
-        session.setAttribute("wxInfoMap", wxInfoMap);*/
-        String unionId = (String) wxInfoMap.get("unionid");
-        log.info("pc商城unionId>>>>>>" + unionId);
-        String openid = (String) wxInfoMap.get("openid");
-        log.info("pc商城openid>>>>>>" + openid);
-        UserLoginVo operation = loginMapper.getOperationUserByUnionId(unionId, "www");
-        if (operation == null) {
-            operation = loginMapper.getOperationUserByOpenId(openid, "www");
-            if (operation == null) {
-                return ResponseJson.error(-4, "您的微信尚未绑定任何机构", wxInfoMap);
-            } else if (StringUtils.isBlank(operation.getUnionId())) {
-                // 如果openId存在, unionId不存在
-                loginMapper.updateOperationUnionId(operation.getUserId(), unionId);
-            }
-        // 如果unionId存在, openId不存在
-        } else if (operation.getOpenId() == null) {
-            loginMapper.updateOperationOpenId(operation.getUserId(), openid);
-        }
-        // 获取用户信息
-        UserLoginVo user = loginMapper.getLoginUserByUserId(operation.getUserId());
-        return logonVerify(user);
+        // 清除redis的扫码数据
+        redisService.remove("scan:" + state);
+        String unionId = (String) infoData.get("unionid");
+        String openId = (String) infoData.get("openid");
+        log.info(">>>>>>pc商城unionId:" + unionId + " ,openid:" + openId);
+        // 用户数据存入Redis,key前缀:wxInfo:website:
+        String infoDataStr = JSON.toJSONString(infoData);
+        Map<String, Object> infoDataMap = (Map<String, Object>) JSON.parseObject(infoDataStr);
+        redisService.setMap("wxInfo:website:" + unionId, infoDataMap);
+        log.info("微信扫码登录,用户数据存入Redis,key:wxInfo:website:" + unionId);
+        // 运营人员授权登录
+        return operationAuthLogin(openId, unionId, "www");
     }
 }