用户权限控制 ----- Auth认证(lumen篇)

来源:互联网 发布:apache与nginx的进程 编辑:程序博客网 时间:2024/06/10 22:27

流程大览

这里写图片描述

在lumen中使用auth认证

  1. 注册AuthServiceProvider服务提供中,框架已经注册好了,只需要解开bootstrap/app.phpAuthServiceProvider 的调用取消代码注释;
  2. 支持ORM,用于获取认证用户,解开$app->withEloquent(); 的调用注释,如果需要通过Auth::User 的方式获取认证用户,需要解开$app->withFacades() 的调用;
  3. 支持路由中间件,把 bootstrap/app.php 里对 $app->routeMiddleware() 的调用 「取消代码注释」,$app->routeMiddleware([
    'auth' => App\Http\Middleware\Authenticate::class,
    ]);
    「取消代码注释;
  4. 还是在bootstrap/app.php 添加自定义配置文件role.php定义 $app->configure('role');,用于路由权限规则定义。

流程说明

登录流程:用户登录 —> 登录验证成功—>生成用户token并保存在数据库 ;
除登录外的其他访问:在AuthServiceProvider 服务提供中验证token的有效性与时效性,验证通过返回认证用户信息,在auth中间件中获取当前访问URI,通过当前认证用户的信息从数据库获取当前用户所拥有的权限,通过权限列表(具体的权限和路由具有对应关系)与当前路由验证用户是否拥有访问权限。

数据表设计

  • 用户表:
 Schema::create('staff_users', function (Blueprint $table) {            $table->increments('id');            $table->string('name',30)->comment('用户名称');            $table->string('alias',30)->nullable()->comment('用户别名');            $table->char('pwd',32)->comment('密码');            $table->enum('status',[0,1])->default(1)->comment('状态 0 禁用 1 启用');            $table->string('phone',11)->comment('手机');            $table->json('extend')->nullable()->comment('用户扩展信息,如登录token等');            $table->softDeletes();            $table->timestamps();            $table->index('status');        });
  • 权限表:
Schema::create('staff_roles', function (Blueprint $table) {            $table->increments('id');            $table->string('rule_name',20)->comment('权限名称');            $table->string('rule',20)->comment('具体权限');            $table->enum('status',[1,0])->comment('状态 0 禁用 1,启用');            $table->softDeletes();            $table->timestamps();            $table->index('status');            $table->unique('rule');        });

*其中rule字段就是记录具体的访问路由,比如一个获取订单列表的URI是order/list 就记录成rule.list‘;

  • 权限小组表
 Schema::create('staff_group', function (Blueprint $table) {            $table->increments('id');            $table->string('name',30)->comment('组名');            $table->string('desc','200')->comment('简单描述');            $table->enum('status',[0,1])->defaule(1)->comment('状态,0 禁用  1 启用');            $table->softDeletes();            $table->timestamps();        });

该表用于权限分组

  • 小组权限对应表
 Schema::create('staff_group_rules', function (Blueprint $table) {            $table->increments('id');            $table->integer('rule_id')->unsigned();            $table->integer('group_id')->unsigned();            $table->timestamps();            $table->foreign('rule_id')->references('id')->on('staff_roles')->onDelete('cascade')->onUpdate('cascade');            $table->foreign('group_id')->references('id')->on('staff_group')->onDelete('cascade')->onUpdate('cascade');        });

该表用于记录规则与规则组对应关系

  • 用户小组表
 Schema::create('staff_users_group', function (Blueprint $table) {            $table->increments('id');            $table->integer('user_id')->unsigned();            $table->integer('group_id')->unsigned();            $table->timestamps();            $table->foreign('user_id')->references('id')->on('staff_users')->onDelete('cascade')->onUpdate('cascade');            $table->foreign('group_id')->references('id')->on('staff_group')->onDelete('cascade')->onUpdate('cascade');        });

该表用于记录用户所属权限小组

代码实现:

  1. 登录:
public function login(Request $request)    {        $account = $request->input('account', '');        $pwd = $request->input('password', '');        if (!$account || !$pwd) {            return Code::_620();        }        //注入服务类获取单个用户信息        $info = $this->accountService->getInfoByName($account);        if (!$info || $info->password != Assistants::getPwd($pwd)) {        //自定义的json返回方式            return Code::_620();        }        //自定义的服务容器        $helper = app('helper');        //产生token的自定义函数        $pro = createToken($info->id);        //将token按时间加密        $token = $helper->getToken($pro);        /**        以下是其他业务,代码到这里登录流程就差不多了,产生了token,更新数据库的原token,如果没有存入token。        **/        $seller = $info->seller()->where('status', SellerAssistants::ACTIVE_STATUS)->get()->toArray();        if(!$seller){            return Code::_500('该账号已被停用');        }        $auth = env('AUTH');        $seller = array_map(function ($item) use ($auth) {            if ($item['is_master']) {                $item['permissions'] = $auth;            }            return ['store_id' => $item['seller_id'], 'auth' => $item['permissions']];        }, $seller);        $seller_ids = array_column($seller, 'store_id');        $store = $this->accountService->getStore($seller_ids);        $tempSeller = [];        foreach ($seller as $val) {            $tempSeller[$val['store_id']] = $val;        }        $returnData = ['token' => $token, 'name' => $info->name, 'store' => []];        foreach ($store as $val) {            if (isset($tempSeller[$val['id']])) {                $temp = $tempSeller[$val['id']];                $temp['store_name'] = $val['name'];                $returnData['store'][] = $temp;            }        }        //更新token        $extend = json_decode($info->extend, true);        $extend['token'] = strtoupper($pro);        if (count($store) == 1) {            $extend['lastStore'] = $store[0]['id'];        }        $info->extend = json_encode($extend, true);        if (!$info->save()) {            return Code::_620();        }        return Code::Y($returnData);    }    //以下为
  1. 生成时间加密的token:
//这里是对第一步的补充说明,分别是生产token,按时间加密,解密token的相关函数//生产tokenfunction createToken($uid = 0){    $time = uniqid($uid);    $rand = random_int(0, 1000);    return md5(md5($time) . md5($rand));}//时间加密function getToken($token='',$str=''){        if(!$token){            $token = strtoupper(env('ACCESS_KEY','MYNAMEDIAMONDS@A!KILL^&!MING@YIQ'));        }        $str = $str?$str:'MINGYI';        $l=strlen($str);        $l=$l>8?8:$l;        $len = 0 - $l;        $time=substr(date('Ymd'),$len);        $b = $time;        while($time !==''){            $char = $time[0];            $token = substr_replace($token,$str[0],$char,0);            $time =substr_replace($time,'',0,1);            $str =substr_replace($str,'',0,1);        }        if(strlen($l)<2){            $l='A'.$l;        }        return strtoupper($l.$token.$b);    }    //解密获取原生token   function getProToken($token=''){        if(!$token){            return $token;        }        $l = substr($token,0,2);        if(intval($l) <1){            $l = substr($l,-1);        }        $len= 0 - $l;        if($len >= 0){            return $token;        }        $token = substr($token,2);        $time = substr($token,$len);        $now = date('Ymd');        $pre = substr_replace($now,$time,$len,$l);        $str=[];        while ($time !==''){            $index= strlen($time) - 1;            $s = $time[$index];            array_unshift($str,$token[$s]);            $token = substr_replace($token,'',$s,1);            $time = substr_replace($time,'',$index,1);        }        $token =substr_replace($token,'',$len);        return ['token'=>$token,'time'=>$pre,'str'=>join('',$str)];    }
  1. AuthServiceProvider服务提供者token验证
/** AuthServiceProvider服务提供者位置: app/Providers/AuthServiceProvider.php**///用户信息我是存在这个模型中的,默认是use的Useruse App\Models\Assistants;.........  public function boot()    {        // Here you may define how you wish users to be authenticated for your Lumen        // application. The callback which receives the incoming request instance        // should return either a User instance or null. You're free to obtain        // the User instance via an API token or any other method necessary.        $this->app['auth']->viaRequest('api', function ($request) {            if(env('AUTH_DEBUG',false)){   //调试模式不验证                return Assistants::first();            }            //从消息头获取传入的token            $token = $request->headers->get('token');            if(!$token){                die("token不能为空!");              }            //解密原声token,获取token,时间,过期时间            $sign = app('helper')->getProToken($token);            $date = date("Ymd");            $timeout = env('TOKEN_TIMEOUT',0);            //验证token是否过期            if ((!$timeout || ($date - (int)$sign['time']) < $timeout) && $sign['token']) {            //token验证通过返回当前认证用户                return Assistants::where('extend->token',$sign['token'])->first();            }            return null;        });    }
  1. auth中间件路由权限检测
/**auth中间件的位置:app/Http/Middleware/Authenticate.php**/  /**     * Handle an incoming request.     *     * @param  \Illuminate\Http\Request $request     * @param  \Closure $next     * @param  string|null $guard     * @return mixed     */    public function handle($request, Closure $next, $guard = null)    {        if ($this->auth->guard($guard)->guest()) {            return Code::_401();        }//获取认证用户信息$request->user()        $userExtend = json_decode($request->user()->extend, true);        if (!isset($userExtend['lastStore'])) {            return Code::_401();        }        /** 获取权限begin        以下代码根据设计的数据库,结合当前用户信息获取用户拥有的权限(或所在权限组拥有的权限,权限可以理解成拥有哪些路由)        **/        $sellerUser = SellerAssistants::where([['seller_id', $userExtend['lastStore']], ['assistant_id', $request->user()->id]])->first();        if (!$sellerUser->is_master) {            $permissions = explode(',', $sellerUser->permissions);            $commonRole = config('role.common');            $role = config('role.auth');            $userRole = array_flip($permissions);            $vaild = array_merge(array_flatten(array_intersect_key($role, $userRole)), $commonRole);            //获取权限 end            //获取当前URI            $path = $request->path();            //获取以“/”开始后面的路由,例如:http://www.xxx.com/order/list 就获取order.list            $method = str_replace('/', '.', substr($path, 0, strpos($path, '/')));            //判断当前处理过后的路由是否在所拥有的权限中            if (!in_array($method, $vaild)) {                return Code::_402();            }        }        //验证通过        return $next($request);    }
原创粉丝点击