当前位置: 首页 > 后端技术 > PHP

Laravel实现简单的用户权限

时间:2023-03-29 21:30:20 PHP

权限管理的思考最近使用laravel设计后台,后台需要有权限管理。权限管理本质上分为两部分,先是认证,然后是权限。认证部分很容易做,就是管理员登录并记录session。这个laravel也有自己的Auth来实现这一点。最麻烦的是授权认证。权限认证本质上就是谁有权管理什么。这里有两个维度,谁是用户维度。在用户维度上,权限管理的粒度可以是单个用户,也可以是组用户。如果对用户进行分组,涉及到的逻辑是一个用户可以在多个组中?另一方面,管理一个东西,这个东西就是东西的维度,一个页面是一个东西,页面上的一个元素也是一个东西,或者更广义地说,一个功能是一个东西。所以做权限管理最重要的就是确认这两个维度的粒度。这已经不是技术问题了,需要讨论。基于以上思路,我这次要做的权限管理是在用户维度上以个体为单位的。只是每个人的权限不同而已。在事物的维度上,我把路由设置为最小的单位,也就是我可以对单个路由设置权限管理。下面的思路就是用什么来标记权限,可以用位,字符,或者整数。后来我选择字符基于两个考虑:1、字符通俗易懂,在数据库中查找也比较方便。2.我没有根据某个权限找有这个权限的人的需求,也就是没有反向搜索的需求。类型等是没有意义的。接下来考虑如何与laravel结合。由于需要为每条路由设置访问权限,当然希望可以在laravel的route.php路由管理中配置。Route::get的时候最好有个参数设置权限。这样做的好处是权限设置简单。在决定路由的时候,我手写了权限控制。至于缺点,也很明显,laravel路由的三种方式只能写一种。就是Route::(method)的方式。基本上决定开始工作了。路由设计的基本路由是Route::post('/admin/validate',['uses'=>'AdminController@postValidate','permissions'=>['admin.validate','admin.index']]);此处,在基本路由操作之后设置权限属性。这个属性被设计成一个数组,因为比如一个post请求可能在某个页面触发,也可能在另一个页面触发。那么这个post请求需要权限同时有两个页面路由。这里使用了admin.validate的权限控制,这样可以对权限进行分组。admin是所有与管理员相关的组。在数据库中,我会存储一个二维数组,[admin]=>['validate','index'];将其存储为二维数组而不是一维数组的优点。一般背景展示有两个维度,一个是头部的tab栏,一个是左边的nav栏。也就是说,二维数组与背景中的tab和nav列是一一对应的。中间件设计好之后,我们把中间件挂起来,设置所有的路由都要经过这个中间件传入请求。**@param\Illuminate\Http\Request$request*@param\Closure$next*@returnmixed*/publicfunctionhandle($request,Closure$next){$permits=$this->getPermission($request);}$admin=\App\Http\Middleware\Authenticate::getAuthUser();//只要有权限,就可以进入这个请求foreach($permitsas$permit){if($permit=='*'){return$next($request);}if($admin->hasPermission($permit)){return$next($request);}}echo"没有权限,请联系管理员";exit;}//获取当前路由需要的权限publicfunctiongetPermission($request){$actions=$request->route()->getAction();如果(empty($actions['permissions'])){echo"该路由没有设置权限。";exit;}return$actions['permissions'];}}这里最重要的是getPermission函数,用于从$request->route获取该路由的action定义()->getAction().然后从permissions字段中获取route.php中定义的路由权限,然后上面的中间件有一个admin?>hasPermission(permit);这就涉及到model的设计了。模型设计permissions;如果(in_array($permission,$permission_db)){返回真;}返回假;}//权限是一个二维数组publicfunctiongetPermissionsAttribute($value){if(empty($value)){return[];}$data=json_decode($value,true);$ret=[];foreach($dataas$key=>$value){$ret[]=$key;foreach($valueas$value2){$ret[]="{$key}.{$value2}";}}返回array_unique($ret);}//全局设置权限publicfunctionsetPermissionsAttribute($value){$ret=[];foreach($valueas$item){$keys=explode('.',$item);如果(计数($keys)!=2){继续;$ret[$keys[0]][]=$keys[1];}$this->attributes['permissions']=json_encode($ret);}}在数据库中,我把二维数组存为json,通过laravel的Attribute的get和set方法完成数据库中json和外部程序逻辑的连接,然后hasPermission就很容易了。直接判断in_arrayup就可以了。后续授权认证的逻辑就清楚了。那么如果页面上的某个tab或者nav需要展示给不同权限的用户,只需要在视图中判断@if($admin->hasPermission('admin.index'))@endif判断用户是否可以看到这个标签不见了。