网站首页技术博客

通过微信扫描小程序码登录PC端

洞天水月2021-03-19 08:45:07589人次阅读
摘要因业务需求,需要PC端的管理后台用户,与我们开发的内部小程序管理系统,保持用户和权限的一致性。所以考虑通过微信扫码登录获取小程序的身份。 具体业务逻辑如下: 1、PC端登录页生成当前登录的key值,带着key值请求后端接口,获取授权登录的小程序码,并轮询后端接口查看该key值对应的小程序码是否被用户扫描和授权。 2、后端生成一个带有key值参数的小程序码,并将此key值记录。 3、通过用户

因业务需求,需要PC端的管理后台用户,与我们开发的内部小程序管理系统,保持用户和权限的一致性。所以考虑通过微信扫码登录获取小程序的身份。

具体业务逻辑如下:

1、PC端登录页生成当前登录的key值,带着key值请求后端接口,获取授权登录的小程序码,并轮询后端接口查看该key值对应的小程序码是否被用户扫描和授权。

2、后端生成一个带有key值参数的小程序码,并将此key值记录。

3、通过用户微信扫描小程序码,拿到对应的key值参数,将此key值和当前小程序用户的身份特征(token)传给后台,告知用户已扫描并点击登录。

4、后台标记此key值用户已登录,并记录用户登录身份,并通过PC端的轮询接口,告知其用户已登录。

5、PC端轮询到用户登录后,带着key值跳转到小程序登录中间页,在中间页PC端后台完成key值和用户信息的转换,记入session,然后跳转到对应的登录后的页面。

 

PC端登录页代码:

function initLoginImg() {
        require(["md5"], function (md5) {
            var timestamp = md5.hash(Date.parse(new Date()) + "_" + parseInt(Math.random() * 100000));
            $("#miniLoginCodeImg").html('image');
            var timer = setInterval(function () {
                get('/api/mini.login_pc/checkLogin', {'scene': timestamp}, false, function (res) {
                    if (res !== "0") {
                        window.location.href = "/admin/login/mini?scene=" + timestamp;
                    }
                }, function (res) {
                  ...
                    clearInterval(timer);
                });
            }, 2500);
        });
    }

    initLoginImg();

PC端生成小程序码:

/**
     * 生成扫码登录小程序码
     * @return Response
     */
    public function miniLogin()
    {
        $params = $this->request->param();
        $rule = [
            'scene' => 'require',
        ];
        try {
            $this->validate($params, $rule);
        } catch (ValidateException $e) {
            return error($e->getMessage());
        }
        $scene = Arr::get($params, 'scene');
        $path = 'pages/landing/landing';
        $cacheKeyService = CacheService::MiniLoginPC;
        $key = Arr::get($cacheKeyService, 'key');
        $expire = Arr::get($cacheKeyService, 'expire');
        Cache::set($key . $scene, '0', $expire);
        $optional = [
            'page' => $path,
            'width' => 30
        ];
        $app = $this->getMiniApp();
        $response = $app->app_code->getUnlimit($scene, $optional);
        return response($response, 200, ['Content-Type' => 'image/png'], 'html');
    }

扫码登录接口:

/**
     * 扫码登录
     * @return \think\response\Json
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function scanCode()
    {
        $user = $this->request->user;
        $params = $this->request->param();
        $rule = [
            'scene' => 'require',
        ];
        $scene = Arr::get($params, 'scene');
        $cacheService = CacheService::MiniLoginPC;
        $key = Arr::get($cacheService, 'key');
        $isLogin = Cache::get($key . $scene);
        if ($isLogin != "0" && empty($isLogin)) {
            return error("登录失败,请重新扫码");
        }
        try {
            $this->validate($params, $rule);
        } catch (ValidateException $e) {
            return error($e->getMessage());
        }
        //1、查找系统用户是否存在
        $systemUser = SystemUserModel::where('openid', '=', $user->openid)->find();
        //2、用户不存在则创建
        if (empty($systemUser)) {
            $systemUser = SystemUserService::instance()->createByWechatUser($user, $this->request);
        }
        //3、将用户写入redis
        $expire = Arr::get($cacheService, 'expire');
        Cache::set($key . $scene, $systemUser, $expire);
        return success(true);
    }

校验用户是否扫码接口:

/**
     * 校验用户是否扫码
     */
    public function checkLogin()
    {
        $params = $this->request->param();
        $rule = [
            'scene' => 'require',
        ];
        try {
            $this->validate($params, $rule);
        } catch (ValidateException $e) {
            return error($e->getMessage());
        }
        $scene = Arr::get($params, 'scene');
        $cacheService = CacheService::MiniLoginPC;
        $key = Arr::get($cacheService, 'key');
        $isLogin = Cache::get($key . $scene);
        if ($isLogin != "0" && empty($isLogin)) {
            return error("登录码已过期");
        }
        return success($isLogin);
    }

登录中间页:

/**
     * 小程序登录
     * @return \think\response\Redirect
     */
    public function mini()
    {
        $params = $this->request->param();
        $scene = Arr::get($params, 'scene');
        if (empty($scene)) {
            $this->error('登录场景值为空', sysuri('admin/login'));
        }
        $cacheConfig = CacheService::MiniLoginPC;
        $key = Arr::get($cacheConfig, 'key') . $scene;
        $systemUser = Cache::get($key);
        if (empty($systemUser)) {
            $this->error('小程序码已过期,请重新扫码', sysuri('admin/login'));
        }
        if (empty($systemUser['status'])) {
            $this->error('该用户已禁用,请联系管理员', sysuri('admin/login'));
        }
        Session::set('user', $systemUser);
        Session::delete("login_input_session_error");
        SystemUserModel::where('id', '=', $systemUser['id'])->update([
            'login_ip' => $this->request->ip(),
            'login_at' => date('Y-m-d H:i:s'),
            'login_num' => Db::raw('login_num+1'),
        ]);
        sysoplog('用户登录', '登录系统后台成功');
        return redirect('/admin');
    }

 

文章评论