5

我正在尝试API:Login文档中描述的Wikipedia客户端登录流程,但发生了一些错误:

1) 我正确地获得了一个使用 HTTP GET 提出的令牌https://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

POST BODY 是

{
    "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

和相同的 POST BODY

然后我得到

{
  "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).

但如图所示,我已经通过了lgtokenjson 正文。我正在使用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)
4

2 回答 2

3

认为从您所说的内容lgtoken和您正在使用的 URL 中,lgname然后(再次!)在 JSON 编码的 POST 正文中。lgpasswordlgtoken

这不是 Mediawiki API 的工作方式。

您将其全部作为 POST 参数提交。永远不会涉及 JSON,除非您要求以该格式返回结果。由于您不提供代码,因此我无法帮助您修复代码,但这就是您需要做的。(如果您使用代码编辑问题,我会尽力帮助您。)

看到你的代码后,我会假设(不知道你的代码细节)你想要这样的东西:

          return self.api.RequestPostP('/w/api.php', headers, {
            action: 'login',
            format: 'json',
            lgname: username,
            lgpassword: password,
            lgtoken: self.login.logintoken
          });
于 2018-03-19T16:18:52.123 回答
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' }
}

第二个帖子请求是我被困了几个小时,试图找出问题所在。您需要使用 URLSearchParams 之类的 API 以编码形式发送数据,或者只需手动将正文键入为字符串。

于 2021-05-14T17:04:43.583 回答