JavaScript客户端对REST API的授权和身份验证

时间:2021-07-25 20:04:50

I'm building a PHP REST API that will be utilized from a JavaScript client, and am having some issues figuring out how to implement the auth and access side of things. There will be multiple applications that will use a JavaScript library that I'll be developing to talk and interact with my application. I'll be providing API keys to each of them, so that's not an issue.

我正在构建一个将从JavaScript客户端使用的PHP REST API,并且在解决如何实现身份验证和访问方面存在一些问题。将有多个应用程序将使用我将开发的JavaScript库来与我的应用程序交谈和交互。我将为每个人提供API密钥,因此这不是问题。

Where I start getting confused is how to have the users on these sites authenticate to my application. It seems like a bad idea to have this external site store my user's account and password information; so, I guess I should have my JavaScript library include a login widget that asks for the user's account info for my application.

我开始感到困惑的地方是如何让这些网站上的用户对我的应用程序进行身份验证。让这个外部网站存储我的用户的帐户和密码信息似乎是一个坏主意;所以,我想我应该让我的JavaScript库包含一个登录小部件,询问用户的应用程序的帐户信息。

If authentication is successful there, since I'm working with a REST API, I'll need to store the token retrieved in a client side cookie or something so that the user doesn't need to login to my application again on every page of the external site. However, what happens if the user logs out of the external site, and then another user logs in from the same browser? As far as my JavaScript library is concerned, the old user would still be logged into my application, because the cookie/token would not have expired yet - how can I clear my cookie when the previous user's session ends? Or, am I completely off the right path here?

如果身份验证成功,由于我正在使用REST API,我需要将检索到的令牌存储在客户端cookie或其他东西中,这样用户就不需要在每个页面上再次登录我的应用程序。外部网站。但是,如果用户退出外部站点,然后另一个用户从同一浏览器登录,会发生什么?就我的JavaScript库而言,旧用户仍然会登录到我的应用程序,因为cookie /令牌尚未过期 - 如何在前一个用户的会话结束时清除我的cookie?或者,我完全偏离了正确的道路吗?

So, I'm thinking the process would be something like:

所以,我认为这个过程会是这样的:

var token; // Some hashed string containing an expiration date and user id
var apiKey = '123abc';

// Read the cookie and check if it already contains the token
token = readCookie('token');
if (token == '') {
    // get username and password from user through some prompt

    var request_data = {apiKey: apiKey, user: username, pass: password};
    $.post('https://service.com/api/user/login', request_data, function(data) {
        token = data;
        document.cookie = "token=" + token;
    });
}

...

var get_data = {apiKey: apiKey, token: token};
$.get('http://service.com/api/<object>', get_data, function(data) {
    // Do something with data
});

Sorry, there's several questions buried in here. I guess the main one is if I'm storing the token to a cookie, how do I ensure that it is cleared when the user logs off of the external application? Or, if I shouldn't be storing it to a cookie, how do I keep the client aware of the user's state?

对不起,这里有几个问题。我想主要的一个是如果我将令牌存储到cookie中,当用户注销外部应用程序时,如何确保将其清除?或者,如果我不应该将其存储到cookie中,如何让客户端了解用户的状态?

3 个解决方案

#1


40  

I suggest you to read this very good blog post about securing a RESTful API.

我建议你阅读这篇关于保护RESTful API的博文。

(In case that link doesn't work—it has already gone dead once and has to be retrieved from archive.org—I found what it seems to be a PDF render of this page accessible here: https://www.ida.liu.se/~TDDD97/labs/hmacarticle.pdf.)

(如果链接不起作用 - 它已经死了一次并且必须从archive.org检索 - 我发现这个页面的PDF呈现在这里可以访问:https://www.ida。 liu.se/~TDDD97/labs/hmacarticle.pdf。)

Note: my answer is off-topic because the solution provided in the blog post above is not secure from a Javascript client. In fact, it explain mostly how to secure a REST API on the server side.

注意:我的回答是偏离主题的,因为上面的博客文章中提供的解决方案对Javascript客户端来说并不安全。实际上,它主要解释了如何在服务器端保护REST API。

#2


8  

"Where I start getting confused is how to have the users on these sites authenticate to my application. It seems like a bad idea to have this external site store my user's account and password information;" -

“我开始感到困惑的是如何让这些网站上的用户对我的应用程序进行身份验证。让这个外部网站存储我的用户的帐户和密码信息似乎是一个坏主意;” -

With REST APIs, the best way to handle this is to use your clients (web pages, mobile apps) whether controlled by your domain or external pass through the user credentials entered by the user (in the login page). You would have a login/logout API that takes care of authenticating.

使用REST API,处理此问题的最佳方法是使用您的客户端(网页,移动应用程序),无论是由您的域控制还是外部传递用户输入的用户凭据(在登录页面中)。您将拥有一个用于进行身份验证的登录/注销API。

When the login API authenticates, it returns a token (one way hash maybe of user preferences of whatever), that can be stored in an encrypted cookie on the client side. This way, your clients never handle the user credentials directly. The token is set to expire whenever you want.

当登录API进行身份验证时,它会返回一个令牌(可能是用户偏好的一种方式),可以存储在客户端的加密cookie中。这样,您的客户端永远不会直接处理用户凭据。只要您愿意,令牌就会设置为过期。

For all subsequent REST API calls, your clients will submit this token along with the request to the API (which is different from the login/logout API). The API may perhaps check a local cache (on the REST Server) to see if this is a valid token. If found, honors the request. Otherwise, throws an error.

对于所有后续REST API调用,您的客户端将此请求与请求一起提交给API(与登录/注销API不同)。 API可能会检查本地缓存(在REST服务器上)以查看这是否是有效令牌。如果找到,请尊重请求。否则,抛出错误。

If the user logs out before token expiration, then the login/logout API will delete this token from the local cache, and your clients will need to delete the session/cookie.

如果用户在令牌过期之前注销,则登录/注销API将从本地缓存中删除此令牌,并且您的客户端将需要删除会话/ cookie。

This way your credentials never get passed around on the client side.

这样,您的凭据永远不会在客户端传递。

And of course data-in-motion security should be achieved as well by SSL and HTTP Digest.

当然,SSL和HTTP摘要也应该实现数据动态安全性。

#3


1  

If it's a private API (you have a users table) going cross-domain from another hostname to your own hostname, I agree with the above, and suggest a simple (SSL) Login/Logout at which point you can give the user (or take away) a cookies from your domain.

如果它是一个私有API(你有一个用户表)从另一个主机名跨域到你自己的主机名,我同意上述内容,并建议一个简单的(SSL)登录/注销,此时你可以给用户(或带走)来自您域名的cookie。

If it's a public API (anyone can get an API key for e.g.) I'd suggest use the method in the blog post from the answer above.

如果它是公共API(任何人都可以获得API密钥),我建议在上面的答案的博客文章中使用该方法。

For the JavaScript client, try https://github.com/jpillora/jquery.rest if anything is missing, submit feature request or contribute if you like :)

对于JavaScript客户端,如果缺少任何内容,请尝试https://github.com/jpillora/jquery.rest,如果您愿意,请提交功能请求或贡献:)

#1


40  

I suggest you to read this very good blog post about securing a RESTful API.

我建议你阅读这篇关于保护RESTful API的博文。

(In case that link doesn't work—it has already gone dead once and has to be retrieved from archive.org—I found what it seems to be a PDF render of this page accessible here: https://www.ida.liu.se/~TDDD97/labs/hmacarticle.pdf.)

(如果链接不起作用 - 它已经死了一次并且必须从archive.org检索 - 我发现这个页面的PDF呈现在这里可以访问:https://www.ida。 liu.se/~TDDD97/labs/hmacarticle.pdf。)

Note: my answer is off-topic because the solution provided in the blog post above is not secure from a Javascript client. In fact, it explain mostly how to secure a REST API on the server side.

注意:我的回答是偏离主题的,因为上面的博客文章中提供的解决方案对Javascript客户端来说并不安全。实际上,它主要解释了如何在服务器端保护REST API。

#2


8  

"Where I start getting confused is how to have the users on these sites authenticate to my application. It seems like a bad idea to have this external site store my user's account and password information;" -

“我开始感到困惑的是如何让这些网站上的用户对我的应用程序进行身份验证。让这个外部网站存储我的用户的帐户和密码信息似乎是一个坏主意;” -

With REST APIs, the best way to handle this is to use your clients (web pages, mobile apps) whether controlled by your domain or external pass through the user credentials entered by the user (in the login page). You would have a login/logout API that takes care of authenticating.

使用REST API,处理此问题的最佳方法是使用您的客户端(网页,移动应用程序),无论是由您的域控制还是外部传递用户输入的用户凭据(在登录页面中)。您将拥有一个用于进行身份验证的登录/注销API。

When the login API authenticates, it returns a token (one way hash maybe of user preferences of whatever), that can be stored in an encrypted cookie on the client side. This way, your clients never handle the user credentials directly. The token is set to expire whenever you want.

当登录API进行身份验证时,它会返回一个令牌(可能是用户偏好的一种方式),可以存储在客户端的加密cookie中。这样,您的客户端永远不会直接处理用户凭据。只要您愿意,令牌就会设置为过期。

For all subsequent REST API calls, your clients will submit this token along with the request to the API (which is different from the login/logout API). The API may perhaps check a local cache (on the REST Server) to see if this is a valid token. If found, honors the request. Otherwise, throws an error.

对于所有后续REST API调用,您的客户端将此请求与请求一起提交给API(与登录/注销API不同)。 API可能会检查本地缓存(在REST服务器上)以查看这是否是有效令牌。如果找到,请尊重请求。否则,抛出错误。

If the user logs out before token expiration, then the login/logout API will delete this token from the local cache, and your clients will need to delete the session/cookie.

如果用户在令牌过期之前注销,则登录/注销API将从本地缓存中删除此令牌,并且您的客户端将需要删除会话/ cookie。

This way your credentials never get passed around on the client side.

这样,您的凭据永远不会在客户端传递。

And of course data-in-motion security should be achieved as well by SSL and HTTP Digest.

当然,SSL和HTTP摘要也应该实现数据动态安全性。

#3


1  

If it's a private API (you have a users table) going cross-domain from another hostname to your own hostname, I agree with the above, and suggest a simple (SSL) Login/Logout at which point you can give the user (or take away) a cookies from your domain.

如果它是一个私有API(你有一个用户表)从另一个主机名跨域到你自己的主机名,我同意上述内容,并建议一个简单的(SSL)登录/注销,此时你可以给用户(或带走)来自您域名的cookie。

If it's a public API (anyone can get an API key for e.g.) I'd suggest use the method in the blog post from the answer above.

如果它是公共API(任何人都可以获得API密钥),我建议在上面的答案的博客文章中使用该方法。

For the JavaScript client, try https://github.com/jpillora/jquery.rest if anything is missing, submit feature request or contribute if you like :)

对于JavaScript客户端,如果缺少任何内容,请尝试https://github.com/jpillora/jquery.rest,如果您愿意,请提交功能请求或贡献:)