简介
认证系统主要由两部分组成:
guards
每个请求中,怎么认证用户
例如:通过 session guard
providers
怎样从持久化存储中获取用户
例如:通过 Eloquent, DB
一般来说,不用修改默认的认证配置
认证快速开始
php artisan make:auth
修改跳转地址
protected $redirectTo = '/';
# 方法的优先级高于属性定义
protected function redirectTo()
{
return '/path';
}
认证字段修改
public function username(){
return 'username';
}
自定义 guard
use Illuminate\Support\Facades\Auth;
# 返回的应该是 a guard instance
protected function guard()
{
return Auth::guard('guard-name');
}
路由认证指定 guard
->middleware('auth:api');
如果登录失败次数过多,会禁止登录一段时间。判断的标准是 username 方法返回值和 ip 。
手动认证用户
# 当你不喜欢自带的控制器去认证用户,你可以移除这些控制器,
# 引入 Auth 利用 attempt 手动认证
if (Auth::attempt(['email' => $email, 'password' => $password])) {
// 认证成功后会产生 session
return redirect()->intended('dashboard');
}
if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) {
// 字段 active 必须是 1
}
if (Auth::guard('admin')->attempt($credentials)) {
// 指定 guard
}
登出
Auth::logout();
记住用户 (无限期)
# $remember 是个 bool 值
if (Auth::attempt(['email' => $email, 'password' => $password], $remember)) {
// The user is being remembered...
}
# 判断是否选择了记住用户
if (Auth::viaRemember()) {
//
}
Auth::login($user);
Auth::login($user, true); // 记住
Auth::guar('admin')->login($user);
Auth::loginUsingId(1);
Auth::loginUsingId(1, true);
Auth::once($credentials); // 临时认证,无状态的。
无登录页面, 利用弹窗请求认证用户
Route::get('profile', function(){
// ...
})->middleware('auth.basic');
# 如果使用 php fastcgi,可能会失效,可以在 .htaccess 里面加入
RewriteCond %{HTTP:Authorization} ^(.+)$
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
利用中间件
namespace App\Http\Middleware;
use Illuminate\Support\Facades\Auth;
class AuthenticateOnceWithBasicAuth
{
public function handle($request, $next)
{
return Auth::onceBasic() ?: $next($request);
}
}
# 注册中间件后 ->middleware('auth.basic.once');
增加自定义 guard
# extend 方法
class AuthServiceProvider extends ServiceProvider
{
/**
* Register any application authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Auth::extend('jwt', function ($app, $name, array $config) {
// Return an instance of Illuminate\Contracts\Auth\Guard...
return new JwtGuard(Auth::createUserProvider($config['provider']));
});
}
}
增加自定义 provider
# extend 方法
class AuthServiceProvider extends ServiceProvider
{
/**
* Register any application authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Auth::provider('riak', function ($app, array $config) {
// Return an instance of Illuminate\Contracts\Auth\UserProvider...
return new RiakUserProvider($app->make('riak.connection'));
});
}
}
API 认证
略
Gates 和 Policies
一般情况下,可以替换使用这两者进行认证。相比较而言,Gates 一般是个闭包,简单的逻辑。而 Policies 可能会涉及到模型或者资源。
Gates
# App\Providers\AuthServiceProvider
public function boot()
{
$this->registerPolicies();
Gate::define('update-post', function ($user, $post) {
return $user->id == $post->user_id;
});
}
public function boot()
{
$this->registerPolicies();
Gate::define('update-post', 'PostPolicy@update');
}
Gate::resource('posts', 'PostPolicy');
# Gate::define('posts.view', 'PostPolicy@view');
# Gate::define('posts.create', 'PostPolicy@create');
# Gate::define('posts.update', 'PostPolicy@update');
# Gate::define('posts.delete', 'PostPolicy@delete');
Gate::resource('posts', 'PostPolicy', [
'image' => 'updateImage',
'photo' => 'updatePhoto',
]);
# Gate::define('post.image', 'PostPolicy@updateImage');
# Gate::define('post.photo', 'PostPolicy@updatePhoto');
if (Gate::allows('update-post', $post)) {
// The current user can update the post...
}
if (Gate::denies('update-post', $post)) {
// The current user can't update the post...
}
if (Gate::forUser($user)->allows('update-post', $post)) {
// The user can update the post...
}
if (Gate::forUser($user)->denies('update-post', $post)) {
// The user can't update the post...
}
Policies
php artisan make:policy PostPolicy --model=Post
# AuthServiceProvider
use App\Policies\PostPolicy;
use App\Post;
protected $policies = [
Post::class => PostPolicy::class,
];
# PostPolicy
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
// 没有模型,只有一个参数的情况,一般 create 会是这种情况
public function create(User $user)
{
//
}
# 在最前端认证,一般是管理员在这里认证
public function before($user, $ability): bool
{
if ($user->isSuperAdmin()) {
return true;
}
}
# 使用
if ($user->can('update', $post)) {
//
}
# 如果 给定的模型 即 $post 已经注册了 policy ,会调用合适的 policy,
# 如果没有注册,会尝试查找和操作名称相匹配的 Gate 。
# 如果是只有一个参数,如 create 操作
use App\Post;
if ($user->can('create', Post::class)) {
// Executes the "create" method on the relevant policy...
}
# 通过中间件
use App\Post;
Route::put('/post/{post}', function (Post $post) {
// The current user may update the post...
})->middleware('can:update,post'); // 第二个参数是 路由参数
// 认证失败返回 403
# 如果是只有一个参数,如 create 操作
Route::post('/post', function () {
// The current user may create posts...
})->middleware('can:create,App\Post');
# 在控制器中
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
// The current user can update the blog post...
// 授权失败返回 403
}
# 如果是只有一个参数,如 create 操作
public function create(Request $request)
{
$this->authorize('create', Post::class);
}
# 在 blade 中使用
@can('update', $post)
<!-- The Current User Can Update The Post -->
@elsecan('create', App\Post::class)
<!-- The Current User Can Create New Post -->
@endcan
@cannot('update', $post)
<!-- The Current User Can't Update The Post -->
@elsecannot('create', App\Post::class)
<!-- The Current User Can't Create New Post -->
@endcannot
# 类似于
@if (Auth::user()->can('update', $post))
<!-- The Current User Can Update The Post -->
@endif
@unless (Auth::user()->can('update', $post))
<!-- The Current User Can't Update The Post -->
@endunless
@can('create', App\Post::class)
<!-- The Current User Can Create Posts -->
@endcan
# 如果是只有一个参数,如 create 操作
@cannot('create', App\Post::class)
<!-- The Current User Can't Create Posts -->
@endcannot
laravel 加密
encrypt($yourString) // 这是内部序列化后再加密
try {
$decrypted = decrypt($encryptedValue);
// 如果加密值被修改,或非法值传入,抛出异常 DecryptException
} catch (DecryptException $e) {
//
}
# 如果不需要序列化加解密
$encrypted = Crypt::encryptString('Hello world.');
$decrypted = Crypt::decryptString($encrypted);
laravel Hash
利用了 Bcrypt ,会随着硬件的加强而加强加密 hash。
$passwordIntoDB = Hash::make($request->newPassword);
# 验证
if (Hash::check('plain-text', $hashedPassword)) {
// The passwords match...
}
# 验证是否需要重新加密
/**
The needsRehash function allows you to determine
if the work factor used by the hasher has changed
since the password was hashed.
这句话理解很久,不太明白它的意思。
since 这儿应该翻译成自从。
意思是自从密码哈希后,你可以利用这个函数确定哈希的哈希因子是否改变过,
以至于我们需要重新进行哈希。
*/
if (Hash::needsRehash($hashed)) {
$hashed = Hash::make('plain-text');
}