使用JavaScript进行基本认证

25
我正在构建一个应用程序,该应用程序使用Caspio API。我在认证其API时遇到了一些问题。我已经花费了2-3天的时间来解决这个问题,但可能是由于我自己的理解不够深入。我已经阅读了无数的stackoverflow帖子和其他文章,但没有解决这个问题。下面是我的解决方案的代码示例,基于我所查看的内容,我得到了400状态代码消息;我在这里做错了什么?(请提供良好注释的代码示例,并且我更喜欢在此处发布引用其他材料的链接,因为我已经广泛地查看了这些材料。谢谢!):

我查看过的一些参考资料:

1)纯JavaScript代码实现HTTP基本认证?

2)如何从JavaScript中进行REST API调用的HTTP身份验证

我想使用以下由caspio描述的身份验证方法:

作为包含凭据的请求主体的替代方法,客户端可以使用HTTP基本身份验证方案。在这种情况下,将使用以下方式设置认证请求:

方法:POST

URL:您的令牌终结点

主体:grant_type=client_credentials

标头参数:

Authorization:Basic Basic authentication realm

以下是我的JavaScript和HTML代码。

JavaScript:

var userName = "clientID";
var passWord = "secretKey";

function authenticateUser(user, password)
{
    var token = user + ":" + password;

    // Should i be encoding this value????? does it matter???
    // Base64 Encoding -> btoa
    var hash = btoa(token); 

    return "Basic " + hash;
}

function CallWebAPI() {

    // New XMLHTTPRequest
    var request = new XMLHttpRequest();
    request.open("POST", "https://xxx123.caspio.com/oauth/token", false);
    request.setRequestHeader("Authorization", authenticateUser(userName, passWord));  
    request.send();
    // view request status
    alert(request.status);
    response.innerHTML = request.responseText;
}

HTML:

<div>
<div id="response">

</div>
<input type="button" class="btn btn-primary" value="Call Web API" onclick="javascript:CallWebAPI();" />

5个回答

14

在花费了相当长的时间研究之后,我找到了这个解决方案;在这个解决方案中,我没有使用基本身份验证,而是采用了oAuth身份验证协议。但是要使用基本身份验证,您应该能够在“setHeaderRequest”中指定此选项,并对其余代码示例进行最小更改。希望这能帮助将来的某个人:

var token_ // variable will store the token
var userName = "clientID"; // app clientID
var passWord = "secretKey"; // app clientSecret
var caspioTokenUrl = "https://xxx123.caspio.com/oauth/token"; // Your application token endpoint  
var request = new XMLHttpRequest(); 

function getToken(url, clientID, clientSecret) {
    var key;           
    request.open("POST", url, true); 
    request.setRequestHeader("Content-type", "application/json");
    request.send("grant_type=client_credentials&client_id="+clientID+"&"+"client_secret="+clientSecret); // specify the credentials to receive the token on request
    request.onreadystatechange = function () {
        if (request.readyState == request.DONE) {
            var response = request.responseText;
            var obj = JSON.parse(response); 
            key = obj.access_token; //store the value of the accesstoken
            token_ = key; // store token in your global variable "token_" or you could simply return the value of the access token from the function
        }
    }
}
// Get the token
getToken(caspioTokenUrl, userName, passWord);

如果您在使用Caspio REST API时需要对某些请求的参数进行编码以发送到终点,则可能非常必要。请参阅Caspio文档以了解此问题;

注意:在此示例中未使用encodedParams,但在我的解决方案中使用了它。

现在,您已经从令牌终点存储了令牌,您应该能够成功地进行身份验证,以便在您的应用程序的Caspio资源终点上进行后续请求

function CallWebAPI() {
    var request_ = new XMLHttpRequest();        
    var encodedParams = encodeURIComponent(params);
    request_.open("GET", "https://xxx123.caspio.com/rest/v1/tables/", true);
    request_.setRequestHeader("Authorization", "Bearer "+ token_);
    request_.send();
    request_.onreadystatechange = function () {
        if (request_.readyState == 4 && request_.status == 200) {
            var response = request_.responseText;
            var obj = JSON.parse(response); 
            // handle data as needed... 

        }
    }
} 

这个解决方案只考虑了如何在纯JavaScript中成功使用Caspio API进行身份验证的请求。我相信仍然存在许多缺陷...


6
这实际上不是问题的解决方案,该问题特别涉及基本认证(Basic Auth)。 - Steve Bennett
1
我认为我在我的原始答案中已经解释了你的观点。虽然,这是一个使用不同的身份验证方法完成相同任务的替代方法。请阅读完整的答案。 - Rex Charles

9
今天我们更经常使用Bearer令牌而不是基本身份验证,但如果您想先使用基本身份验证来获取Bearer令牌,则有几种方法:
const request = new XMLHttpRequest();
request.open('GET', url, false, username,password)
request.onreadystatechange = function() {
        // D some business logics here if you receive return
   if(request.readyState === 4 && request.status === 200) {
       console.log(request.responseText);
   }
}
request.send()

完整的语法请参考此处

第二种使用Ajax的方法:

$.ajax
({
  type: "GET",
  url: "abc.xyz",
  dataType: 'json',
  async: false,
  username: "username",
  password: "password",
  data: '{ "key":"sample" }',
  success: function (){
    alert('Thanks for your up vote!');
  }
});

希望这能为你提供一个线索,从哪里开始使用JS进行API调用。在像Angular、React等框架中,有更强大的方式使用基本身份验证或Oauth身份验证进行API调用。请自行探索。

0
为了让这个问题保持最新,一个使用node-fetch的node.js解决方案如下:
    const auth = Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
    fetch("https://some-oauth2.server.com/connect/token", {
      method: "POST",
      body: "grant_type=client_credentials",
      headers: {
        "Content-type": "application/x-www-form-urlencoded",
        Authorization: `Basic ${auth}`,
      },
    })
      .then((response) => response.json())
      .then((response) => {
        console.log(response); //response.access_token is bearer token, response.expires_in is lifetime of token
      });

敏感请求应该是服务器对服务器的,将凭证细节保存在Header中而不是QueryString中意味着它不太可能在Web服务器日志中可见。

-5

EncodedParams变量被重新定义为params变量是不起作用的。你需要有相同的预定义调用变量,否则可能需要更多的工作。干杯!在php中,json没有充分利用其功能,有更好的方法来调用json,但我现在无法回忆起来。


-9

将用户名、密码、token_和key变量的var改为const。


这与问题无关,不应该作为答案发布。 - Tom
@Tom,我认为这个回答并不需要被标记。我已经给它点了踩。 - GuedesBF

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接