我的团队有一个我们使用Slim Framework在PHP中编写的API。它被Web应用程序和第三方移动应用程序使用。
我们使用标准OAuth 2工作流来提供对资源的访问。我们可以看到某人是否正在发送有效的访问令牌以及API请求,并且该部分流程是有意义的。
我们遇到的绊脚石是如何最有效地授权访问资源,具体取决于与访问令牌关联的用户的权限。
为简单起见,我们只想确保相关资源的所有者与访问令牌的所有者匹配。对于我来说,对于每个请求,路由中间件都会处理这个问题,在处理请求之前,请确保资源所有者ID与访问令牌的ID匹配。
我的想法是,资源权限在所有路由中不一定一致,路由不一定在URI的同一部分中具有ID,它可能在URI中没有ID所有等等。
我目前的解决方案是拥有一个授权实用程序类,该类接收一封电子邮件,并针对当前“登录”的用户(令牌所有者)进行检查。
class Authorization() {
checkResourcePermissions($email) {
if (loggedInUser->email == $email) {
return true;
}
}
}
显然这是一种简化,但这意味着,由于路由中间件在请求通过之前不会有请求的上下文,我需要在每个API路由中调用此授权方法,并以如果有必要的错误,等等。我们的API相当大,基本上将其煮沸到大量的复制和粘贴,这总是让我非常紧张。
我错过了什么?
答案 0 :(得分:0)
我建议使用'普通'中间件: 首先,假设您有一个类'user',您可以在其中实现您的逻辑以访问各种类型的资源或具有特定权限,仅给出$ 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
- 对象:
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
});
如果不允许用户访问此资源,则整个过程中断(请注意,使用Exceptions实现redirect()!)并执行另一个路由。你仍然需要在每一条路线中都有一些代码,但是如果没有一致的方法来确定要占用的资源,那么就无法解决这个问题。
希望这对你有帮助。如果您有任何问题,请随时提出!