laravel 中間件做權限目錄管理

1:創建表結構

創建用戶表 user

創建權限表 permission

image.png

創建角色表 role

創建用戶角色表 user_role

image.png

創建角色權限表  role_permission

image.png

2:創建中間件權限判斷和目錄生成

<?php

/**
 * 檢測後臺用戶是否登錄中間件
*    此中間件可以跟登錄驗證登錄中間分離
 */

namespace App\Http\Middleware;

use App\Components\AdminManager;
use App\Components\Common\ApiResponse;
use App\Components\PermissionManager;
use Closure;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\View;

class CheckAdminLogin
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Closure $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        //檢測session中是否有登錄信息
        if (!$request->session()->has('self_admin')) {
            return redirect('/admin/login');
        }
        $self_admin = $request->session()->get('self_admin');
        $self_admin = AdminManager::getById($self_admin->id);     //增加判斷status==0的失效踢出管理員
        if ($self_admin->status == '0') {
            return redirect('/admin/login');
        }
        //組成redis的key名稱
        $key = 'banni:admin:menu:'.$self_admin->id;
        //自己寫的,銷燬redis中用戶權限的緩存
//        PermissionManager::destroyPermissions();
        //獲取redis中用戶權限信息
        $admin_menu_data = Redis::get($key);
        //判斷是否是超級管理員
        $is_admin = $self_admin->role === 0?true:false;
        //判斷是否在redis中獲取到該緩存
        if( !$admin_menu_data ){
            //未獲取到緩存重新生成用戶權限信息,存儲到redis中
            if(!PermissionManager::getMenuList($self_admin->id,$is_admin)){
                return redirect('/admin/login');
            }
            $admin_menu_data = Redis::get($key);
        }
        //獲取用戶權限信息
        $admin_menu_data = unserialize($admin_menu_data);
        //獲取用戶權限
        $permissions_arr = $admin_menu_data['permission_auth'];
                        
        //追加默認權限到權限數組中
array_push($permissions_arr,'/admin/index','/admin/index/index','/admin/logout','/','/index','/admin/index/error','/admin/overview/index','/admin/overview/orderGMVTrend','/admin/overview/userTrend','/admin/welcome');
        //獲取請求url,過濾帶參數的路由,重新封裝
        $path_arr = explode('/',$request->path());
        if( is_numeric(array_pop($path_arr)) ){
            $permission_path = '/'.implode('/',$path_arr);
        }else{
            $permission_path = '/'.$request->path();
        }
        //判斷不是超級管理員,並且沒有此權限
        if( !$is_admin && !in_array( $permission_path,$permissions_arr) ){
            //判斷接收方式返回關聯信息
            if( $request->ajax() ){
                return ApiResponse::makeResponse(false, "", ApiResponse::INNER_ERROR,'權限不足,請聯繫管理員');
            }else{
                return redirect('/admin/index/error');
            }
        }
        //傳入目錄數組到前端,像layui這種只生成一次目錄的,可以只請求一次,但是我還沒做
        view()->share('admin_menu', $admin_menu_data['menu_list']);
        //如果不需要判斷按鈕顯示權限的,可以註釋此步驟
        view()->share('admin_permissions', $permissions_arr);
        return $next($request);
    }

}

生成用戶權限方法

 /*
     * 生成菜單列表
     * $adming_id 關聯表id
     * $is_admin    是否是超級管理員
     * $type 類型:1後臺管理;2:公會後臺管理
     *
     */
    public static function getMenuList($adming_id,$is_admin = false,$type = 1){

        switch ($type){
            case 1:
                $f_table = 'admin';
                break;
            case 2:
                $f_table = 'guild_user';
                break;
            default:
                break;
        }

        //構建菜單列表數組
        $menu_list = [];
        //構建用戶權限列表
        $permission_auth = [];
        //判斷是否是超級管理員
        if( $is_admin ){
            $con_arr = [
                'status' => 1,
                'type' => $type
            ];
            $permissions = self::getListByCon($con_arr,false)->toArray();
            foreach ($permissions as $permission){
                $permission_auth[] = $permission['url'];
                if( $permission['is_display'] ){
                    $menu_list[$permission['f_id']][] = [
                        "id" => $permission['id'],
                        "name" => $permission['name'],
                        "url" => $permission['url'],
                        "is_display" => $permission['is_display'],
                        "f_id" =>$permission['f_id'],
                        "icon" => $permission['icon']
                    ];
                }
            }
        }else{
            //非超級管理員獲取目錄權限
            $user_role_where = [
                'f_table' => $f_table,
                'f_id' => $adming_id,
                'status' => 1
            ];
            $user_roles = UserRoleManager::getListByCon($user_role_where,false);
            foreach ( $user_roles as $user_role ){
                $user_role = UserRoleManager::getInfoByLevel($user_role,'Y,1');
            }
            //生成目錄信息和權限數組
            foreach($user_roles as $user_role){
                foreach ( $user_role['roles'] as $role) {
                    foreach( $role['permissions'] as $permission ){
                        $permission_auth[] = $permission['url'];
                        if( $permission['is_display'] ){
                            $menu_list[$permission['f_id']][] = [
                                "id" => $permission['id'],
                                "name" => $permission['name'],
                                "url" => $permission['url'],
                                "is_display" => $permission['is_display'],
                                "f_id" =>$permission['f_id'],
                                "icon" => $permission['icon'],
                                "seq" => $permission['seq']
                            ];
                        }
                    }
                }
            }
            //冒泡排序目錄
            foreach ( $menu_list as $key => $menu ){
                self::bubbleSort($menu_list[$key]);
            }

        }
        //構建redis中的key
        $type_key = $type==1?'admin':'guild:admin';
        $menu_list_key = 'banni:'.$type_key . ':menu:'.$adming_id;
        $admin_menu_list = [
            'admin_id'=> $adming_id,
            'menu_list'=> $menu_list,
            'permission_auth' => $permission_auth
        ];

        //刪除有序集合中用戶的權限
        Redis::del($menu_list_key);
        //插入權限進redis有序集合中,分數爲用id
        if( Redis::set($menu_list_key, serialize($admin_menu_list) ) ){
            return true;
        }else{
            return false;
        }
    }


    /*
     * 銷燬所有權限相關緩存文件
     */
    public static function destroyPermissions($type=1){
        switch ($type){
            case 1:
                $prefix = 'banni:admin:menu:*';
                break;
            case 2:
                $prefix = 'banni:guild:admin:menu:*';
                break;
        }
        $keys = Redis::keys($prefix);
        foreach( $keys as $key ){
            Redis::del($key);
        }
//        Redis::del($key);
    }

    /*
     * 冒泡排序菜單順序
     */
    public static function bubbleSort(&$data){
        for ($i = 0; $i < count($data) ; $i++) {
            for ($j = $i+1; $j < count($data); $j++) {
                if ($data[$i]['seq'] < $data[$j]['seq']) {
                    $tem = $data[$i]; // 這裏臨時變量,存貯$i的值
                    $data[$i] = $data[$j]; // 第一次更換位置
                    $data[$j] = $tem; // 完成位置互換
                }
            }
        }
    }

3:前端目錄生成

                        <!-- 循環一級目錄 -->
                        @foreach( $admin_menu[0] as $key=>$value)

                            <li data-name="app" class="layui-nav-item">
                                <!-- 判斷一級目錄是否可跳轉,可跳轉目錄沒有子集 -->
                                @if( $value['url'] )
                                    <a href="javascript:;" lay-href="{{ asset($value['url'], true) }}?not_in_admin_id=0" lay-tips="{{$value['name']}}"
                                       lay-direction="2">
                                        <i class="layui-icon {{$value['icon']}}"></i>
                                        <cite>{{$value['name']}}</cite>
                                    </a>
                                @else
                                    <a href="javascript:;" lay-tips="{{$value['name']}}" lay-direction="2">
                                        <i class="layui-icon {{$value['icon']}}"></i>
                                        <cite>{{$value['name']}}</cite>
                                    </a>

                                    <dl class="layui-nav-child">
                                        <!-- 判斷是否有子集 -->
                                        @if (isset($admin_menu[$value['id']]))
                                            <!-- 循環子集生成菜單 -->
                                            @foreach($admin_menu[$value['id']] as $val)
                                                <!-- 判斷是否有子集,這是第三層,如果沒有三層菜單,判斷可以不要 -->
                                                @if( isset(  $admin_menu[$val['id']] ) )
                                                    <dd data-name="setting">
                                                        <a href="javascript:;">{{$val["name"]}}</a>
                                                        <dl class="layui-nav-child">
                                                            @foreach($admin_menu[$val['id']] as $v)
                                                                <dd data-name="workorder">
                                                                    <a lay-href="{{ asset( $v['url'] , true) }}" >{{$v["name"]}}</a>
                                                                </dd>
                                                            @endforeach
                                                        </dl>
                                                    </dd>
                                                @else
                                                    <dd data-name="workorder">
                                                        <a lay-href="{{ asset( $val['url'] , true) }}" >{{$val["name"]}}</a>
                                                    </dd>
                                                @endif

                                            @endforeach
                                        @endif
                                    </dl>
                                @endif
                            </li>


                        @endforeach

如果有按鈕需要是否顯示判斷

<!-- 判斷此鏈接是否在權限中,如果在就顯示,不在就隱藏 -->
@if( $data->audit_status == 0 && in_array('/admin/guildGameSettledApply/approve',$admin_permissions) )
     <button class="layui-btn layui-btn-sm" lay-submit="" onclick="approve(this,'{{$data->id}}','{{asset('/admin/guildGameSettledApply/approve', true)}}')">
          審覈通過
     </button>
@endif                                                                                                                         
                                        

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章