看到Laravel-中国社区经常有人问LaravelPassport是如何进行密码验证获取Token的问题。正好我最近的API项目使用的是LaravelDingoApi+Passport,同样使用Oauth2'grant_type'=>'password'密码授权进行Auth验证,简单总结下如何登录和退出等常见场景和多账户系统认证。基本配置基本安装配置主要参考官方文档,不详述,列出关键代码段config/auth.php'guards'=>['api'=>['driver'=>'passport','provider'=>'users',],],'providers'=>['users'=>['driver'=>'eloquent','model'=>\App\Models\User::class],],Providers/AuthServiceProvider.phppublicfunctionboot(){$this->registerPolicies();//令牌发行的默认有效期是永久的//Passport::tokensExpireIn(Carbon::now()->addDays(2));//Passport::refreshTokensExpireIn(Carbon::now()->addDays(4));Passport::routes(function(RouteRegistrar$router){//密码授权,只需要这些路由config(['auth.guards.api.provider'=>'users']);$router->forAccessTokens();});}Middleware/AuthenticateApi.php自定义中间件返回auth->guard('api')->check()){返回$this->auth->应该使用('api');}thrownewUnauthorizedHttpException('','Unauthenticated');}}App/Http/Kernel.php/***应用的路由中间件。**这些中间件可以分配给组或单独使用。**@vararray*/protected$routeMiddleware=['api-auth'=>AuthenticateApi::class,......];}账号验证字段不限于邮箱。对于账号验证,不限于数据表中的email字段,也可能是用户名或手机号码字段。您只需要在User模型中添加findForPassport方法。示例代码如下:AppModelsUsersclassUserextendsAuthenticatableimplementsTransformable{useTransformableTrait,HasApiTokens,SoftDeletes;publicfunctionfindForPassport($login){return$this->orWhere('email',$login)->orWhere('phone',$login)->first();}}客户端获取access_token请求,只传递用户名和密码。密码授权方式需要提交的参数如下:$response=$http->post('http://your-app.com/oauth/token',['form_params'=>['grant_type'=>'password','client_id'=>'client-id','client_secret'=>'client-secret','username'=>'taylor@laravel.com','password'=>'my-密码','范围'=>'',],]);但是client不想在请求参数里放grant_type,client_id,client_secret,scope或者在请求的时候暴露给client,如果像JWT那样只发送username和password怎么办?很简单,我们只需要将不需要的请求放到配置文件中,然后客户端请求用户名和密码,然后我们将请求发送到oauth/token并进行相关配置即可。.env.phpOAUTH_GRANT_TYPE=passwordOAUTH_CLIENT_ID=1OAUTH_CLIENT_SECRET=EvE4UPGc25TjXwv9Lmk432lpp7Uzb8G4fNJsyJ83OAUTH_SCOPE=*config/passport.php当然该配置你可以配置多个clientreturn['grant_type'=>env('OAUTH_GRANT_TYPE'),'client_id'=>env('OAUTH_CLIENT_ID'),'client_secret'=>env('OAUTH_CLIENT_SECRET'),'scope'=>env('OAUTH_SCOPE','*'),];LoginController.php示例代码如下,因为使用DingoApi配置api前缀,所以请求/api/oauth/token/***获取登录TOKEN*@paramLoginRequest$request*@return\Illuminate\Http\JsonResponse*/publicfunctiontoken(LoginRequest$request){$username=$request->get('用户名');$user=User::orWhere('email',$username)->orWhere('phone',$username)->first();if($user&&($user->status==0)){thrownewUnauthorizedHttpException('','帐户已被禁用');}$client=newClient();尝试{$request=$client->request('POST',请求st()->root()。'/api/oauth/token',['form_params'=>config('passport')+$request->only(array_keys($request->rules()))]);}catch(RequestException$e){thrownewUnauthorizedHttpException('','账户验证失败');}if($request->getStatusCode()==401){thrownewUnauthorizedHttpException('','账户验证失败');}returnresponse()->json($request->getBody()->getContents());}注销并清除Token客户端注销并清除oauth_access_tokens表中记录的记录,示例代码如下:/***Logout*/publicfunctionlogout(){if(\Auth::guard('api')->check()){\Auth::guard('api')->user()->token()->delete();}returnresponse()->json(['message'=>'注销成功','status_code'=>200,'data'=>null]);}根据用户ID认证用户app('auth')->guard('api')->setUser(User::find($userId));多用户表(multi-Auth)认证比如分别对customer表和administrator表进行Auth认证的情况下,关键代码段也列出来了:'guards'=>['api'=>['driver'=>'passport','provider'=>'users',],'admin_api'=>['driver'=>'passport','provider'=>'admin_users',],],'providers'=>['users'=>['driver'=>'eloquent','model'=>\App\Models\User::class],'admin_users'=>['driver'=>'eloquent','model'=>\App\Models\AdminUser::class],],新建一个PasspordAdminServiceProvider来实现我们自己的PasswordGrant,别忘了在config/app的providers配置部分添加AppProviders.php/PasspordAdminServiceProviderapp->make(AdminUserPassportRepository::class),$this->app->make(\Laravel\Passport\Bridge\RefreshTokenRepository::class));$grant->setRefreshTokenTTL(护照::refreshTokensExpireIn());返回$赠款;}}新建一个AdminUserPassportRepository,密码校验主要是通过getUserEntityByUserCredentials,读取配置的guards对应的provider进行认证。我们重写这个方法,并通过传递参数告诉它我们要使用哪个守卫来进行客户端身份验证使用Laravel\Passport\Bridge\UserRepository;使用Laravel\Passport\Bridge\User;使用RuntimeException;类AdminUserPassportRepository扩展UserRepository{publicfunctiongetUserEntityByUserCredentials($username,$password,$grantType,ClientEntityInterface$clientEntity){$guard=App::make(Request::class)->get('guard')?:'api';//其实就是key就是这里,通过传递一个guard参数来告诉它我们是使用api还是admin_apiprovider进行认证$provider=config("auth.guards.{$guard}.provider");if(is_null($model=config("auth.providers.{$provider}.model"))){thrownewRuntimeException('无法从配置中确定用户模型。');}if(method_exists($model,'findForPassport')){$user=(new$model)->findForPassport($username);}else{$user=(new$model)->where('email',$username)->first();}如果(!$用户){返回;}elseif(method_exists($user,'validateForPassportPasswordGrant')){if(!$user->validateForPassportPasswordGrant($password)){返回;}}elseif(!$this->hasher->check($password,$user->密码)){返回;}返回新用户($user->getAuthIdentifier());}}登录和单用户系统一样,只是在请求oauth/token的时候带上guard参数,示例代码如下:Admin/Controllers/Auth/LoginController.phpmiddleware('guest')->except('logout');}/***获取登录令牌*@paramLoginRequest$request*@return\Illuminate\Http\JsonResponse*/publicfunctiontoken(LoginRequest$request){$username=$request->get('username');$user=AdminUser::orWhere('email',$username)->orWhere('phone',$username)->first();if($user&&($user->status==0)){thrownewUnauthorizedHttpException('','账号已被禁止使用');}$client=newClient();尝试{$request=$client->request('POST',request()->root().'/api/oauth/token',['form_params'=>config('passport')+$request->只有(array_keys($request->rules()))+['guard'=>'admin_api']]);}catch(RequestException$e){thrownewUnauthorizedHttpException('','账户验证失败');}if($request->getStatusCode()==401){thrownewUnauthorizedHttpException('','账户验证失败');}returnresponse()->json($request->getBody()->getContents());}/***注销*/publicfunctionlogout(){if(\Auth::guard('admin_api')->check()){\Auth::guard('admin_api')->user()->token()->delete();}returnresponse()->json(['message'=>'成功注销','status_code'=>200,'data'=>null]);}}转载请注明:转载自Ryan是个菜鸟|LNMP技术栈笔记对你帮助很大,不打赏本文链接地址:LaravelPassportAPI认证使用总结
