RESTful API基于用户角色的不同响应

时间:2019-06-28 11:05:55

标签: php laravel rest

我正在使用Laravel作为我的PHP框架。约定将index show store ...函数放入控制器。

我有2种类型的用户(管理员和普通用户)。假设有一个Order(餐厅)模型,我想为其控制器实现index功能。 一个用户可以有多个订单。

我需要的是该功能:

  
      
  • 如果管理员正在调用此API:返回所有订单
  •   
  • 如果普通用户正在调用此API:仅返回该用户拥有的订单
  •   

我搜索了,但什么也找不到(我不知道要搜索什么)。

一旦执行以下操作,我就不喜欢它,因为它看起来像是聚集了两个不同的功能:

if ($user->role == admin) {
       // fetch all orders
   } else if ($user->role == normal_user) {
       // just find user orders
     }

所以我的问题是实现我想要的最好的方法是什么?

5 个答案:

答案 0 :(得分:1)

为什么不使用if语句?

您可以在模型上创建范围,但是仍然有一个if。

那呢?

UPDATE Purchase p JOIN
       (SELECT aw.PurchaseID, SUM(aw.Price) as total_price
        FROM Artwork aw
        WHERE aw.PurchaseID = 'D4758'
        GROUP BY aw.PurchaseID
       ) aw
       ON p.PurchaseID = aw.PurchaseID
    SET p.Total = aw.total_price;

或者将其设为内联

if ($user->role == admin) { Order::all(); } else if ($user->role == normal_user) { $user->orders()->get(); }

IMO的最佳做法是制作一个不同的Admin / OrderController.php

然后使用中间件检查wat,确定用户的角色,然后将其重定向到管理控制器。

由于您可能还希望更新和删除或仅由管理员使用的其他功能

答案 1 :(得分:1)

不久前,我自己也遇到了类似的问题,最后提出了一个奇怪的解决方案,以避免该if / else阻塞。

假设

我假设用户模型中存在一个名为isNot($role)的辅助方法,以验证用户的角色是否匹配给定的角色。 这只是给出检查想法的一个示例,但是您应该根据需要实现条件。

我做出的第二个假设是,每个订单都有一个user_id字段,该字段将通过其ID(用户和订单之间的FK为1:N)来引用该订单的所有者。

实施

public function index(Request $request)
{
    $orders = Order::query()
            ->when($request->user()->isNot('admin'), function ($query) use ($request) {
                return $request->user()->orders();
                // Or return $query->where('user_id', $request->user()->id);
            })
            ->paginate();

    return OrderResource::collection($orders);
}

when方法是这里的关键。基本上,您可以这样称呼它:when($value, $callback),如果$valuefalse,则不会执行该回调,否则它将执行。

因此,例如,如果用户不是管理员,则最终将执行以下查询: Order::paginate(); 这样可以分页获取所有订单(请注意,您可以将paginateget交换。

否则,将执行回调,您将在paginate上执行$request->user()->orders();方法(像方法一样被调用的顺序仍然是查询生成器对象,因此可以在其上调用paginate)。 查询将是: $request->user()->orders()->paginate();

如果您选择在回调中选择第二种解决方案,则基本上可以在主范围中添加一个where条件(对订单的user_id进行过滤),以仅获取用户的订单。 查询将是: Order::query()->where('user_id', $request->user()->id)->paginate();

最后,为了更好地控制作为响应发送回的内容,我使用了Laravel's API Resource(如果需要自定义响应,我也建议您也这样做)。

注意::该代码可能存在语法和/或逻辑错误,因为它只是对生产代码进行即时编辑,并且尚未经过测试,但应该给出一个总体思路以获得正确的实施方式。

答案 2 :(得分:0)

最好将if / else包含在您的订单模式中,如下所示:

class Order extends Model {
....
 static function fetchFor (User $user) : Collection
 {
   return $user->isAdmin() ? self::all() : self::where("user_id",$user->id); 
 } 
}

然后您可以在控制器上调用此方法


public function index()
{
  return view('your-view')->with('orders',Order::fetchFor(Auth::user())->get())
}

答案 3 :(得分:0)

您可以在Order类中创建范围... 例如,您在Order中有一个user_id字段,用于检测用户

class Order 
{
 ...
 public function scopeByRole($query)
 {
   if (!Auth::user()->isAdmin())
     $query = $query->where('user_id', Auth::user()->id);
   return $query;
 }

}


在您的控制器中,只需获取所有具有范围的订单:

$orders = Order::byRole()->get();

按角色返回订单

此外,您还需要在类User中具有检测角色的功能,例如

class User
{
  public function isAdmin()
  {
    // you logic which return true or false
  }
}

答案 4 :(得分:0)

这种REST API端点通常是允许多个过滤器,排序和分页的搜索。如果是这样,完全可以为过滤器应用不同的默认值,并将过滤器限制为角色。

如果没有管理员角色的用户尝试为其他用户应用用户过滤器,我将自动为缺少的管理员角色应用过滤器user = currentUser并返回禁止。

通过这种方法,您还可以为管理员提供搜索特定用户的要约的功能,并且控制器只需要使用一个搜索api。