Laravel 5.3 登陸註冊底層實現詳解

 
 
 
每一個控制器都使用 trait 來引入它們須要的方法 */
用於處理用戶登陸認證
用於處理新用戶註冊
包含重置密碼邏輯
用於處理重置密碼郵件連接
 
認證須要的視圖
包含了應用的基礎佈局文件
 
 
Auth::routes();
 
static::$app->make('router')->auth();
 
 
 
 
 
 
 
註冊
 
 
 
public function showRegistrationForm()
{
return view('auth.register');
}
return view('auth.register');
public function register(Request $request)
{
$this->validator($request->all())->validate();
event(new Registered($user = $this->create($request->all())));
$this->guard()->login($user);
return $this->registered($request, $user)
?: redirect($this->redirectPath());
}
 
1. $this->validator($request->all())->validate();
 
 
$this->validator() protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|min:6|confirmed',
]);
}
若是咱們的用戶註冊須要的表單與這幾個字段不一致(例如須要添加一個手機號),就在這裏修改
event(new Registered($user = $this->create($request->all())));
 
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
}
利用 request 參數建立一個新用戶,而後返回用戶實例。接着觸發用戶註冊事件。
3. $this->guard()->login($user);
 
$this->guard()
 
 
'defaults' => [
'guard' => 'web', # 'passwords' => 'users',
],
 
'guards' => [
'web' => [
'driver' => 'session', Illuminate\Auth\SessionGuard::class
'provider' => 'users',
],
 
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
 
'providers' => [
'users' => [
'driver' => 'eloquent', Illuminate\Auth\EloquentUserProvider::class
'model' => App\User::class, # App\User::class
],
 
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
 
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
],
],
 
App\User
 
方法:
 
文件 vendor/laravel/framework/src/Illuminate/Auth/SessionGuard.php 內:
 
public function login(AuthenticatableContract $user, $remember = false)
{
$this->updateSession($user->getAuthIdentifier());
 
// If the user should be permanently "remembered" by the application we will
// queue a permanent cookie that contains the encrypted copy of the user
// identifier. We will then decrypt this later to retrieve the users.
if ($remember) {
$this->createRememberTokenIfDoesntExist($user); //若是用戶選中了「記住我」,則生產remember_token
 
$this->queueRecallerCookie($user);
}
 
// If we have an event dispatcher instance set we will fire an event so that
// any listeners will hook into the authentication events and run actions
// based on the login and logout events fired from the guard instances.
$this->fireLoginEvent($user, $remember);
 
$this->setUser($user);
}
其中 $user->getAuthIdentifier() 用來獲取用戶惟一標識( Illuminate\Auth\Authenticatable::getAuthIdentifier)
 
其中 $this->updateSession(); 實現以下:
protected function updateSession($id)
{
$this->session->set($this->getName(), $id); //將用戶惟一標識寫入Session,記錄登陸狀態
$this->session->migrate(true); //更新SessionID同時保留Session全部屬性
}
 
4. return $this->registered($request, $user)
?: redirect($this->redirectPath());
 
public function redirectPath()
{
return property_exists($this, 'redirectTo') ? $this->redirectTo : '/home';
}
 
 
DRY 原則
登陸(認證)
 
認證
$this->post('login', 'Auth\LoginController@login');
一, 登陸(認證)
 
文件 vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesUsers.php 內:
 
public function login(Request $request)
{
$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.
if ($this->hasTooManyLoginAttempts($request)) { //爆破保護
$this->fireLockoutEvent($request);
 
return $this->sendLockoutResponse($request);
}
 
$credentials = $this->credentials($request); //獲取登陸憑證,這裏指用email和密碼的數組
 
if ( $this->guard()->attempt($credentials, $request->has('remember'))) {
return $this->sendLoginResponse($request);
}
 
// 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.
$this->incrementLoginAttempts($request);
 
return $this->sendFailedLoginResponse($request);
}
 
1. $this->validateLogin($request); 數據驗證。
 
protected function validateLogin(Request $request)
{
$this->validate($request, [
$this->username() => 'required', 'password' => 'required',
]);
}
 
2. $credentials = $this->credentials($request);
 
protected function credentials(Request $request)
{
return $request->only( $this->username(), 'password');
}
public function username()
{
return 'email';
}
3. $this->guard()->attempt($credentials, $request->has('remember')) //進行身份認證
 
這裏 $this->guard() 獲取系統默認 guard,配置文件 ),對應 Illuminate\Auth\SessionGuardIlluminate\Auth\SessionGuard
文件 vendor/laravel/framework/src/Illuminate/Auth/SessionGuard.php 內:
 
public function attempt(array $credentials = [], $remember = false, $login = true)
{
$this->fireAttemptEvent($credentials, $remember, $login); //觸發認證事件
 
$this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);
 
// If an implementation of UserInterface was returned, we'll ask the provider
// to validate the user against the given credentials, and if they are in
// fact valid we'll log the users into the application and return true.
if ( $this->hasValidCredentials($user, $credentials)) {
if ($login) {
$this->login($user, $remember);
}
 
return true;
}
 
// If the authentication attempt fails we will fire an event so that the user
// may be notified of any suspicious attempts to access their account from
// an unrecognized user. A developer may listen to this event as needed.
if ($login) {
$this->fireFailedEvent($user, $credentials);
}
 
return false;
}
 
3.1 $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);
 
這裏 $this->provider 是指 Illuminate\Auth\EloquentUserProvider::class 的實例。
 
文件 vendor/laravel/framework/src/Illuminate/Auth/EloquentUserProvider.php 內:
 
// 根據認證憑證去查詢用戶信息,返回 User Model 供 guard 實例進行身份認證
public function retrieveByCredentials(array $credentials)
{
if (empty($credentials)) {//這裏的$credentials是指 email和明文密碼的數組
return;
}
 
// First we will add each credential element to the query as a where clause.
// Then we can execute the query and, if we found a user, return it in a
// Eloquent User "model" that will be utilized by the Guard instances.
$query = $this->createModel()->newQuery();
 
foreach ($credentials as $key => $value) {
if (! Str::contains($key, 'password')) {
$query->where($key, $value);
}
}
 
return $query->first();
}
 
3.2 $this->hasValidCredentials($user, $credentials) 驗證密碼是否正確!!!
 
文件 vendor/laravel/framework/src/Illuminate/Auth/SessionGuard.php 內:
 
protected function hasValidCredentials($user, $credentials)
{
return ! is_null($user) && $this->provider->validateCredentials($user, $credentials);
}
 
文件 vendor/laravel/framework/src/Illuminate/Auth/EloquentUserProvider.php 內:
 
public function validateCredentials(UserContract $user, array $credentials)
{
$plain = $credentials['password'];
// $plain 明文密碼, $user->getAuthPassword() 數據庫內保持的hashed 密碼
return $this->hasher->check($plain, $user->getAuthPassword());
}
 
Illuminate\Contracts\Hashing\Hasher 接口內:
/**
* Check the given plain value against a hash.
*
* @param string $value
* @param string $hashedValue
* @param array $options
* @return bool
*/
public function check($value, $hashedValue, array $options = []);
 
3.3 $this->login($user, $remember); 見註冊部分的說明
 
退出登陸
 
文件 vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesUsers.php 內:
 
public function logout(Request $request)
{
$this->guard()->logout();
 
$request->session()->flush();
 
$request->session()->regenerate();
 
return redirect('/');
}
 
文件 vendor/laravel/framework/src/Illuminate/Auth/SessionGuard.php 內:
 
public function logout()
{
$user = $this->user(); // User Model
 
// If we have an event dispatcher instance, we can fire off the logout event
// so any further processing can be done. This allows the developer to be
// listening for anytime a user signs out of this application manually.
$this->clearUserDataFromStorage(); //清除cookie, session
 
if (! is_null($this->user)) {
$this->refreshRememberToken($user); //清除數據庫中的 remember_token
}
 
if (isset($this->events)) {
$this->events->fire(new Events\Logout($user));
}
 
// Once we have fired the logout event we will clear the users out of memory
// so they are no longer available as the user is no longer considered as
// being signed into this application and should not be available here.
$this->user = null;
 
$this->loggedOut = true;
}
 
protected function clearUserDataFromStorage()
{
$this->session->remove($this->getName()); //移除session
 
if (! is_null($this->getRecaller())) {
$recaller = $this->getRecallerName();
 
$this->getCookieJar()->queue($this->getCookieJar()->forget($recaller)); //cookie過時
}
}
 
/*清除 remember_token*/
protected function refreshRememberToken(AuthenticatableContract $user)
{
$user->setRememberToken($token = Str::random(60));
$this->provider->updateRememberToken($user, $token); //經過設置一個隨機串來清除原 token
}
 
文件 vendor/laravel/framework/src/Illuminate/Auth/EloquentUserProvider.php 內:
 
/* Update the "remember me" token for the given user in storage. */
public function updateRememberToken(UserContract $user, $token)
{
$user->setRememberToken($token);
$user->save(); //更新數據庫
}
相關文章
相關標籤/搜索