【微信】微信开放平台第三方授权登录获取用户信息

背景:

2021-12-27 微信 cgi-bin/user/info 接口不再提供用户头像和昵称信息,大家无法在用户扫码通过关注事件无感知到拿到相关信息了;

按官方说法,获取用户头像昵称数据都需要用户前端网页授权,需要使用 sns/userinfo 接口;

补充:此方案针对的是公众号授权开放平台之后的,获取用户信息的流程;如果是独立的公众号或小程序,理论上和这个流程大体一致,但更为简单;如有疑问可以在评论留言。

方案流程如下:

如果是纯服务端开发,没有前端页面跳转,则需要有个跳转获取code的过程;

// 1.微信登录;第一次没有code,会自跳转生成一个code
public function wxLogin()
{
    
    
  $appid = I('appid'); // 某一个公众号的appid
  if (!isset($_GET['code'])) {
    
    
      $this->getCode($appid);
  }
  $tokenData = $this->getComponentAccessToken($appid, $_GET['code']);
  if (empty($tokenData['status']) {
    
    
      echo '授权失败'
      exit;
  }
  $userInfo = $this->getUserInfo($tokenData['data']['openid'], $tokenData['data']['access_token']);
  return $userInfo;
}

// 自跳转过程
public function getCode($appid, $scope='snsapi_userinfo')
{
    
    
  $request = array(
    'appid' => $appid,
    'redirect_uri' => get_request_scheme().$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'],
    'response_type' => 'code',
    'scope' => $scope,
    'state' => 'state',
    'component_appid' => C('APPID'), // 开放平台的appid
  );
  $url = 'https://open.weixin.qq.com/connect/oauth2/authorize?'.http_build_query($request).'#wechat_redirect';
  header("location: {
      
      $url}");
  exit;
}


// 2.获取该appid授权的开放平台的access_token
public function getComponentAccessToken($appid, $code): array
{
    
    
  $url = "sns/oauth2/component/access_token";
  $param = [
    'appid' => $appid,
    'code' => $code,
    'grant_type' => 'authorization_code',
    'component_appid' =>  C('APPID'), // 开放平台的appid
    'component_access_token' => $this->componentToken(),
  ];

  $fetchData = $this->curlGet($url . '?' . http_build_query($param));

  if (empty($fetchData)) {
    
    
    return ['status' => 0, 'msg' => '微信服务器登录失败', 'data' => []];
  }

  //错误返回 {"errcode":40029,"errmsg":"invalid code"}
  //正确返回 {"access_token":"ACCESS_TOKEN","expires_in":7200,"refresh_token":"REFRESH_TOKEN","openid":"oINQu5d6uAwEhIgFvpbah4atffbc","scope":"SCOPE"}
  $fetchData = json_decode($fetchData, true);
  if (isset($fetchData['errcode'])) {
    
    
    return ['status' => 0, 'msg' => $fetchData['errcode'] . '-' . $fetchData['errmsg'], 'data' => $fetchData];
  }

  return ['status' => 1, 'msg' => '', 'data' => $fetchData];
}


// 3. 获取公众号用户信息
// https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
public function getUserInfo($openid, $access_token): array
{
    
    
  $param = [
    'access_token' => $access_token,
    'openid' => $openid,
    'lang'=>'zh_CN',
  ];

  $url = "sns/userinfo";
  //请求失败:{"errcode":40003,"errmsg":" invalid openid "}
  //请求成功:{
    
    
  //  "openid": "OPENID",
  //  "nickname": NICKNAME,
  //  "sex": 1,
  //  "province":"PROVINCE",
  //  "city":"CITY",
  //  "country":"COUNTRY",
  //  "headimgurl":"https://thirdwx.qlogo.cn/mmopen/xxxxxxxbx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
  //  "privilege":[ "PRIVILEGE1" "PRIVILEGE2"     ],
  //  "unionid": "o6_bmasdasdsad6_xxxxxx"
  //}
  $fetchData = $this->curlGet($url . '?' . http_build_query($param));
  if (empty($fetchData)) {
    
    
    return ['status' => 0, 'msg' => '微信服务器获取用户信息失败', 'data' => []];
  }

  $fetchData = json_decode($fetchData, true);

  if (isset($fetchData['errcode'])) {
    
    
    return ['status' => 0, 'msg' => $fetchData['errcode'] . '-' . $fetchData['errmsg'], 'data' => $fetchData];
  }

  return ['status' => 1, 'msg' => '', 'data' => $fetchData];
}

public function curlGet($url, $headers = [])
{
    
    
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_HEADER, 0);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($ch, CURLOPT_TIMEOUT, 10);
  curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

  $data = curl_exec($ch);
  curl_close($ch);
  return $data;
}

// 获取第三方平台component_access_token
// {"component_access_token":"8BINO1szMZtuJshySnl6TEMXkmSdM-E8le1yzC4U9tPmLUr2wLEUJCaL9QIxFPT_OcoXAkNDMpm0HuPJzFASitiS-Daskk1URPy7xaUe1yNCPu_73oVDyXYsqFg0zVmxXVVjAHATRR","expires_in":7200}
// 每个令牌是存在有效期(2小时)的,且令牌的调用不是无限制的,请第三方平台做好令牌的管理,在令牌快过期时(比如1小时50分)再进行刷新
public function componentToken() {
    
    
  $redis = new Redis();
  $componenttoken = $redis->get(C('CTKEY'));
  if (!empty($componenttoken)) return $componenttoken;
	
  // VTKEY 参考https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/2.0/api/Before_Develop/creat_token.html
  // 需要在微信服务器推送的时候存起来; 在这里用上
  $verifyticket = $redis->get(C('VTKEY'));
  $params = array(
    'component_appid' => C('APPID'),
    'component_appsecret' => C('APPSECRET'),
    'component_verify_ticket' => $verifyticket,
  );
  $ret = $this->curlGet('cgi-bin/component/api_component_token', $params);
  $redis->set(C('CTKEY'), $ret['component_access_token'], C('CTTTL'));
  return $ret['component_access_token'];
}

参考官方文档

猜你喜欢

转载自blog.csdn.net/Kevin_Gates/article/details/129432036