Skip to content
nodejs扫码授权夸克网盘获取cookie

使用nodejs+express制作接口,,代码如下

其中uuid版本要为8.3.2

js
npm install uuid@8.3.2

然后再根据下方代码需要安装其他依赖即可

提供的是两个接口:

  1. 获取登录二维码 // 获取登录二维码的token
  2. 检查登录状态 // 检查登录状态,返回用户信息和cookie字符串
js
/**
 * 获取夸克网盘登录二维码并检查登录状态
 */

const express = require('express');
const router = express.Router();
const axios = require('axios');
const { v4: uuidv4 } = require('uuid');

const sameFormat = (code = 200, msgData = '请求成功', data = null) => {
    return {
        code,
        msg: msgData,
        data
    }
}

/**
 * 获取登录二维码
 */
router.post('/getQrCode', async (req, res, next) => {
    try {
        const apiUrl = 'https://uop.quark.cn/cas/ajax/getTokenForQrcodeLogin';
        const requestId = uuidv4();

        const params = {
            client_id: '532',
            v: '1.2',
            request_id: requestId
        };

        const client = axios.create({
            timeout: 30000,
            headers: {
                'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36',
                'Accept': 'application/json, text/plain, */*',
                'Accept-Language': 'zh-CN,zh;q=0.9'
            }
        });

        console.log('正在获取二维码token...');
        const response = await client.get(apiUrl, { params });

        if (response.status === 200) {
            const data = response.data;

            if (data.status === 2000000) {
                const token = data.data?.members?.token;
                if (token) {
                    console.log(`✓ 获取到二维码token: ${token}`);

                    const baseUrl = "https://su.quark.cn/4_eMHBJ";
                    const qrParams = new URLSearchParams({
                        token: token,
                        client_id: '532',
                        ssb: 'weblogin',
                        uc_param_str: '',
                        uc_biz_str: 'S:custom|OPT:SAREA@0|OPT:IMMERSIVE@1|OPT:BACK_BTN_STYLE@0'
                    });

                    const qrUrl = `${baseUrl}?${qrParams.toString()}`;

                    console.log('二维码URL:', qrUrl);

                    res.status(200).send(sameFormat(200, '获取二维码成功', {
                        token,
                        qrUrl
                    }));
                } else {
                    console.log('✗ 响应中未找到token');
                    res.status(500).send(sameFormat(500, '响应中未找到token'));
                }
            } else {
                console.log(`✗ 获取token失败: ${data.message || '未知错误'}`);
                res.status(500).send(sameFormat(500, `获取token失败: ${data.message || '未知错误'}`));
            }
        } else {
            console.log(`✗ API请求失败: ${response.status}`);
            res.status(500).send(sameFormat(500, `API请求失败: ${response.status}`));
        }

    } catch (error) {
        console.log(`✗ 获取二维码失败: ${error.message}`);
        res.status(500).send(sameFormat(500, `获取二维码失败: ${error.message}`));
    }
});

/**
 * 检查登录状态
 */
router.post('/checkLoginStatus', async (req, res, next) => {
    const { token } = req.body; // 传入登录二维码的token

    if (!token) {
        return res.status(400).send(sameFormat(400, 'token不能为空'));
    }
    const db = req.app.get('db');
    try {
        const apiUrl = 'https://uop.quark.cn/cas/ajax/getServiceTicketByQrcodeToken';
        const requestId = uuidv4();

        const params = {
            client_id: '532',
            v: '1.2',
            token: token,
            request_id: requestId
        };

        const client = axios.create({
            timeout: 10000,
            headers: {
                'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36',
                'Accept': 'application/json, text/plain, */*'
            }
        });

        const response = await client.get(apiUrl, { params });

        if (response.status === 200) {
            const data = response.data;

            // 检查登录状态
            if (isLoginSuccess(data)) {
                console.log('✓ 登录成功');
                // 获取用户信息和Cookie
                const serviceTicket = data.data.members.service_ticket;
                const { userInfo, cookieString } = await getUserInfoAndCookies(serviceTicket);

                return res.status(200).send(sameFormat(200, '登录成功', {
                    userInfo, // 用户信息
                    cookieString // Cookie字符串 (和浏览器f12获取的格式不一样,,但是可以正常使用,没问题的)
                }));
            } else if (isLoginFailed(data)) {
                console.log('✗ 登录失败');
                res.status(400).send(sameFormat(400, '登录失败'));
            } else {
                // 还在等待扫码
                console.log('等待扫码中');
                res.status(200).send(sameFormat(200, '等待扫码中', {
                    status: 'waiting'
                }));
            }
        } else {
            res.status(200).send(sameFormat(200, '等待扫码中', {
                status: 'waiting'
            }));
        }

    } catch (error) {
        console.log(`检查登录状态出错: ${error.message}`);
        res.status(500).send(sameFormat(500, '检查登录状态出错'+error.message));
    }
});

/**
 * 判断是否登录成功
 */
function isLoginSuccess(data) {
    if (!data || typeof data !== 'object') {
        return false;
    }

    const status = data.status;
    const message = data.message || '';

    // 登录成功的标志:status=2000000, message="ok", 且有data.members.service_ticket
    return (
        status === 2000000 &&
        message === 'ok' &&
        data.data?.members?.service_ticket
    );
}

/**
 * 判断是否登录失败
 */
function isLoginFailed(data) {
    if (!data || typeof data !== 'object') {
        return false;
    }

    const status = data.status;
    const message = (data.message || '').toLowerCase();

    // 明确的失败状态(不包括50004001,那是等待状态)
    const failIndicators = [
        [50004002, 50004003, 50004004].includes(status),
        message.includes('expired'),
        message.includes('failed'),
        message.includes('error'),
        message.includes('timeout'),
        message.includes('invalid')
    ];

    return failIndicators.some(indicator => indicator);
}

/**
 * 获取用户信息和Cookie
 */
async function getUserInfoAndCookies(serviceTicket) {
    try {
        const apiUrl = 'https://pan.quark.cn/account/info';

        const params = {
            st: serviceTicket,
            lw: 'scan'
        };

        const client = axios.create({
            timeout: 30000,
            headers: {
                'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36',
                'Accept': 'application/json, text/plain, */*'
            }
        });

        console.log('正在获取用户信息...');
        const response = await client.get(apiUrl, { params });

        if (response.status === 200) {
            const userInfo = response.data;
            console.log('✓ 用户信息获取成功');

            // 提取Cookie
            const cookies = response.headers['set-cookie'] || [];
            const cookieString = cookies.map(cookie => {
                // 只提取cookie名称和值
                return cookie.split(';')[0];
            }).join('; ');

            console.log(`✓ 获取到Cookie: ${cookieString.substring(0, 50)}...`);

            return { userInfo, cookieString };
        } else {
            throw new Error(`获取用户信息失败: ${response.status}`);
        }

    } catch (error) {
        console.log(`✗ 获取用户信息失败: ${error.message}`);
        throw error;
    }
}

module.exports = router;