laravel 5.5 -- Authentication 认证 laravel 安全

单于越
2023-12-01

简介

认证系统主要由两部分组成:

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');
}
 类似资料: