1

当正在处理的数据与调用 api 的用户相关时,需要身份验证的 API 应该在 url 调用中包含用户 ID?

想象一个被 Web 应用程序使用的 API(两者都在同一个堆栈中)并且它使用一种身份验证方法(cookie、基本身份验证等)。

假设网络管理用户拥有的书籍。当 Web 应用调用 /users/:id_user/books 时,会列出属于 :id_user 的书籍。

在这种情况下,当处理请求时,应用程序知道用户 ID。例如,在使用 Express 和 Passport 的 node.js 中,用户 ID 在 request.user.id 中,例如

所以我想知道省略 :id_user 作为参数是否是一种好方法,因为代码可以执行以下操作:

路线:/users/books(获取登录的用户书籍)

app.get('/users', auth(), function (req, res) {

var userId: req.user.id; // Get user id from authentication data.
// Find user's books
books.find({ _owner: req.user.id}, function(err, books){return res.send(books)});

}

代替

路线:/users/:id_user/books(使用显式用户 ID 从登录用户获取书籍)

app.get('/users/:id_user', auth(), function (req, res) {

var userId = req.params.id_user; // get param from the URI

// For security reasons: prevent the user to access other user books
// by providing another user id in the url by comparing logged user credentials to
// user id from URI.

if (req.params.id !== req.user.id) { return res.send(403); // Forbidden }

// Find user's books.
books.find({ _owner: userId}, function(err, books){return res.send(books)});

}

更新:

由于 Jonathan P. Diaz 回答建议使用“me”作为参数,我一直在尝试执行从 req.params.id = "me" 到 req.params.id = req.user.id 的更改一个地方,而不是在每条路线中编写代码行。此外,在作为 app.get/app.put/etc 的第二个参数传递的回调中,也无法修改中间件中的 req.params(此时它不存在)。当调用该方法时 req.params.id 又是“我”,它在执行数据库操作时显然失败了。

我找到的解决方案是这样的:

在您的路线文件中添加如下函数:

var callWrapper = function(callback) {

    return function(req, res) {

      if (req.params && req.params.id === "me") {
        req.params.id = req.user.id;
      }
      return callback(req, res);
    }
}

然后以这种方式构建路由:

app.get('/users/:id/books', securityProtectionApi, callWrapper(user.showUserBooks));

Note: user.showUserBooks is the controller method and securityProtectionApi is a check using passport for sending unauthorized when the user is not authenticated.
4

2 回答 2

1

好问题。我认为解决方案一要干净得多。在某些情况下,您需要指定谁实际调用该服务,因为它是一个共享方法(例如,您可以使用相同的方法访问其他用户的公共数据),可能是登录用户或其他人,什么我们通常做的是使用相同的想法,正如你所说的“/method/:id/books”但是当:id等于“ me ”(“ /users/me/books ”)时,我们假设它是当前用户并且我们使用通过护照保存在请求中的值,如果不是,则:id参数是我们继续该过程所需要的。

app.get "/users/:id/books", (req, res, next) ->
    if req.params.id and req.params.id == "me"
        req.params.id = req.user.id

编辑: 您可以使用 app.use() 将其添加为中间件。将其放在顶部,并可能使用更具体的参数名称以使其清晰。快递 app.use()

app.use(function(req, res, next){
 if (req.params && req.params.userId === "me") {
        req.params.id = req.user.id;
      }
next();
}
于 2013-08-17T05:01:09.897 回答
0

Depends on your level of security, but you got options. Risks include:

  • Incrementing the ID to get access to other user data
  • Modifying the requests to view other user accounts (account ownership)
  • Disclosing user account numbers and id's to browser and proxy caches (headers stored in logs)

Generally you got - authentication (logged in or anonymous) and - authorization (entitlement, am I allowed to view this page.)

Providing these parameters to the url opens you up to then entitlement checks not being done (common mistake).

My take on it is: Dont use it when user context is important. (Profile, Orders, Account lists, etc) Rather use the session token and infer entitlement on the server.

于 2013-08-19T04:57:16.837 回答