【问题标题】:Properly implementing resource authorization for a RESTful API正确实现 RESTful API 的资源授权
【发布时间】:2015-09-15 16:13:39
【问题描述】:

我的团队有一个我们使用 Slim 框架用 PHP 编写的 API。它被网络应用程序和第三方移动应用程序使用。

我们使用标准 OAuth 2 工作流程来提供对我们资源的访问。我们可以查看是否有人在发送 API 请求时发送了有效的访问令牌,并且这部分流程是有意义的。

我们遇到的绊脚石是如何根据与访问令牌关联的用户的权限最有效地授权对资源的访问。

为了简单起见,假设我们只想确保相关资源的所有者与访问令牌的所有者匹配。对我来说,这似乎是路由中间件会为每个请求处理的事情,在处理请求之前,请确保资源所有者 ID 与访问令牌的 ID 匹配。

我认为的问题是资源权限不一定在所有路由中都一致,路由不一定在 URI 的同一部分中具有 ID,它可能在 URI 中没有 ID所有,等等等等。

我当前的解决方案是拥有一个授权实用程序类,它接收一封电子邮件并针对当前“登录”的用户(令牌所有者)进行检查。

class Authorization() {
    checkResourcePermissions($email) {
         if (loggedInUser->email == $email) {
             return true;
         }       
    }
}

显然这是一种简化,但这意味着,由于路由中间件在请求通过之前没有请求的上下文,因此我需要在每个 API 路由中调用此授权方法,并以必要时出错等。我们的 API 相当大,基本上把它归结为大量的复制和粘贴,这总是让我非常紧张。

我错过了什么?

【问题讨论】:

  • 你要找的是外部授权。看看abacxacml

标签: php api rest authorization slim


【解决方案1】:

我建议使用“普通”中间件: 首先,假设您有一个“用户”类,您可以在其中实现您的逻辑以访问各种类型的资源或具有特定权限,仅给定 $app.它可以访问请求并从 HTTP 请求中获取识别单个用户所需的任何信息。

class User{   
        private $userid=false;
        public function __construct($app){
                $this->app=$app;
                $users_mail=$this->app->request->post('email');
                //SELECT user_id FROM USERSTABLE WHERE email = $users_mail
                //$this->userid=user_id
        }
        public function ensureHasAccess($resourceID,$redirect='/noPermission'){
                if(!/*some DB Query which returns true if this user may access the given $resourceID*/)
                        $this->app->redirect($redirect)
        }
        public function ensureHasRole($role) {
                //some other permission checking, like ensureHasAccess();
        }
        public function ensureIsUser(){
                //do Something
        }
}

接下来,您需要一个 MiddleWare,它在路由调度之前运行,并创建一个User-Object:

class UserPermissionMiddleware extends \Slim\Middleware{
        public function call(){
                $this->app->request->user = new User($app);

                $this->next->call();
        }
}

然后,只需添加这个中间件:

$app->add(new UserPermissionMiddleware());

现在,您可以修改每个路由以检查对资源的访问,而资源 id(当然)仍然需要根据路由特定的代码手动提供:

$app->get('/resource/:id',function($resourceId) use ($app){
        $app->request->user->ensureHasAccess($resourceId);
        //deliver resource
});

如果不允许用户访问该资源,则整个过程被中断(注意redirect()是使用Exceptions实现的!)并执行另一个路由。您仍然需要在每条 Route 中添加一些代码,但是如果没有一致的方法来确定要访问的资源,那么就没有办法解决这个问题。

希望到目前为止这对您有所帮助。如果您有任何问题,请随时提出!

【讨论】:

    猜你喜欢
    • 2014-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-15
    • 1970-01-01
    • 1970-01-01
    • 2020-01-20
    相关资源
    最近更新 更多