我正在构建一个将从JavaScript客户端使用的PHP REST API,并且在解决如何实现身份验证和访问方面存在一些问题。将有多个应用程序将使用我将开发的JavaScript库来与我的应用程序交谈和交互。我将为每个人提供API密钥,因此这不是问题。
我开始感到困惑的地方是如何让这些网站上的用户对我的应用程序进行身份验证。让这个外部网站存储我的用户的帐户和密码信息似乎是一个坏主意;所以,我想我应该让我的JavaScript库包含一个登录小部件,询问用户的应用程序的帐户信息。
如果身份验证成功,由于我正在使用REST API,我需要将检索到的令牌存储在客户端cookie中,以便用户不需要再次登录我的应用程序。外部网站的每个页面。但是,如果用户退出外部站点,然后另一个用户从同一浏览器登录,会发生什么?就我的JavaScript库而言,旧用户仍然会登录到我的应用程序,因为cookie /令牌尚未过期 - 如何在前一个用户的会话结束时清除我的cookie?或者,我完全偏离了正确的道路吗?
所以,我认为这个过程会像:
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
});
抱歉,这里有几个问题。我想主要的一个是如果我将令牌存储到cookie中,当用户注销外部应用程序时,如何确保它被清除?或者,如果我不应该将其存储到cookie中,如何让客户端了解用户的状态?
答案 0 :(得分:41)
我建议您阅读有关保护RESTful API的very good blog post。
(如果该链接不起作用 - 它已经死了一次并且必须从archive.org中检索 - 我发现这个页面的PDF呈现在这里可以访问:https://www.ida.liu.se/~TDDD97/labs/hmacarticle.pdf 。)
注意:我的回答是偏离主题的,因为上面博客文章中提供的解决方案对Javascript客户端来说并不安全。实际上,它主要解释了如何在服务器端保护REST API。
答案 1 :(得分:8)
“我开始感到困惑的地方是如何让这些网站上的用户对我的应用程序进行身份验证。让这个外部网站存储我的用户的帐户和密码信息似乎是一个坏主意;” -
使用REST API,处理此问题的最佳方法是使用您的客户端(网页,移动应用程序),无论是由您的域控制还是外部传递用户输入的用户凭据(在登录页面中)。您将拥有一个用于进行身份验证的登录/注销API。
当登录API进行身份验证时,它会返回一个令牌(可能是用户偏好的一种方式),可以存储在客户端的加密cookie中。这样,您的客户端永远不会直接处理用户凭据。只要您愿意,令牌就会设置为过期。
对于所有后续REST API调用,您的客户端将此请求与请求一起提交给API(与登录/注销API不同)。 API可能会检查本地缓存(在REST服务器上)以查看它是否是有效令牌。如果找到,请尊重请求。否则,抛出错误。
如果用户在令牌过期之前注销,则登录/注销API将从本地缓存中删除此令牌,并且您的客户端将需要删除会话/ cookie。
这样,您的凭据永远不会在客户端传递。
当然,SSL和HTTP摘要也应该实现数据动态安全性。
答案 2 :(得分:1)
如果它是一个私有API(你有一个用户表)从另一个主机名到你自己的主机名跨域,我同意上面的说法,并建议一个简单的(SSL)登录/注销,此时你可以给出用户(或带走)来自您域名的Cookie。
如果它是公共API(任何人都可以获得API密钥),我建议在上面的答案中使用博客文章中的方法。
对于JavaScript客户端,如果缺少任何内容,请尝试https://github.com/jpillora/jquery.rest,如果您愿意,请提交功能请求或提供:)