Skip to content

扫码登录,非对称版本

登录流程

  1. 站点登录页增加扫码登录按钮
  2. 用户点击扫码登录按钮
  3. 登录页请求/plugin/ledc/push/config接口,获取websocket长连接参数
  4. 长连接参数内channel_name为唯一的频道名称(会话ID)
  5. 通过push.js建立与爱语飞飞的websocket长连接
  6. 登录页请求/qrcode/create?scene=oauth&force_refresh=1接口,获取二维码并展示
  7. 用户使用微信扫一扫,扫描二维码
  8. 爱语飞飞通过长连接推送用户身份凭证到站点的登录页
  9. 站点登录页转发channel_name用户身份凭证到站点后端登录接口
  10. 后端使用非对称公钥验签用户身份凭证是否来自爱语飞飞
  11. 验证通过后,站点做登录成功的操作

在线演示

扫码登录在线演示

前端代码

https://iyuu.cn/scan_login.js

后端代码

安装依赖包 composer require ledc/crypt

php
/**
 * 爱语飞飞扫码登录
 * @param Request $request
 * @return Response
 */
public function index(Request $request): Response
{
    [$payload, $signature, $key] = $request->postMore(['payload/s', 'signature/s', 'key/s'], true);
    if (empty($payload)) {
        return $this->fail('payload is empty');
    }
    if (empty($signature)) {
        return $this->fail('signature is empty');
    }
    if (empty($key)) {
        return $this->fail('key is empty');
    }

    try {
        Limit::perMinute($request->getRealIp(), 6);
        $rsaCrypt = make_rsa_crypt_instance($key);
        $data = $rsaCrypt->decrypt($payload, $signature);
        $rocket = new WechatAccountRocket($data);
        /** @var User|null $user */
        $user = User::find($rocket->uuid);
        if (empty($user) || 0 !== (int)$user->status) {
            return $this->fail('当前账户已经被禁用');
        }

        /** @var WechatUser|null $wechatUser */
        $wechatUser = WechatUser::find($rocket->weid);
        if (empty($wechatUser) || !password_verify($wechatUser->token, $rocket->token_password_hash)) {
            return $this->fail('登录失败:token哈希与登录方不一致');
        }

        UserServices::login($user);

        return $this->success();
    } catch (Throwable $throwable) {
        return $this->fail($throwable->getMessage());
    }
}