laravel5.2 验证有所改动,增加了一个叫guard的东西,这个东西主要是负责检查用户的session之类的
原文有提到: https://laravel.com/docs/5.2/authentication#introduction
At its core, Laravel’s authentication facilities are made up of “guards” and “providers”. Guards define how users are authenticated for each request. For example, Laravel ships with a session guard which maintains state using session storage and cookies and a token guard, which authenticates users using a “API token” that is passed with each request.
这个命令会自动创建一些验证相关的文件resources/views/auth 和resources/views/layouts,不过我们暂时先不用,先理解过程。
php artisan make:auth
先提前布置一下路由表
app/Http/routes.phpRoute::group(['middleware' => ['web']], function () { Route::resource('/articles','ArticlesController'); Route::get('auth/login','Auth\AuthController@getLogin'); //打开登录页面,用get Route::post('auth/login','Auth\AuthController@postLogin'); //提交request给login页面的postLogin方法,其实是给Auth\AuthController的postLogin Route::get('auth/register','Auth\AuthController@getRegister'); //类似 Route::post('auth/register','Auth\AuthController@postRegister');//类似 Route::get('auth/logout','Auth\AuthController@getLogout'); //logout单独独立出来,也是类似的方式使用// Route::get('auth/logout',function(){// Auth::logout();// });});
需要说明一下:
1. 上面这些在laravel 5.2里面都是要包含在web这个中间件的[‘middleware’ => [‘web’],除了csrf之外,还有一些验证的逻辑会有关联。
2. login 和 register是在“保护”内的,而logout则不是,具体可以看AuthController.php,主要是因为logout比较随意,也不能用session来限制其访问
3. 上面这些路由都不是默认提供的,需要自己手写,主要是因为laravel 5.2开始没有提供,不过正因为这样,整个流程也比较清晰的整理出来
4. laravel这个默认登录注册是需要跟model关联的,如果model有问题,则也会影响整个过程,laravel把很多东西都封装好了,对于一般人来说,不容易知道里面的流程怎么生效的,需要不断研究学习源码才行。
app/Http/Controllers/Auth/AuthController.php< ?phpnamespace App\Http\Controllers\Auth;use App\User;use Validator;use App\Http\Controllers\Controller;use Illuminate\Foundation\Auth\ThrottlesLogins;use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;class AuthController extends Controller{ /* |-------------------------------------------------------------------------- | Registration & Login Controller |-------------------------------------------------------------------------- | | This controller handles the registration of new users, as well as the | authentication of existing users. By default, this controller uses | a simple trait to add these behaviors. Why don't you explore it? | */ use AuthenticatesAndRegistersUsers, ThrottlesLogins; //使用了这2个类作为主要的验证功能类,下面会说到 /** * Where to redirect users after login / registration. * * @var string */ protected $redirectTo = '/'; //这个是登录成功的重定向链接,有时候需要修改。 /** * Create a new authentication controller instance. * * @return void */ public function __construct() { $this->middleware($this->guestMiddleware(), ['except' => 'logout']); //排除了logout,不在中间件保护范围内 } /** * Get a validator for an incoming registration request. * * @param array $data * @return \Illuminate\Contracts\Validation\Validator */ protected function validator(array $data) //这里自带了一个验证逻辑,request的验证有2种方法,一种是写request文件,一种就是用validator { return Validator::make($data, [ 'name' => 'required|max:255', 'email' => 'required|email|max:255|unique:users', 'password' => 'required|min:6|confirmed', //默认有这些验证逻辑,这个逻辑是有讲究的,因为默认的laravel验证注册登录是会关联到这里的。 ]); } /** * Create a new user instance after a valid registration. * * @param array $data * @return User */ protected function create(array $data) //这个就是create,在函数体里面就是用了model的create方法,直接在数据库生成数据 { return User::create([ 'name' => $data['name'], 'email' => $data['email'], 'password' => bcrypt($data['password']), ]); }}
vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesAndRegistersUsers.php< ?phpnamespace Illuminate\Foundation\Auth;trait AuthenticatesAndRegistersUsers{ use AuthenticatesUsers, RegistersUsers {//这里是重点,使用了两个类,一个是验证用户,一个是注册用户 AuthenticatesUsers::redirectPath insteadof RegistersUsers; AuthenticatesUsers::getGuard insteadof RegistersUsers; }}
因为我们在路由上写了要调用getlogin,postlogin,getregister,postregister,而AuthenticatesUsers就是主要处理getlogin,postlogin的。
vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesUsers.php<?phpnamespace Illuminate\Foundation\Auth;use Illuminate\Http\Request;use Illuminate\Support\Facades\Auth;use Illuminate\Support\Facades\Lang;trait AuthenticatesUsers{ use RedirectsUsers; /** * Show the application login form. * * @return \Illuminate\Http\Response */ public function getLogin() //getLogin在此! { return $this->showLoginForm(); } /** * Show the application login form. * * @return \Illuminate\Http\Response */ public function showLoginForm() //其实调用这个showLoginForm { $view = property_exists($this, 'loginView') ? $this->loginView : 'auth.authenticate'; if (view()->exists($view)) { return view($view); } return view('auth.login'); //看到这里可以看出,判断是否存在auth.authenticate文件,如果没有则用auth.login,这个文件其实就是views文件夹下面的blade文件,即resources/views/auth/login.blade.php } /** * Handle a login request to the application. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function postLogin(Request $request) //这里是postlogin { return $this->login($request); } /** * Handle a login request to the application. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function login(Request $request) //其实调用的是login { $this->validateLogin($request); // If the class is using the ThrottlesLogins trait, we can automatically throttle // the login attempts for this application. We'll key this by the username and // the IP address of the client making these requests into this application. $throttles = $this->isUsingThrottlesLoginsTrait(); //这个是判读用户登录的频率相关的 if ($throttles && $lockedOut = $this->hasTooManyLoginAttempts($request)) { //这里有一个更详细的toomanylogin $this->fireLockoutEvent($request); return $this->sendLockoutResponse($request); } $credentials = $this->getCredentials($request); //这里是用来确认用户是否登陆过,会跟remember有关,就是免登陆相关的。 if (Auth::guard($this->getGuard())->attempt($credentials, $request->has('remember'))) { return $this->handleUserWasAuthenticated($request, $throttles); } // If the login attempt was unsuccessful we will increment the number of attempts // to login and redirect the user back to the login form. Of course, when this // user surpasses their maximum number of attempts they will get locked out. if ($throttles && ! $lockedOut) { $this->incrementLoginAttempts($request); } return $this->sendFailedLoginResponse($request); } /** * Validate the user login request. * * @param \Illuminate\Http\Request $request * @return void */ protected function validateLogin(Request $request) { $this->validate($request, [ $this->loginUsername() => 'required', 'password' => 'required', ]); } /** * Send the response after the user was authenticated. * * @param \Illuminate\Http\Request $request * @param bool $throttles * @return \Illuminate\Http\Response */ protected function handleUserWasAuthenticated(Request $request, $throttles) { if ($throttles) { $this->clearLoginAttempts($request); } if (method_exists($this, 'authenticated')) { return $this->authenticated($request, Auth::guard($this->getGuard())->user()); } return redirect()->intended($this->redirectPath()); } /** * Get the failed login response instance. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ protected function sendFailedLoginResponse(Request $request) { return redirect()->back() ->withInput($request->only($this->loginUsername(), 'remember')) ->withErrors([ $this->loginUsername() => $this->getFailedLoginMessage(), ]); } /** * Get the failed login message. * * @return string */ protected function getFailedLoginMessage() { return Lang::has('auth.failed') ? Lang::get('auth.failed') : 'These credentials do not match our records.'; } /** * Get the needed authorization credentials from the request. * * @param \Illuminate\Http\Request $request * @return array */ protected function getCredentials(Request $request) { return $request->only($this->loginUsername(), 'password'); } /** * Log the user out of the application. * * @return \Illuminate\Http\Response */ public function getLogout() { return $this->logout(); } /** * Log the user out of the application. * * @return \Illuminate\Http\Response */ public function logout() { Auth::guard($this->getGuard())->logout(); return redirect(property_exists($this, 'redirectAfterLogout') ? $this->redirectAfterLogout : '/'); } /** * Get the guest middleware for the application. */ public function guestMiddleware() { $guard = $this->getGuard(); return $guard ? 'guest:'.$guard : 'guest'; } /** * Get the login username to be used by the controller. * * @return string */ public function loginUsername() { return property_exists($this, 'username') ? $this->username : 'email'; } /** * Determine if the class is using the ThrottlesLogins trait. * * @return bool */ protected function isUsingThrottlesLoginsTrait() { return in_array( ThrottlesLogins::class, class_uses_recursive(static::class) ); } /** * Get the guard to be used during authentication. * * @return string|null */ protected function getGuard() { return property_exists($this, 'guard') ? $this->guard : null; }}
这个主要处理getregister,postregister
vendor/laravel/framework/src/Illuminate/Foundation/Auth/RegistersUsers.php< ?phpnamespace Illuminate\Foundation\Auth;use Illuminate\Http\Request;use Illuminate\Support\Facades\Auth;trait RegistersUsers{ use RedirectsUsers; /** * Show the application registration form. * * @return \Illuminate\Http\Response */ public function getRegister() //这里就是getRegister { return $this->showRegistrationForm(); } /** * Show the application registration form. * * @return \Illuminate\Http\Response */ public function showRegistrationForm() //其实调用的是他 { if (property_exists($this, 'registerView')) { return view($this->registerView); } return view('auth.register'); //看逻辑可以知道,如果没有registerView的话就用auth.register来作为注册页,原理跟login差不多 } /** * Handle a registration request for the application. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function postRegister(Request $request) //这里是postRegister { return $this->register($request); } /** * Handle a registration request for the application. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function register(Request $request) //其实是用他,这里有点复杂 { $validator = $this->validator($request->all()); if ($validator->fails()) { //会先去判断是否能够通过validator,而这个validator就是之前在AuthController.php的那个,而且这个throwValidationException(并不是在页面的显示错误的 //是在这里storage/logs/laravel.log $this->throwValidationException( $request, $validator ); } Auth::guard($this->getGuard())->login($this->create($request->all())); //这里通过调用getGuard来判断是否确认写入数据库,这里首先通过create写入数据库,然后进行login登录,登录成功了,就是下面的回调页面了。好巧妙。 return redirect($this->redirectPath()); //注册成功返回的那个回调页面,也是在AuthController.php配 } /** * Get the guard to be used during registration. * * @return string|null */ protected function getGuard() { return property_exists($this, 'guard') ? $this->guard : null; //这个就是判断auth.php里的guard的。 }}
resources/views/auth/login.blade.php@extends('layout.app')@section('content') <div class="col-md-4 col-md-offset-4"> {!! Form::open(['url'=>'auth/login']) !!} //这里跟路由表配置要相匹配,post提交到auth/login <!--- Email Field ---> <div class="form-group"> {!! Form::label('email', 'Email:') !!} //登录项有2个,一个是email一个是password {!! Form::email('email', null, ['class' => 'form-control']) !!} </div> <!--- Password Field ---> <div class="form-group"> {!! Form::label('password', 'Password:') !!} {!! Form::password('password', ['class' => 'form-control']) !!} </div> {!! Form::submit('登录',['class'=>'btn btn-primary form-control']) !!} {!! Form::close() !!} </div> <ul class="list-group"> //这个代码是额外的,主要是为了看验证失败的时候的报错信息,laravel会将错误信息写到$errors里面去,所以能够在页面获取来看 @foreach($errors->all() as $error) <li class="list-group-item list-group-item-danger">{{$error}}</li> @endforeach </ul>@stop
这里我们有4个字段,有3个事必须的,name,password,email,因为这个对应AuthController的create方法的值,其实这个也是跟model的表有关,因为我们的user表也就是使用这3个字段来做验证的。
resources/views/auth/register.blade.php@extends('layout.app')@section('content') <div class="col-md-4 col-md-offset-4"> {!! Form::open(['url'=>'auth/register']) !!} //注意这里是post到auth/register <!--- Name Field ---> <div class="form-group"> {!! Form::label('name', 'Name:') !!} {!! Form::text('name', null, ['class' => 'form-control']) !!} </div> <!--- Email Field ---> <div class="form-group"> {!! Form::label('email', 'Email:') !!} {!! Form::email('email', null, ['class' => 'form-control']) !!} </div> <!--- Password Field ---> <div class="form-group"> {!! Form::label('password', 'Password:') !!} {!! Form::password('password', ['class' => 'form-control']) !!} </div> <!--- Password-confirm Field ---> <div class="form-group"> {!! Form::label('password_confirmation', 'Password_confirmation:') !!} //需要注意的是,这个password_confirmation是有讲究的,如果不是这样写的话,会导致validator验证不通过 {!! Form::password('password_confirmation', ['class' => 'form-control']) !!} </div> {!! Form::submit('注册',['class'=>'btn btn-primary form-control']) !!} {!! Form::close() !!} </div> <ul class="list-group"> @foreach($errors->all() as $error) <li class="list-group-item list-group-item-danger">{{$error}}</li> @endforeach </ul>@stop
vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesUsers.php public function getLogout() //这里就是getLogout { return $this->logout(); } /** * Log the user out of the application. * * @return \Illuminate\Http\Response */ public function logout() //其实是他 { Auth::guard($this->getGuard())->logout(); return redirect(property_exists($this, 'redirectAfterLogout') ? $this->redirectAfterLogout : '/auth/login'); //这里需要注意的是,这里logout的重定向地址需要设置一下,默认是/但是如果/是要登录才可以看的话,那么就会出错。 }
app/Http/Controllers/Auth/AuthController.php protected $redirectTo = '/articles'; //刚才我们提到登录成功的重定向地址就是这个$redirectTo protected $guard = 'web'; //这个guard是特别的,是因为laravel5.2的关系
对此官网的解释
Guard CustomizationYou may also customize the "guard" that is used to authenticate users. To get started, define a guard property on your AuthController. The value of this property should correspond with one of the guards configured in your auth.php configuration file:protected $guard = 'admin';
你要设置一个guard的值,并且要跟auth.php对应好,然后我们再看看auth.php
config/auth.php< ?phpreturn [ /* |-------------------------------------------------------------------------- | Authentication Defaults |-------------------------------------------------------------------------- | | This option controls the default authentication "guard" and password | reset options for your application. You may change these defaults | as required, but they're a perfect start for most applications. | */ 'defaults' => [ 'guard' => 'web', //默认指定了一个guard 是叫web的 'passwords' => 'users', ], /* |-------------------------------------------------------------------------- | Authentication Guards |-------------------------------------------------------------------------- | | Next, you may define every authentication guard for your application. | Of course, a great default configuration has been defined for you | here which uses session storage and the Eloquent user provider. | | All authentication drivers have a user provider. This defines how the | users are actually retrieved out of your database or other storage | mechanisms used by this application to persist your user's data. | | Supported: "session", "token" | */ 'guards' => [ 'web' => [ //然后这个叫web的guard呢有driver和provider这些属性,一个是session 驱动,一个是users的provider,简单理解就是用users表和session来做guard,这个guard可以理解为校验 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'token', 'provider' => 'users', ], ], /* |-------------------------------------------------------------------------- | User Providers |-------------------------------------------------------------------------- | | All authentication drivers have a user provider. This defines how the | users are actually retrieved out of your database or other storage | mechanisms used by this application to persist your user's data. | | If you have multiple user tables or models you may configure multiple | sources which represent each model / table. These sources may then | be assigned to any extra authentication guards you have defined. | | Supported: "database", "eloquent" | */ 'providers' => [ 'users' => [ //这里再次解释了users的这个provider就是一个eloquent,就是model Users 'driver' => 'eloquent', 'model' => App\User::class, ], // 'users' => [ // 'driver' => 'database', // 'table' => 'users', // ], ],];
注册成功后会有数据在数据库生成检查数据库
id name email password remember_token created_at updated_at1 123456 1239@qq.com $2y$10$EfEo1gCcK6JdwgxjqjNbK.fVZjgu7i68uKMPqNwBX9VpNVuvgthm6 wSaR4V256k4xxisbbiVNS1o9iEqwCaIDZB5Nk5YZYj5JNBENIiowTALrBNNT 2016-05-25 15:31:07 2016-05-25 15:41:53
每次登录成功都会有一个laravel_session,而guard就是校验这个东西的,判断是否能登陆之类。