微信扫码怎么样获取后端查到的用户信息呢?

如上提问,web端扫码通过微信登录,然后后端获取了用户信息,但怎么准确的传回前端呢?
image.png

首先,web端手机扫码,实际交互的是手机微信和腾讯服务器,最后获取到信息的终端其实是手机。当然服务器也可以获取到。但是怎么样把这个信息准确的发到前端呢?

比如有ABCDEFG个前端,后端怎么准确的把信息发到对应的前端(终端机)呢?

阅读 701
2 个回答

就是标准的 OAuth 2.0 流程。

  • 网站会携带 callback_url 跳转到微信的登录网关
  • 扫码确认后微信网关会携带上 code 跳转回 callback_url
  • 业务端拿到 code 后,使用 code 请求后端接口,后端先换取 access_token,再使用 access_token 换取用户身份信息,返回给前端

这里的 code 就具有短期唯一性,并且是微信那边保证的,为了防跨站攻击,还提供的有 state 参数。

轮询:

function checkLoginStatus(uuid) {
  fetch(`/api/check-login-status?uuid=${uuid}`)
    .then(response => response.json())
    .then(data => {
      if (data.status === 'success') {
       
        console.log('用户信息:', data.userInfo);
        window.location.href = '/dashboard';
      } else if (data.status === 'waiting') {
       
        setTimeout(() => checkLoginStatus(uuid), 2000);
      }
    });
}

fetch('/api/generate-qrcode')
  .then(response => response.json())
  .then(data => {
    const uuid = data.uuid;

    document.getElementById('qrcode').src = data.qrcodeUrl;
    
    checkLoginStatus(uuid);
  });

WebSocket :

const socket = new WebSocket('ws://your-domain.com/ws');
let uuid = '';

socket.onopen = () => {

  socket.send(JSON.stringify({
    type: 'generate_qrcode'
  }));
};

socket.onmessage = (event) => {
  const data = JSON.parse(event.data);
  
  if (data.type === 'qrcode') {

    uuid = data.uuid;
    document.getElementById('qrcode').src = data.qrcodeUrl;
  } else if (data.type === 'login_success') {

    console.log('用户信息:', data.userInfo);
    window.location.href = '/dashboard';
  }
};

@RestController
@RequestMapping("/api/wechat")
public class WechatLoginController {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    
    @GetMapping("/generate-qrcode")
    public Map<String, Object> generateQrcode() {
        String uuid = UUID.randomUUID().toString();
        
        String appId = "你的AppID";
        String redirectUri = URLEncoder.encode("你的回调地址", StandardCharsets.UTF_8);
        String scope = "snsapi_login";
        
        String qrcodeUrl = "https://open.weixin.qq.com/connect/qrconnect" +
                "?appid=" + appId +
                "&redirect_uri=" + redirectUri +
                "&response_type=code" +
                "&scope=" + scope +
                "&state=" + uuid;
        
        Map<String, Object> result = new HashMap<>();
        result.put("uuid", uuid);
        result.put("qrcodeUrl", qrcodeUrl);
        
        return result;
    }
    
    // 微信回调接口
    @GetMapping("/callback")
    public String wechatCallback(@RequestParam String code, @RequestParam String state) {
        // state就是之前生成的uuid
        try {
            // 获取微信用户信息
            WechatUserInfo userInfo = getWechatUserInfo(code);
            
            // 将用户信息存入Redis,设置过期时间5分钟
            redisTemplate.opsForValue().set(
                "wechat:login:" + state,
                new ObjectMapper().writeValueAsString(userInfo),
                5, TimeUnit.MINUTES
            );
            
            return "登录成功,请返回网页";
        } catch (Exception e) {
            return "登录失败:" + e.getMessage();
        }
    }
    
    // 前端轮询接口
    @GetMapping("/check-login-status")
    public Map<String, Object> checkLoginStatus(@RequestParam String uuid) {
        Map<String, Object> result = new HashMap<>();
        
        String userInfoJson = redisTemplate.opsForValue().get("wechat:login:" + uuid);
        if (userInfoJson != null) {
            try {
                // 找到用户信息,登录成功
                WechatUserInfo userInfo = new ObjectMapper().readValue(userInfoJson, WechatUserInfo.class);
                
                // 删除Redis中的数据
                redisTemplate.delete("wechat:login:" + uuid);
                
                result.put("status", "success");
                result.put("userInfo", userInfo);
            } catch (Exception e) {
                result.put("status", "error");
                result.put("message", e.getMessage());
            }
        } else {
            // 未找到用户信息,继续等待
            result.put("status", "waiting");
        }
        
        return result;
    }
    
    // 获取微信用户信息
    private WechatUserInfo getWechatUserInfo(String code) {
        // 微信开放平台参数
        String appId = "你的AppID";
        String appSecret = "你的AppSecret";
        
        // 1. 通过code获取access_token
        String tokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token" +
                "?appid=" + appId +
                "&secret=" + appSecret +
                "&code=" + code +
                "&grant_type=authorization_code";
        
        RestTemplate restTemplate = new RestTemplate();
        String tokenResponse = restTemplate.getForObject(tokenUrl, String.class);
        
        // 解析响应获取access_token和openid
        // 这里简化处理,实际应该使用JSON解析
        JsonNode tokenJson = new ObjectMapper().readTree(tokenResponse);
        String accessToken = tokenJson.get("access_token").asText();
        String openid = tokenJson.get("openid").asText();
        
        // 2. 通过access_token和openid获取用户信息
        String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
                "?access_token=" + accessToken +
                "&openid=" + openid;
        
        String userInfoResponse = restTemplate.getForObject(userInfoUrl, String.class);
        
        // 解析用户信息
        return new ObjectMapper().readValue(userInfoResponse, WechatUserInfo.class);
    }
}

WebSocket:

@ServerEndpoint("/ws/wechat-login/{uuid}")
@Component
public class WechatLoginWebSocket {
    
    private static Map<String, Session> sessionMap = new ConcurrentHashMap<>();
    
    @OnOpen
    public void onOpen(Session session, @PathParam("uuid") String uuid) {
        sessionMap.put(uuid, session);
    }
    
    @OnClose
    public void onClose(@PathParam("uuid") String uuid) {
        sessionMap.remove(uuid);
    }
    
    public static void sendUserInfo(String uuid, WechatUserInfo userInfo) {
        Session session = sessionMap.get(uuid);
        if (session != null) {
            try {
                Map<String, Object> message = new HashMap<>();
                message.put("type", "login_success");
                message.put("userInfo", userInfo);
                
                session.getBasicRemote().sendText(new ObjectMapper().writeValueAsString(message));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题