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(); //更新数据库
}
 
posted @ 2016-11-17 14:14  猿界小学生  阅读(5302)  评论(0编辑  收藏  举报