中间件
Laravel 内置了一些中间件,例如身份验证、CSRF 保护等。所有的中间件都存放在 app/Http/Middleware 文件夹中。
<?php
namespace App\Http\Controllers;
class UsersController extends Controller
{
public function __construct()
{
$this->middleware('auth', [
'except' => ['show', 'create', 'store']
]);
}
}
middleware
方法接收两个参数,第一个是中间件的名称,第二个是要进行过滤的动作。
except
方法用来设定指定动作不使用 Auth 中间件进行过滤,即除了此处指定的动作以外,所有其他动作都必须登录用户才能访问,类似于黑名单的过滤机制。
only
方法只过滤指定动作。
在控制器 Auth 中间件使用中,首选 except 方法,这样的话,当新增一个控制器方法时,默认是安全的,此为最佳实践。
授权策略
创建授权策略
php artisan make:policy UserPolicy
所有生成的授权策略文件都会被放置在 app/Policies 文件夹下。
app/Policies/UserPolicy.php
<?php
namespace App\Policies;
use Illuminate\Auth\Access\HandlesAuthorization;
use App\Models\User;
class UserPolicy
{
use HandlesAuthorization;
public function update(User $currentUser, User $user)
{
return $currentUser->id === $user->id;
}
}
注册授权策略
Laravel 提供两种注册授权策略的方式,第一种是手动指定,第二种是自动授权注册。自动授权注册如下:
app/Providers/AuthServiceProvider.php
<?php
namespace App\Providers;
class AuthServiceProvider extends ServiceProvider
{
.
.
.
public function boot()
{
$this->registerPolicies();
// 修改策略自动发现的逻辑
Gate::guessPolicyNamesUsing(function ($modelClass) {
// 动态返回模型对应的策略名称,如:// 'App\Models\User' => 'App\Policies\UserPolicy',
return 'App\Policies\\'.class_basename($modelClass).'Policy';
});
}
}
授权策略定义完成之后,便可以在控制器中使用 authorize 方法来验证用户授权策略。默认的 App\Http\Controllers\Controller
类包含了 Laravel 的 AuthorizesRequests
trait。此 trait 提供了 authorize
方法,它可以被用于快速授权一个指定的行为,当无权限运行该行为时会抛出 HttpException。authorize
方法接收两个参数,第一个为授权策略的名称,第二个为进行授权验证的数据。
引用:
<?php
namespace App\Http\Controllers;
class UsersController extends Controller
{
public function edit(User $user)
{
$this->authorize('update', $user);
return view('users.edit', compact('user'));
}
public function update(User $user, Request $request)
{
$this->authorize('update', $user);
$this->validate($request, [
'name' => 'required|max:50',
'password' => 'nullable|confirmed|min:6'
]);
$data = [];
$data['name'] = $request->name;
if ($request->password) {
$data['password'] = bcrypt($request->password);
}
$user->update($data);
session()->flash('success', '个人资料更新成功!');
return redirect()->route('users.show', $user);
}
}
友好的重定向
重定向到用户登录之前访问的页面:
<?php
namespace App\Http\Controllers;
class SessionsController extends Controller
{
public function store(Request $request)
{
$credentials = $this->validate($request, [
'email' => 'required|email|max:255',
'password' => 'required'
]);
if (Auth::attempt($credentials, $request->has('remember'))) {
session()->flash('success', '欢迎回来!');
$fallback = route('users.show', Auth::user());
return redirect()->intended($fallback);
} else {
session()->flash('danger', '很抱歉,您的邮箱和密码不匹配');
return redirect()->back()->withInput();
}
}
.
.
.
}
redirect()
的intended
方法可将页面重定向到上一次请求尝试访问的页面上,并接收一个默认跳转地址参数,当上一次请求记录为空时,跳转到默认地址上。
注册与登录页面访问限制
只让未登录用户访问登录页面:
<?php
namespace App\Http\Controllers;
class SessionsController extends Controller
{
public function __construct()
{
$this->middleware('guest', [
'only' => ['create']
]);
}
}
只让未登录用户访问注册页面:
<?php
namespace App\Http\Controllers;
class UsersController extends Controller
{
public function __construct()
{
$this->middleware('auth', [
'except' => ['show', 'create', 'store']
]);
$this->middleware('guest', [
'only' => ['create']
]);
}
}
app/Http/Middleware/RedirectIfAuthenticated.php
<?php
class RedirectIfAuthenticated
{
public function handle(Request $request, Closure $next, ...$guards)
{
$guards = empty($guards) ? [null] : $guards;
foreach ($guards as $guard) {
if (Auth::guard($guard)->check()) {
session()->flash('info', '您已登录,无需再次操作。');
return redirect(RouteServiceProvider::HOME);
}
}
return $next($request);
}
}
}
app/Providers/RouteServiceProvider.php
class RouteServiceProvider extends ServiceProvider
{
/**
* The path to the "home" route for your application.
*
* This is used by Laravel authentication to redirect users after login.
*
* @var string
*/
public const HOME = '/';