如何在 Laravel 上進行多權限登入管理
因為之前寫 Codeigniter 時習慣把一般用戶與能進後台的用戶在 login 時就把他們分開,所以想說用 laravel
也來實現相同的功能。因為對 laravel 還不熟,所以想遵從 laravel 的規範用最少的修正來完成。
Provider
需求:
該功能基於原有的 users 表不作變動的情況下,讓一位使用者有多個權限,並限制某權限能否登入該系統
事前準備:
安裝好 Laravel 並且最少建立起能夠執行登入登出的功能
建立一張名為 role 的表,表內最少包含以下欄位
id(int)
user_id(int)
role(int)
開始:
從原有的 Users.php 拷貝一個 UsersModel.php (沿用原有的 Users 也可以)
建立一個 RoleModel.php
在 UsersModel.php 內加上以下方法
1
2
3
4public function roles()
{
return $this->hasMany(RoleModel::class, 'user_id');
}執行 php artisan make:provider CustomUserProvider 建立一個自己認證用的 Provider
這個 Provider 必需繼承 EloquentUserProvider 或 UserProvider。並且換掉 retrieveByCredentials() 函數的執行內容來進行驗證。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55<?php
namespace App\Providers;
use App\Models\UsersModel;
use Illuminate\Auth\EloquentUserProvider;
use Illuminate\Support\Str;
use Illuminate\Contracts\Support\Arrayable;
/**
* 自定義登入時驗證項目
*
* @author LIN CHENGHUNG <k80092@hotmail.com>
*/
class CustomUserProvider extends EloquentUserProvider
{
/**
* 透過驗證資訊來比對身份
*
* @param array $credentials 驗證資訊
*
* @return Illuminate\Contracts\Auth\Authenticatable
*/
public function retrieveByCredentials(array $credentials)
{
if (
empty($credentials) ||
(count($credentials) === 1 &&
Str::contains($this->firstCredentialKey($credentials), 'password'))
) {
return;
}
$query = $this->newModelQuery();
// 追加條件
$query = $query->whereHas('roles', function ($query) {
$query->whereRole(config('const.ROLE')['ADMIN']);
});
foreach ($credentials as $key => $value) {
if (Str::contains($key, 'password')) {
continue;
}
if (is_array($value) || $value instanceof Arrayable) {
$query->whereIn($key, $value);
} else {
$query->where($key, $value);
}
}
return $query->first();
}
}修改 AuthServiceProvider.php 來將寫好的 Provider 註冊
1
2
3Auth::provider('myAuthProvider', function ($app, array $config) {
return new CustomUserProvider($app['hash'], 'App\Models\UsersModel');
});修改 Auth.php 中預設的 eloquent provider 換成自己寫的 myAuthProvider
1
2
3
4
5
6
7......
'providers' => [
'users' => [
'driver' => 'myAuthProvider', // 修改這裡
'model' => App\Models\UsersModel::class,
],
......Guard
基本到這裡為止就算沒有實作這個 Guard 也已經完成一個最簡單的限制特定權限登入的功能。不過如果需要針對認證流程再作定義的話,可以在實作一個 Guard 來完成!
建立一個管理員用的 Guard 叫做 AdminGuard(我放在 App\Guards 底下)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26<?php
namespace App\Guards;
use Illuminate\Auth\SessionGuard;
/**
* 管理者守門員
*
* @author LIN CHENGHUNG <k80092@hotmail.com>
*/
class AdminGuard extends SessionGuard
{
/**
* 登入驗證
*
* @param array $credentials
* @param bool $remember
* @return bool
*/
public function attempt(array $credentials = [], $remember = false)
{
// 自行定義驗證內容
return parent::attempt($credentials, $remember);
}
}修改 AuthServiceProvider.php 來將寫好的 Guard 註冊
1
2
3Auth::extend('admin', function ($app, $name, $config) {
return new AdminGuard($name, new CustomUserProvider($app['hash'], 'App\Models\UsersModel'), $app['session.store']);
});增加 Auth.php 中的 guard
1
2
3
4
5
6
7
8
9
10
11
12......
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
// 增加這邊
'admin' => [
'driver' => 'admin',
'provider' => 'users',
],
......這樣就可以用以下的方式來進行登入
1
2
3if (auth('admin')->attempt($credentials, $remember)) {
// dosomething
}然後在像下面這樣設定路由的 guard 來限制哪些是管理者才能訪問的URL
1
2
3Route::middleware('auth:admin')->get('test',function() {
echo 'test';
});代碼:
參考: