laravel 實現多使用者體系登入

Chiu發表於2019-02-16

laraveli新增一個或多個使用者表,以admin為例。。
部分檔案內容可能需要根據實際情況修改

建立一個Admin模型

php artisan make:model Admin -m

編寫admins表欄位

Schema::create(`admins`, function (Blueprint $table) {
    $table->increments(`id`);
    $table->string(`name`)->unique();
    $table->string(`password`);
    $table->rememberToken();
    $table->timestamps();
});

編輯admin模型

<?php

namespace App;

use IlluminateNotificationsNotifiable;
use IlluminateFoundationAuthUser as Authenticatable;

/**
 * @property int $id
 * @property CarbonCarbon $created_at
 * @property CarbonCarbon $updated_at
 */
class Admin extends Authenticatable
{
    use Notifiable;
    protected $fillable = [
        `name`, `password`,`remember_token`
    ];
    protected $hidden = [
        `password`,`remember_token`
    ];
}

修改auth.php配置檔案

`guards` => [
    ...
    `admin` => [
        `driver` => `session`,
        `provider` => `admins`
    ]
],

`providers` => [
    ...
    `admins` => [
        `driver` => `eloquent`,
        `model` => AppAdmin::class,
    ]
],

app/Http/Controllers下建立目錄Admin/Auth
Admin目錄下建立檔案HomeController.php(這個檔案用來測試登入成功後的跳轉頁面)

<?php

namespace AppHttpControllersAdmin;

use AppHttpControllersController;
use IlluminateHttpRequest;

class HomeController extends Controller
{
    /**
     * HomeController constructor.
     */
    public function __construct()
    {
        $this->middleware(`auth:admin`);
    }

    /**
     * Show the application dashboard.
     *
     * @return IlluminateHttpResponse
     */
    public function index()
    {
        return view(`admin.home`);
    }
}

使用命令生成一個Request

php artisan make:request AdminLoginRequest

此時在app/Http/Request目錄下便生成了這個檔案,然後編輯這個檔案

<?php

namespace AppHttpRequests;

use IlluminateFoundationHttpFormRequest;

class AdminLoginRequest extends FormRequest
{
    /**
     * 確定使用者是否有權發出此請求.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * 獲取適用於請求的驗證規則.
     *
     * @return array
     */
    public function rules()
    {
        return [
            `name`     => `required`,
            `password` => [`required`, `min:6`] //密碼必須,最小長度為6
        ];
    }
}

Admin/Auth目錄下建立檔案LoginController.php

<?php

namespace AppHttpControllersAdminAuth;

use AppHttpControllersController;
use AppHttpRequestsAdminLoginRequest;
use IlluminateSupportFacadesAuth;

class LoginController extends Controller
{
    public function showLoginForm()
    {
        return view(`admin.auth.login`);
    }

    public function postLogin(AdminLoginRequest $loginRequest)
    {
        $data = $loginRequest->only(`name`, `password`);
        $result = Auth::guard(`admin`)->attempt($data, true);
        if ($result) {
            return redirect(route(`admin.home`));
        } else {
            return redirect()->back()
                ->with(`name`, $loginRequest->get(`name`))
                ->withErrors([`name` => `使用者名稱或密碼錯誤`]);
        }
    }

    public function postLogout()
    {
        Auth::guard(`admin`)->logout();
        return redirect(route(`admin.login.show`));
    }
}

新增路由。開啟app/providers/RouteServiceProvider.php
在方法mapWebRoutes()方法後面增加一個方法

protected function mapAdminWebRoutes()
    {
        Route::middleware(`web`)
            ->prefix(`admin`)
            ->namespace($this->namespace)
            ->group(base_path(`routes/admin.php`));
    }

map()方法裡呼叫上面增加的方法

public function map()
    {
        $this->mapApiRoutes();

        $this->mapAdminWebRoutes();//呼叫新增的方法

        $this->mapWebRoutes();
    }

routes目錄下增加一個路由檔案admin.php

<?php
Route::get(`login`,`AdminAuthLoginController@showLoginForm`)
    ->middleware(`guest:admin`)
    ->name(`admin.login.show`);

Route::get(`/`,`AdminHomeController@index`)
    ->name(`admin.home`);

Route::post(`login`,`AdminAuthLoginController@postLogin`)
    ->middleware(`guest:admin`)
    ->name(`admin.login.post`);

Route::post(`logout`,`AdminAuthLoginController@postLogout`)
    ->middleware(`auth:admin`)
    ->name(`admin.logout`);

home.blade.php複製到resources/views/admin
layouts/app.blade.php複製為layouts/admin.blade.php,修改相應的地方

<ul class="nav navbar-nav navbar-right">
    <!-- Authentication Links -->
    @guest(`admin`)
        <li><a href="{{ route(`admin.login.show`) }}">admin Login</a></li>
    @else
    <li class="dropdown">
        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false" aria-haspopup="true">
            {{ Auth::guard(`admin`)->user()->name }} <span class="caret"></span>
        </a>

        <ul class="dropdown-menu">
            <li>
                <a href="{{ route(`admin.logout`) }}"
                    onclick="event.preventDefault();
                    document.getElementById(`logout-form`).submit();">
                    Logout
                </a>

                <form id="logout-form" action="{{ route(`admin.logout`) }}" method="POST" style="display: none;">
                    {{ csrf_field() }}
                </form>
            </li>
        </ul>
    </li>
    @endguest
</ul>

login.blade.php複製到admin/Auth目錄下

@extends(`layouts.admin`)

@section(`content`)
    <div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
                <div class="panel panel-default">
                    <div class="panel-heading">Admin Login</div>

                    <div class="panel-body">
                        <form class="form-horizontal" method="POST" action="{{ route(`admin.login.post`) }}">
                            {{ csrf_field() }}

                            <div class="form-group{{ $errors->has(`name`) ? ` has-error` : `` }}">
                                <label for="name" class="col-md-4 control-label">E-Mail Address</label>

                                <div class="col-md-6">
                                    <input id="name" type="text" class="form-control" name="name"
                                           value="{{ old(`name`) }}" required autofocus>

                                    @if ($errors->has(`name`))
                                        <span class="help-block">
                                        <strong>{{ $errors->first(`name`) }}</strong>
                                    </span>
                                    @endif
                                </div>
                            </div>

                            <div class="form-group{{ $errors->has(`password`) ? ` has-error` : `` }}">
                                <label for="password" class="col-md-4 control-label">Password</label>

                                <div class="col-md-6">
                                    <input id="password" type="password" class="form-control" name="password" required>

                                    @if ($errors->has(`password`))
                                        <span class="help-block">
                                        <strong>{{ $errors->first(`password`) }}</strong>
                                    </span>
                                    @endif
                                </div>
                            </div>

                            <div class="form-group">
                                <div class="col-md-8 col-md-offset-4">
                                    <button type="submit" class="btn btn-primary">
                                        Login
                                    </button>
                                </div>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

資料填充

php artisan make:seed AdminsTableSeeder

編輯AdminsTableSeeder.php

public function run()
    {
        AppAdmin::insert([
            `name`=>`yzha5`,
            `password`=> bcrypt(`123456`)
        ]);
    }

DatabaseSeeder.php

$this->call(AdminsTableSeeder::class);

檔案上傳至伺服器,登入伺服器,執行填充命令

php artisan migrate
php artisan db:seed

此時,直接開啟http://xxx/admin並不會跳轉到http://xxx/admin/login,因此需要處理一些異常。開啟app/Exceptions/Handle.php
重寫unauthenticated()方法。

use IlluminateSupportFacadesRoute;

protected function unauthenticated($request, AuthenticationException $exception)
    {
        return starts_with(Route::currentRouteName(), `admin`)
            ? redirect(route(`admin.login.show`))
            : parent::unauthenticated($request, $exception);
    }

完善一下

以上程式碼,當admin登入後,再次訪問/admin/login這個URI時,會自動跳轉到/home這個URI,這是因為guest這個中介軟體預設跳轉到了/home,也就是middleware目錄下的RedirectIfAuthenticated.php這個檔案。

解決方法為:
建立一箇中單件,名為:RedirectIfAdminAuthenticated

php artisan make:middleware RedirectIfAdminAuthenticated

編輯這個檔案:

<?php

namespace AppHttpMiddleware;

use Closure;
use IlluminateSupportFacadesAuth;

class RedirectIfAdminAuthenticated
{
    /**
     * Handle an incoming request.
     *
     * @param $request
     * @param Closure $next
     * @param null $guard
     * @return IlluminateHttpRedirectResponse|IlluminateRoutingRedirector|mixed
     */
    public function handle($request, Closure $next, $guard = null)
    {
        if (Auth::guard($guard)->check()) {
            return redirect(`/admin`);
        }

        return $next($request);
    }
}

Kernel.php中新增一行

protected $routeMiddleware = [
        ...
        `admin.guest` => AppHttpMiddlewareRedirectIfAdminAuthenticated::class,
        ...
    ];

更改admin路由,將guest:admin改為admin.guest:admin

Route::get(`login`,`AdminAuthLoginController@showLoginForm`)
    ->middleware(`admin.guest:admin`)
    ->name(`admin.login.show`);
Route::post(`login`,`AdminAuthLoginController@postLogin`)
    ->middleware(`admin.guest:admin`)
    ->name(`admin.login.post`);

相關文章