Как войти в API MediaWiki (Wikipedia) в Node.js

Я пытаюсь описать процесс входа клиента из Википедии в API: Документация для входа, но что-то не так:

1) я правильно получаю токен с HTTP GEThttps://en.wikipedia.org/w/api.php?action=query&meta=tokens&type=login&format=json

и я получаю действительныйlogintokenстрока.

2.1) Я тогда попробуюclientloginлайк:

HTTP POST/w/api.php?action=clientlogin&format=json&lgname=xxxx&lgtoken=xxxx%2B%5C

и ПОЧТА ТЕЛА была

{
    "lgpassword" : "xxxxx",
    "lgtoken" : "xxxxx"
}

Но я получаю ошибку:

{
  "error": {
    "code": "notoken",
    "info": "The \"token\" parameter must be set."
 },
  "servedby": "mw1228"
}

Если я попытаюсь изменитьlgtokenвtokenЯ получаю тот же результат.

2.2) Затем я попробовал старый метод, т.е.action=loginи передает тело, но оно не работает, так как возвращает мне еще один токен входа в систему: HTTP POSThttps://en.wikipedia.org/w/api.php?action=login&format=json&lgname=xxxx

и тот же почтовый орган

Я тогда получаю

{
  "warnings": {}
  },
  "login": {
    "result": "NeedToken",
    "token": "xxxxx+\\"

}

где документы утверждают, что

NeedToken if the lgtoken parameter was not provided or no session was active (e.g. your cookie handling is broken).

но я прошел lgtoken в теле JSON, как показано. Я использую Node.js и встроенный http модуль, который должен пройти и сохранить сессию Cookies в правильном направлении (с другими API это работает нормально).

Я нашел похожую проблему на клиенте LrMediaWiki здесь.

[ОБНОВЛЕНИЕ] Это моя текущая реализация:

  Wikipedia.prototype.loginUser = function (username, password) {
      var self = this;
      return new Promise((resolve, reject) => {

        var cookies = self.cookies({});
        var headers = {
          'Cookie': cookies.join(';'),
          'Accept': '*/*',
          'User-Agent': self.browser.userAgent()
        };
        // fetch login token
        self.api.RequestGetP('/w/api.php', headers, {
          action: 'query',
          meta: 'tokens',
          type: 'login',
          format: 'json'
        })
          .then(response => { // success
            if (response.query && response.query.tokens && response.query.tokens['logintoken']) {
              self.login.logintoken = response.query.tokens['logintoken'];
              self.logger.info("Wikipedia.login token:%s", self.login);
              return self.api.RequestPostP('/w/api.php', headers, {
                action: 'login',
                format: 'json',
                lgname: username
              },
                {
                  lgpassword: password,
                  lgtoken: self.login.logintoken
                });
            } else {
              var error = new Error('no logintoken');
              return reject(error);
            }
          })
          .then(response => { // success
            return resolve(response);
          })
          .catch(error => { // error
            self.logger.error("Wikipedia.login error%s\n%@", error.message, error.stack);
            return reject(error);
          });
      });
    }//loginUser

где this.api это простая оболочка для Node.js http, исходный код доступен здесь, а подписи API выглядят так:

Promise:API.RequestGetP(url,headers,querystring)
Promise:API.RequestPostP(url,headers,querystring,body)

2 ответа

Если принятый в настоящее время ответ у кого-то не работает, следующий метод определенно сработает. Я использовал библиотеку axios для отправки запросов. Можно использовать любую библиотеку, но ключ кроется в правильном форматировании тела и заголовков.

      let url = "https://test.wikipedia.org/w/api.php";

let params = {
    action: "query",
    meta: "tokens",
    type: "login",
    format: "json"
};

axios.get(url, { params: params }).then(resp => {
    let loginToken = resp.data.query.tokens.logintoken
    let cookie = resp.headers["set-cookie"].join(';');

    let body = {
        action: 'login',
        lgname: 'user_name',
        lgpassword: 'password',
        lgtoken: loginToken,
        format: 'json'
    }
    let bodyData = new URLSearchParams(body).toString();

    axios.post(url, bodyData, {
        headers: {
            Cookie: cookie,
        }
    }).then(resp => {
        // You're now logged in!

        // You'll have to add the following cookie in the headers again for any further requests that you might make
        let cookie = resp.headers["set-cookie"].join(';')

        console.log(resp.data)
    })
})

И вы должны увидеть ответ вроде

      {
    login: { result: 'Success', lguserid: 0000000, lgusername: 'Username' }
}

Второй почтовый запрос был там, где я застрял на несколько часов, пытаясь понять, что не так. Вам необходимо отправить данные в закодированной форме с помощью API, такого как URLSearchParams, или просто вручную набрав текст в виде строки.

Я думаю, из того, что вы говорите, у вас есть lgtoken а также lgname в URL-адресе, который вы используете, а затем lgpassword а также lgtoken (снова!) в теле POST в JSON-кодировке.

Это не то, как работает Mediawiki API.

Вы отправляете все это как параметры POST. JSON никогда не участвует, за исключением случаев, когда вы запрашиваете возвращение результата в этом формате. Я не могу помочь вам исправить ваш код, поскольку вы его не предоставляете, но это то, что вам нужно сделать. (Если вы измените свой вопрос с помощью своего кода, я сделаю все возможное, чтобы помочь вам.)

После просмотра вашего кода я предположу (не зная деталей вашего кода), что вы хотите что-то вроде этого:

          return self.api.RequestPostP('/w/api.php', headers, {
            action: 'login',
            format: 'json',
            lgname: username,
            lgpassword: password,
            lgtoken: self.login.logintoken
          });
Другие вопросы по тегам