iT邦幫忙

0

Laravel 系列 04 前後台登入使用不同的資料表(laravel9)

  • 分享至 

  • xImage
  •  

前台會員:members 資料表
後台使用者:users 資料表

參考專案:https://github.com/ronrun/laravel-multiauth/tree/9.x_two-tables

要不要拆資料表?
參考國外文章與留言,會看到有些人說不需要拆,沒意義。要拆也有要拆的理由。
1 我的啟蒙導師 opencart 一直都是拆開的。前台叫 customer, 後台叫 user。
2 後台使用者基本上只要帳號跟密碼。其它都不是必要的。但是可能我們會可能會想知道前台會員的性別、生日、住址、電話,若是購物網站,還需要收貨地址、收貨人姓、收貨人名字、付款人地址、付款人性、付款人名字… 。後台使用者不需要佔用這些欄位。
3 對非資訊專業的人來說,當他們知道是放一起,可能多少都會有一點疑慮。

還有一種分法,users 保留登入登出常用欄位。把不常用的欄位另外拆成一張表。
users
user_profiles
聽說這樣拆的目的是效率會比較好。我是沒有實作過。

總之,本文要講的是如何使用兩張表: users, members。

建立 members 資料表
php artisan make:migration create_members_table

在 database/migrations 資料夾可以找到,檔名開頭是年月日,後面是 _create_members_table.php
把 users 的 up() 那一段複製過來,改成 members

    public function up()
    {
        Schema::create('members', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->boolean('is_active')->default('1');
            $table->rememberToken();
            $table->timestamps();
        });
    }

可以稍微修改一下 users 資料表

    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name',50);
            $table->string('email',100)->unique();
            $table->string('username',20);
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->boolean('is_active')->default('1');
            $table->rememberToken();
            $table->timestamps();
        });
    }

建立管理者資料
編輯 database\seeders\DatabaseSeeder.php

use App\Models\User;
...
    public function run()
    {
        User::truncate();
        User::create([
            'username' => 'admin',
            'email' => 'admin@example.org',
            'password' => bcrypt('123456'),
            'name' => 'Administrator',
            'is_active' => 1,
            ]);
    }

重建 Migration 並執行 Seeder
php artisan migrate:refresh --seed

建立 Member Model
php artisan make:model Member
把 User Model 的內容複製過來,Class 名稱改成 Member, 存檔。

修改 User Model
新增 username 欄位

    protected $fillable = [
        'name',
        'email',
        'username',
        'password',
    ];

password_resets 是否要處理?
例如也拆成兩個?應該不需要。目前沒看到網路上有文章是拆開的。

新增 guard
修改 config\auth.php

    'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],
改成
    'defaults' => [
        'guard' => 'web',
        'passwords' => 'members',
    ],
    'guards' => [ 
        'web' => [ 
            'driver' => 'session', 
            'provider' => 'users', 
        ], 
    ],
改成
    'guards' => [ 
        'web' => [ 
            'driver' => 'session', 
            'provider' => 'members', 
        ],

        'admin' => [ 
            'driver' => 'session', 
            'provider' => 'users', 
        ], 
    ],
    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],
    ],
改成
    'providers' => [ 
        'members' => [ 
            'driver' => 'eloquent', 
            'model' => App\Models\Member::class, 
        ],

        'users' => [ 
            'driver' => 'eloquent', 
            'model' => App\Models\User::class, 
        ], 
    ],

前台 LoginController
開頭加 use Auth;
新增 overwrite 函數

use Auth;

    /** 
     * Overwrite 
     */ 
    protected function guard() 
    { 
        return Auth::guard('web'); 
    }

    /** 
     * Overwrite 
     */ 
    protected function authenticated(Request $request, $user) 
    { 
        return redirect(route('home')); 
    }

    /** 
     * Overwrite 
     */ 
    public function logout(Request $request) 
    { 
        $this->guard()->logout(); 
        if (!Auth::guard('web')->check() && !Auth::guard('admin')->check()){ 
            $request->session()->invalidate(); 
        } 
        return redirect(route('login')); 
    }

guard() :指定 guard
authenticated(): 登入動作執行之後的轉址
logout(): 將當前的 guard 登出,並且判斷如果完全沒有登入,才清掉 session 。

後台 LoginController
複製前台 LoginController
app\Http\Controllers\Admin\Auth\LoginController.php

一樣開頭加 use Auth; 然後加上上面三個函數。
不一樣的字串:

return Auth::guard('admin');

return redirect(route('admin.dashboard'));

return redirect(route('admin.login'));

再加兩個函數

    protected function username()
    {
        return redirect(route('home'));
    }

    public function showLoginForm() 
    { 
        return view('admin.login'); 
    }

因為 users 資料表用的帳號是 username 而不是 email 。模版位置也不一樣。

app\Exceptions\Handler.php
新增一個函數

    protected function unauthenticated($request, AuthenticationException $exception)
    {
        $guard = \Arr::get($exception->guards(), 0);
        switch ($guard) { 
            case 'admin': 
                return redirect()->guest(route('admin.login')); 
                break; 
            default: 
                return redirect()->guest(route('login')); 
                break; 
        } 
    }

這個函數原本在 vendor\laravel\framework\src\Illuminate\Foundation\Exceptions\Handler.php
內容是

    protected function unauthenticated($request, AuthenticationException $exception)
    {
        return $request->expectsJson()
                    ? response()->json(['message' => $exception->getMessage()], 401)
                    : redirect()->guest(route('login'));
    }

修改 .env
新增後台資料夾名稱

FOLDER_ADMIN=admin

有了這個參數之後,後台可以另外命名。例如叫 backgarden 後花園,還是挪威的森林之類的。比較不會被外人亂試。

登入後的轉址
app\Http\Middleware\RedirectIfAuthenticated.php

    public function handle(Request $request, Closure $next, ...$guards)
    {
        $backend = env('FOLDER_ADMIN');
        //default backend segment is 1, if locale exists,2 
        if($request->segment(1) == $backend || $request->segment(2) == $backend){ 
            if(Auth::guard('admin')->check()){ 
                return redirect(route('admin.dashboard')); 
            } 
        }

        if($request->segment(1) != $backend && $request->segment(2) != $backend){ 
            if(Auth::guard('web')->check()){ 
                return redirect(route('home')); 
            } 
        } 
        return $next($request);
    }

修改 app\Providers\RouteServiceProvider.php

    protected function mapWebRoutes()
    {
        Route::middleware('web')
             ->namespace($this->namespace)
             ->group(base_path('routes/web.php'));
    }

新增一段,使用 admin.php

    protected function mapWebRoutes()
    {
        Route::middleware('web')
             ->namespace($this->namespace)
             ->group(base_path('routes/web.php'));

        Route::middleware('web')
             ->namespace($this->namespace)
             ->group(base_path('routes/admin.php'));
    }

這裡面的 web 不用改。

新增路由 routes/admin.php

<?php
use Illuminate\Support\Facades\Route;

$backend = env('FOLDER_ADMIN');

Route::group(['prefix' => $backend], function () use($backend) {
    Route::redirect('/', $backend.'/dashboard');
	Route::get('/login', [App\Sections\Admin\Http\Controllers\Auth\LoginController::class, 'showLoginForm'])->name('admin.login');
	Route::post('/login', [App\Sections\Admin\Http\Controllers\Auth\LoginController::class, 'login'])->name('admin.login.post');
	Route::post('/logout', [App\Sections\Admin\Http\Controllers\Auth\LoginController::class, 'logout'])->name('admin.logout');

    Route::group(['middleware' => 'auth:admin'], function () {
        Route::get('/dashboard', [App\Sections\Admin\Http\Controllers\DashboardController::class, 'index'])->name('admin.dashboard');
        // other admin routes...
    });
});
?>

新增 resources\views\admin_layouts\app.blade.php
複製 resources\views\layouts\app.blade.php

@if (Route::has('login'))
改成
@if (Route::has('admin.login'))
route('login')
改成
route('admin.login')
route('logout') 
改成
route('admin.logout') 

其它檔像 register, forget password... 等等,不會用到,不用處理。

新增 resources\views\admin\login.blade.php
複製 resources\views\auth\login.blade.php
修改開頭 @extends('admin._layouts.app')
符合大小寫的 email 全部改成 username
Eamil Address 改成 Username

新增 resources\views\admin\dashboard.blade.php
複製 resources\views\home.blade.php
修改開頭 @extends('admin._layouts.app')

新增 DashboardController
複製 HomeController
php artisan make:controller Admin\DashboardController
裡面只需要一個函數

	public function index() 
	{ 
		return view('admin.dashboard'); 
	}

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言