这一节,我们完成登录登出的功能, 在路由中设置中间件, 过滤一些非法请求,关于中间件、用户授权请参靠官方文档,如果是新手,强烈建议先看下文档然后再开始下面的工作。
#知识学习:
HTTP 中间件
HTTP 中间件提供了一个方便的机制来过滤进入应用程序的 HTTP 请求,例如,Laravel 本身使用中间件来验证用户的身份,如果用户未通过身份验证,中间件将会把用户导向登录页面,反之,当用户通过了身份验证,中间件将会通过此请求并接着往下执行。
当然,除了身份验证之外,中间件也可以被用来运行各式各样的任务,CORS 中间件负责替所有即将离开程序的响应加入适当的标头。而日志中间件则可以记录所有传入应用程序的请求。
Laravel 框架已经内置了一些中间件,包括维护、身份验证、CSRF 保护,等等。所有的中间件都放在app/Http/Middleware
目录内。
注册中间件#
全局中间件#
若是希望每个 HTTP 请求都经过一个中间件,只要将中间件的类加入到 app/Http/Kernel.php
的 $middleware
属性清单列表中。
为路由指派中间件#
如果你要指派中间件给特定路由,你得先在 app/Http/Kernel.php
给中间件设置一个好记的键,默认情况下,这个文件内的 $routeMiddleware
属性已包含了 Laravel 目前设置的中间件,你只需要在清单列表中加上一组自定义的键即可。
// 在 App\Http\Kernel 类内...
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,];
中间件一旦在 HTTP kernel 文件内被定义,即可在路由选项内使用 middleware 键值指定:
Route::get('admin/profile', ['middleware' => 'auth', function () {
//}]);
项目实战:
先看routes.php的登陆登出的路由:
##############
### 登陆登出功能
##############
Route::get('login', [
// 'uses' :表示指定路由名称到控制器动作
'middleware' => 'guest', 'as'=>'login', 'uses' => 'loginController@LoginGet'
]);
Route::post('login', [
'middleware' => 'guest', 'uses' => 'loginController@LoginPost'
]);
Route::get('logout', [
'middleware' => 'auth', 'as'=>'logout', 'uses' => 'loginController@Logout'
]);
guest 只允许游客(没登陆的情况下)访问get路由login和post路由login,要是已经登录,就会跳转到相应页面,注意关键词响应。我们登录用户有两种,学生,和管理员,当他们在登录的情况下要想访问这两个路由,肯定会做出不同的响应。即,学生,跳转到学生主页,管理员,跳转到管理员主页.现在来看看RedirectIfAuthenticated.php
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->check()) // 用户是否登陆
{
if(!Auth::user()->is_admin){
return new RedirectResponse('/stu/home'); // 不是管理员
}else{
return new RedirectResponse(url('/admin')); // 如果是管理员,则进入后台管理页面
}
}
return $next($request);
}
auth 只有登录用户才能访问,auth是在Kernel.php中注册的全局中间件
'auth' => \App\Http\Middleware\Authenticate::class,
我们可以看下源码 Authenticate.php
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->guest()) // 没有登录,是游客
{
if ($request->ajax()) // 通过ajax来请求,这里返回json数据
{
return response('Unauthorized.', 401);
}
else // 直接请求, 跳转到登录页
{
return redirect()->guest('auth/login');
}
}
return $next($request);
}
也就是说只有登录了才能登出,就是这个意思。
说完了中间件,创建控制器。loginController.php
php artisan make:controller loginController --plain
在loginController.php的控制器中写需要的方法:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
// 引入用户类
use App\UsersInfo;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redirect;
class loginController extends Controller
{
/**
* 返回login视图,登陆页面
*/
public function loginGet()
{
return view('login');
}
/**
* 登陆响应
*/
public function loginPost(Request $request)
{
// 登录验证规则
$this->validate($request, UsersInfo::rules());
$id = $request->get('id');
$password = $request->get('password');
if(Auth::attempt(['id' => $id, 'password' => $password], $request->get('remember')))
{
if(!Auth::user()->is_admin){
return Redirect::route('stu_home');
}else {
return Redirect::action('Admin\AdminController@index');
}
}else{
return Redirect::route('login')
->withInput()
->withErrors('学号或者密码不正确,请重试!');
}
}
/**
* 用户登出
*/
public function logout()
{
if (Auth::check()) {
Auth::logout();
}
return Redirect::route('login');
}
}
可以使用validate验证用户输入,在laravel5中使用validate非常方便,注意第二个参数,User::rules(), 这是在User模型中一个静态方法,接着在User.php中加入静态方法。
protected static function rules()
{
return [
'id' => 'required|digits:10', <!-- 代表必需填写,10位数字 -->
'password' => 'required' <!-- 必填 -->
];
}
验证用户登录使用了Auth::attempt(),这是laravel中自带的验证方法,非常好用,如果验证通过,接着判断是否是管理员,然后分别跳转到不同的url.
return Redirect::route('stu_home') -- 对应路由名为stu_home的路由
return Redirect::action('Admin\AdminController@index') -- 对于这个index方法
登出使用的是Auth::logout().
这时候点击登录,laravel会告诉你view(login)不存在,创建login.blade.php文件
@extends('master')
@section('title')
欢迎登录
@stop
@section('content')
<div class="container-fluid">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">登录</div>
<div class="panel-body">
@include('errors.list')
{!! Form::open(['url' => '/login', 'class' => 'form-horizontal', 'role' => 'form']) !!}
<div class="form-group">
{!! Form::label('id', '学号', ['class' => 'col-md-4 control-label']) !!}
<div class="col-md-6">
{!! Form::text('id', old('id'), ['class' => 'form-control', 'required']) !!}
</div>
</div>
<div class="form-group">
{!! Form::label('password', '密码', ['class' => 'col-md-4 control-label']) !!}
<div class="col-md-6">
{!! Form::password('password', ['class' => 'form-control', 'required']) !!}
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<div class="checkbox">
<label>
<input type="checkbox" name="remember"> Remember Me
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
{!! Form::submit('Login', ['class' => 'btn btn-primary form-control']) !!}
</div>
</div>
{!! Form::close() !!}
</div>
</div>
</div>
</div>
</div>
@stop
这时候要是点击登录,如果报错,因为在laravel5中Illuminate/Html组件被移了,我们可以在composer.json的required数组中加入
"illuminate/html": "5.0"
在config/app.php中的provider数组中添加
'Illuminate\Html\HtmlServiceProvider',
aliases数组中添加
'Html' => 'Illuminate\Html\HtmlFacade',
'Form' => 'Illuminate\Html\FormFacade',
接着执行:
composer update
等待安装完成之后,就能看到我们的登录页面了
这时候你随便输入学号密码,页面会刷新一下,不会跳转,错误已经被存在了Session中,现在把他显示出来. 在login.blade.php中有这样一行
@include('errors.list')
我们创建errors/list.blade.php
@if (count($errors) > 0)
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
这时候要是输入不符合前面的规则,你会看到提示英文提示信息,要是输入密码或者帐号错误,你会看到 学号或者密码不正确,请重试, 这是loginPost中返回的自定义错误信息.
现在,我们有两个问题需要解决,第一,英文提示信息,对我们中国用户可能不太友好,你可以更换.第二,错误提示会一直留着页面.下面,我们一一解决.
关于表单验证的自定义错误信息,可以查看官方链接, 现在我们找到/resources/lang/en/validation.php,在custom数组中添加:
'id' => [
'required' => '学号不能为空',
"digits" => "学号必须是 10 位数字",
"unique" => "该同学已经存在",
],
'password' => [
'required' => '密码不能为空',
],
重新随便输入学号密码,你就可以看到中文提示信息了
关于提示信息的隐藏,这里有两种简单的解决方案,参靠bootstrap中的警告框,修改/errors/list.blade.php
@if (count($errors) > 0)
<div class="alert alert-danger alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
这个时候错误信息的右边就会有一个关闭按钮,点击就可隐藏错误信息
第二种带关闭提示错误信息的显示框:
来源:oschina
链接:https://my.oschina.net/u/2557944/blog/665165