声明:本文由夭℃~空投稿,未经作者许可,禁止转载!
这个想法的产生背景是在我碰到一个实际需求的时候。当时我碰到了这么一个需求:
首先我有很多模块,每个模块都有一个鉴权方式。
我本来想用中间件来做,但是随即发现,由于每个模块的过滤方式不一样导致中间件的数量一下子增加了很多。而且,由于中间件的分离到了中间件的文件夹去,且并不能实现中间件的复用价值。所以,我抛弃了使用中间件的方法。
这个时候,我想到,每个控制器自己有独立的 construct不就好了,这样每个控制器都有自己的独特的鉴权方式。
但是问题随之而来,Laravel 的控制器虽然能实现自动 construct,但是在 construct里面的,并不能实现 response,也就是说在 construct里面的 response将会被忽略。不是实现返回错误信息,或者重定向的需求。
翻了文档之后似乎找不到一个完美的解决方法。于是,我去翻源代码,最终把目标放 beforeFilter,并用 boforeFilter实现了这个需求。
重新整理适用场景:
本用法适用于每个控制器都需要同样的一套过滤,而具体的过滤方式由控制器自身决定,也就是基于控制器本身的中间件。
代码如下:
首先建立一个基础的控制器:
<?phpnamespace App\Http\Controllers\Api\Business;use RuntimeException;use Illuminate\Routing\Controller as BaseController;use Illuminate\Auth\Guard;use Illuminate\Http\Request;abstract class Controller extends BaseController{ protected $request; protected $auth; public function __construct(Request $request,Guard $auth){ $this->request = $request; $this->auth = $auth; //统一鉴权 $this->beforeFilter(function(){ return $this->checkPermission(); }); } protected function checkPermission(){ throw new RuntimeException('['.get_class($this).'] missing method[checkPermission]'); }}
将 request和 auth放到基础控制器,是为了方便鉴权过程中调用,关键的地方,在于设置 beforeFilter,通过 beforeFilter调用控制器自身的协议方法。至于我在基础控制器里面放 checkPermission是要求所有基于这个控制器的控制器必须重载掉这个方法。 beforeFilter可以设置第二个参数,跟 middleware()一样,可以设置 except或者 only。
然后定义模块控制器继承这个方法:
<?phpnamespace App\Http\Controllers\Api\Business;class TicketController extends Controller{ //鉴定权限 protected function checkPermission(){ //return redirect()->to('某个url'); //return view(); //return 'string'; ... }}
只要 checkPermission里面返回 response,那么就会跟中间件一样作为整个请求的 response.如果里面不返回任何东西,那么php会自动返回 null。只要是 null,就代表着通过 checkPermission的验证。
这样就能实现基于控制器自身的中间件,更多用法有待发掘。
注:目前这个我在5.0版本使用通过,更高的版本有待测试。
本文由夭℃~空投稿,他邮箱是 anwelblue@qq.com,有什么问题欢迎与他一起探讨,此外你还可以在学院二群找到他: 542175836。