Laravel 通过 snsapi_base 静默授权获取用户微信公众号 openid

更新日期: 2019-01-04 阅读次数: 9420 分类: Laravel

由于 JSAPI 调用微信支付需要用户的 openid,所以要了解如何获取到 openid。

还是官方的文档说的清楚

https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842

以 snsapi_base 为 scope 发起的网页授权,是用来获取进入页面的用户的 openid 的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面)。

应该是用在登录之后,如果没有绑定 open_id 就应该立即调用授权。

前端判断是否在微信中,同时判断是否有 openid,如果在微信中,已登录并且没有 openid,则跳转。回调回来时,由于带了 code 参数,所以后台 controller 可以直接获取到 openid。并与当前用户关联。(取消 openid 的唯一索引。因为一个用户可能拥有多个手机号,对应同一个 openid)

获取 openid 的时机问题

这取决于业务场景,但是可以肯定的是需要在调用预支付之前,必须获取到 openid。

Laravel 通过 snsapi_base 静默授权获取用户微信公众号 openid

实现代码

$user = Auth::user();
$code = $request->get('code', '');  # redirect_uri/?code=CODE&state=STATE

// 判断是否在微信中
$ua = $request->header('User-Agent');
$is_in_wechat = preg_match('/MicroMessenger/i', $ua);

if ($is_in_wechat && !$user->open_id) {
    // 用户在微信中, 并且没有关联 openid
    if ($code) {
        // 通过 code 获取 open_id
        $client = new Client();
        $url = sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code",
            env('WECHAT_APPID'), env('WECHAT_SECRET'), $code);
        try {
            $res = $client->request('GET', $url, ['timeout' => 1.5]);
            $res = $res->getBody();
            $res = json_decode($res);
            $user->open_id = $res->openid;
            $user->save();
        } catch(\Throwable $e) {
            Log::info('Fail to call api');
        }
    } else {
        // 静默授权,跳转获取 code
        $url = sprintf("https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_base#wechat_redirect",
            env('WECHAT_APPID'), urlencode(env('APP_URL') . '/cart'));
        return redirect($url);
    }
}

返回的 JSON 数据结构

{
  "access_token": "xxx",
  "expires_in": 7200,
  "refresh_token": "xxx",
  "openid": "xxx",
  "scope": "snsapi_base"
}

关于作者 🌱

我是来自山东烟台的一名开发者,有敢兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式