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.php
Route::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();
// });
});
需要说明一下:
上面这些在laravel 5.2里面都是要包含在web这个中间件的['middleware' => ['web'],除了csrf之外,还有一些验证的逻辑会有关联。
login 和 register是在“保护”内的,而logout则不是,具体可以看AuthController.php,主要是因为logout比较随意,也不能用session来限制其访问
上面这些路由都不是默认提供的,需要自己手写,主要是因为laravel 5.2开始没有提供,不过正因为这样,整个流程也比较清晰的整理出来
laravel这个默认登录注册是需要跟model关联的,如果model有问题,则也会影响整个过程,laravel把很多东西都封装好了,对于一般人来说,不容易知道里面的流程怎么生效的,需要不断研究学习源码才行。
这是我理解的过程图
首先看AuthController
app/Http/Controllers/Auth/AuthController.php
< ?php
namespace 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']),
]);
}
}
然后我们看AuthenticatesAndRegistersUsers
vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesAndRegistersUsers.php
< ?php
namespace Illuminate\Foundation\Auth;
trait AuthenticatesAndRegistersUsers
{
use AuthenticatesUsers, RegistersUsers {//这里是重点,使用了两个类,一个是验证用户,一个是注册用户
AuthenticatesUsers::redirectPath insteadof RegistersUsers;
AuthenticatesUsers::getGuard insteadof RegistersUsers;
}
}
然后我们再看AuthenticatesUsers
因为我们在路由上写了要调用getlogin,postlogin,getregister,postregister,而AuthenticatesUsers就是主要处理getlogin,postlogin的。
vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesUsers.php
<?php
namespace 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;
}
}
然后我们再看RegistersUsers.php
这个主要处理getregister,postregister
vendor/laravel/framework/src/Illuminate/Foundation/Auth/RegistersUsers.php
< ?php
namespace 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
然后我们看AuthenticatesUsers.php
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的重定向地址需要设置一下,默认是/但是如果/是要登录才可以看的话,那么就会出错。
}
然后我们再看AuthController.php
app/Http/Controllers/Auth/AuthController.php
protected $redirectTo = '/articles'; //刚才我们提到登录成功的重定向地址就是这个$redirectTo
protected $guard = 'web'; //这个guard是特别的,是因为laravel5.2的关系
对此官网的解释
Guard Customization
You 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
< ?php
return [
/*
|--------------------------------------------------------------------------
| 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_at
1 123456 1239@qq.com $2y$10$EfEo1gCcK6JdwgxjqjNbK.fVZjgu7i68uKMPqNwBX9VpNVuvgthm6 wSaR4V256k4xxisbbiVNS1o9iEqwCaIDZB5Nk5YZYj5JNBENIiowTALrBNNT 2016-05-25 15:31:07 2016-05-25 15:41:53
每次登录成功都会有一个laravel_session,而guard就是校验这个东西的,判断是否能登陆之类。