由于 HTTP 协议是无状态的,我们无法在两个页面之间保证用户身份的同步,因此我们需要借助会话在浏览器中临时存储用户的身份信息,进而保证在同一浏览器中,用户在不同页面具有相同的登录状态。
一、RESTful
下面我们还需要对路由进行配置,添加一些接下来需要用到的路由,新增的路由分别对应会话控制器的三个动作:create, store, destroy。
app/Http/routes.php
<?php
Route::get('/', 'StaticPagesController@home')->name('home');
Route::get('/help', 'StaticPagesController@help')->name('help');
Route::get('/about', 'StaticPagesController@about')->name('about');
// 用户注册
Route::get('/signup', 'UsersController@create')->name('signup');
// 资源路由
resource('users', 'UsersController');
// 会话控制,登录,退出
get('login', 'SessionsController@create')->name('login');
post('login', 'SessionsController@store')->name('login');
delete('logout', 'SessionsController@destroy')->name('logout');
新增的路由功能如下:
HTTP 请求URL 动作 作用
GET /login SessionsController@create 显示登录页面
POST /login SessionsController@store 创建新会话(登录)
DELETE /logout SessionsController@destroy 销毁会话(退出登录)
我们可以使用 Laravel 提供的 route:list
命令来查看已添加的路由。
我们可以从上面的列表清晰的看到所有在 routes.php 中被定义好的路由,这将帮助我们更好的理解应用的基础架构。
Laravel 遵从 RESTful
架构的设计原则,将数据看做一个资源,由 URI 来指定资源。对资源进行的获取、创建、修改和删除操作,分别对应 HTTP 协议提供的 GET、POST、PATCH 和 DELETE
方法。当我们要查看一个 id 为 1 的用户时,需要向 /users/1 地址发送一个 GET 请求,当 Laravel 的路由接收到该请求时,默认会把该请求传给控制器的 show 方法进行处理。
Laravel 为我们提供了 resource 方法来定义用户资源路由。
新增的 resource 方法将遵从 RESTful 架构为用户资源生成路由。该方法接收两个参数,第一个参数为资源名称,第二个参数为控制器名称。
resource('users', 'UsersController');
上面代码将等同于:
get('/users', 'UsersController@index')->name('users.index');
get('/users/{id}', 'UsersController@show')->name('users.show');
get('/users/create', 'UsersController@create')->name('users.create');
post('/users', 'UsersController@store')->name('users.store');
get('/users/{id}/edit', 'UsersController@edit')->name('users.edit');
patch('/users/{id}', 'UsersController@update')->name('users.update');
delete('/users/{id}', 'UsersController@destroy')->name('users.destroy');
可以看到使用 resource 方法让我们少写了很多代码,且严格按照了 RESTful 架构对路由进行设计。
生成的资源路由列表信息如下所示:
这时我们访问 http://sample.app/users/1 页面,会出现如下页面。这是因为该路由请求由 UsersController 里面的 show 方法来处理.
二、两种页面提示信息
1.Validate()验证参数错误提示
如果Vlalidate()验证参数错误,则会在视图页面抛出erros的错误信息,并退出程序,这时,我们需要在视图页面判断是否有错误抛出,如果有则显示错误信息。由于错误提示是一个通用的,所以,这里我们封装一个错误的局部视图页面,然后在其他页面引入,这样可以大大增加代码的复用性和简洁性。
// 输入参数验证
$this->validate($request, [
'email' => 'required|email|max:255',
'password' => 'required'
]);
错误提示页面:
views/shared/errors.blade.php
@if(count($errors) > 0)
<div class="alert alert-danger">
<lu>
@foreach($errors->all() as $error)
<li>
{{ $error }}
</li>
@endforeach
</lu>
</div>
@endif
在登录页面引用errors.blade.php:
@extends('layouts.default')
@section('title', '登录')
@section('content')
<div class="col-md-offset-2 col-md-8">
<div class="panel panel-default">
<div class="panel-heading">
<h5>登录</h5>
</div>
<div class="panel-body">
@include('shared.errors')
<form method="POST" action="{{ route('login') }}">
{{ csrf_field() }}
<div class="form-group">
<label for="email">邮箱:</label>
<input type="text" name="email" class="form-control" value="{{ old('email') }}">
</div>
<div class="form-group">
<label for="password">密码:</label>
<input type="password" name="password" class="form-control" value="{{ old('password') }}" />
</div>
<button type="submit" class="btn btn-primary">登录</button>
</form>
<hr />
<p>还没账号?<a href="{{ route('signup') }}">现在注册!</a></p>
</div>
</div>
</div>
@stop
2.session()->flash()闪现提示消息
如在用户登录成功或失败时,我们需要给用户一个友好的提示信息,以往我都是在服务端返回一个JS的弹出框,给出提示信息,这里Laravel为我们提供了一个非常好的提示信息,就是使用会话的flash()方法。
由于 HTTP 协议是无状态的,所以 Laravel 提供了一种用于临时保存用户数据的方法 - 会话(Session),并附带支持多种会话后端驱动,可通过统一的 API 进行使用。
我们可以使用 session()
方法来访问会话实例。而当我们想存入一条缓存的数据,让它只在下一次的请求内有效时,则可以使用 flash
方法。flash 方法接收两个参数,第一个为会话的键,第二个为会话的值,我们可以通过下面这行代码的为会话赋值。
session()->flash('success', '欢迎,您将在这里开启一段新的旅程~');
之后我们可以使用 session()->get('success')
通过键名来取出对应会话中的数据,取出的结果为 欢迎,您将在这里开启一段新的旅程~。
接下来的消息提示我们会用会话进行闪存,并分别为其设定好指定的键。danger, warning, success, info 这四个键名在 Bootstrap 分别具有不同样式展现效果,因此后面我们将使用这几个键名作为消息提示的专有设定。
现在让我们加入消息提醒视图,让会话消息在视图上进行展示。
resources/views/shared/messages.blade.php
@foreach (['danger', 'warning', 'success', 'info'] as $msg)
@if(session()->has($msg))
<div class="flash-message">
<p class="alert alert-{{ $msg }}">
{{ session()->get($msg) }}
</p>
</div>
@endif
@endforeach
session()->has($msg)
可用于判断会话中 $msg 键对应的值是否为空,若为空则在页面上不进行显示。最后,我们通过 session()->get($msg)
来取出对应的值并在页面上进行显示。
现在,让我们在全局通用视图中加入消息提醒视图。
resources/views/layouts/default.blade.php
<!DOCTYPE html>
<html>
<head>
<title>@yield('title', 'Sample App') - Laravel 入门教程</title>
<link rel="stylesheet" href="/css/app.css">
</head>
<body>
@include('layouts._header')
<div class="container">
<div class="col-md-offset-1 col-md-10">
@include('shared.messages')
@yield('content')
@include('layouts._footer')
</div>
</div>
</body>
</html>
当我们再次注册一个验证通过的用户时,能够看到消息提醒在页面上成功展示。
三、登录信息
1.密码验证方法Auth::attempt()
借助 Laravel 提供的 Auth
的 attempt
方法可以让我们很方便的完成用户的身份认证操作,如下所示:
if (Auth::attempt(['email' => $email, 'password' => $password])) {
// 该用户存在于数据库,且邮箱和密码相符合
}
attempt
方法会接收一个数组来作为第一个参数,该参数提供的值将用于寻找数据库中的用户数据。因此在上面的例子中,用户信息将使用 email 字段的值在数据库中进行查找,如果用户被找到,在将 password 的值进行哈希加密并与数据库中已加密过的密码进行匹配,如果匹配后两个值完全一致,则会创建一个通过认证的会话给用户。会话获取到之后,即视为用户登录成功。当用户身份认证成功 attempt 方法会返回 true,反之则返回 false。
会话控制器登录操作:app/Http/Controllers/SessionsController.php
<?php
namespace App\Http\Controllers;
use Auth;
.
.
.
class SessionsController extends Controller
{
// 展示登录视图
public function create()
{
return view('sessions.create');
}
// 存储数据
public function store(Request $request)
{
// 输入参数验证
$this->validate($request, [
'email' => 'required|email|max:255',
'password' => 'required'
]);
$credentials = [
'email' => $request->email,
'password' => $request->password,
];
// 账号密码验证
if(Auth::attempt($credentials))
{
dd(Auth::user());
// 登录成功后的操作
session()->flash('success', '欢迎回来!');
return redirect()->route('users.show', [Auth::user()]);
}
else
{
// 登录失败后的操作
session()->flash('danger', '很抱歉,您的邮箱和密码不匹配');
return redirect()->back();
}
}
}
2.获取登录成功后用户的信息
Larvel 为我们提供了用Auth::user()
方法来获取当前登录用户的信息
Auth::user()
我们可以使用dd(Auth::user());
打印看下获取到的当前登录用户信息:
3.判断用户是否登录Auth::check()
Laravel 提供了 Auth::check()
方法用于判断当前用户是否已登录,已登录返回 true
,未登录返回 false
。
4.退出登录Auth::logout()
我们可以通过调用 Laravel 默认提供的 Auth::logout()
方法来实现用户的退出功能。
四、使用隐藏域来伪造 DELETE 请求
退出登录: Auth::logout();
在做登录退出操作时,需要删除用户的登录信息,如下表单:
<form action="{{ route('logout') }}" method="POST">
{{ csrf_field() }}
{{ method_field('DELETE') }}
<button class="btn btn-block btn-danger" type="submit" name="button">退出</button>
</form>
可以看到用户退出登录的按钮实际上是一个表单的提交按钮,在点击退出按钮之后浏览器将向 /logout 地址发送一个 POST 请求。但由于 RESTful
架构中会使用 DELETE
请求来删除一个资源,当用户退出时,实际上相当于删除了用户登录会话的资源,因此这里的退出操作需要使用 DELETE 请求来发送给服务器。由于浏览器不支持发送 DELETE 请求,因此我们需要使用一个隐藏域来伪造 DELETE 请求
。
在 Blade
模板中,我们可以使用 method_field
方法来创建隐藏域。
{{ method_field('DELETE') }}
其转化为 HTML 代码如下:
<input type="hidden" name="_method" value="DELETE">
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。