Laravel8.* 实现前后台分离登陆认证

2,229 阅读2分钟

1.启用Laravel认证

Laravel 的 laravel/ui 包提供了一种快速认证方法,可以使用一些简单的命令来支持你进行身份验证所需的所有路由和视图:

composer require laravel/ui
php artisan ui vue --auth

这个命令应该在新应用程序上使用,并将安装布局视图,注册和登录视图以及所有身份验证端点的路由。 还将生成一个 HomeController 来处理应用程序仪表板的登录后请求。

2.创建Admin模型

php artisan make:model Admin -m

迁移如下:

Schema::create('admins', function (Blueprint $table) {
    $table->id();
    $table->string("name",30)->default("")->comment("姓名");
    $table->string("email",50)->comment("邮箱")->nullable()->unique();
    $table->string("phone",11)->comment("电话")->nullable()->unique();
    $table->string("password",64)->default("")->comment("密码");
    $table->string("profile")->default("")->comment("介绍");
    $table->rememberToken();
    $table->timestamps();
});

3.修改Admin模型继承Authenticatable

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class Admin extends Authenticatable
{
    use HasFactory, Notifiable;
    /**
     * 定义网关
     * @var string
     */
    protected $guard_name = 'admin';

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

    protected $hidden = [
        'password', 'remember_token',
    ];
}

4.自定义Guards

打开config/auth.php文件添加自定义守护Guards

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],
    'admin' => [
        'driver' => 'session',
        'provider' => 'admins',
    ],
    'api' => [
        'driver' => 'token',
        'provider' => 'users',
        'hash' => false,
    ],
],
'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => App\User::class,
    ],
    'admins' => [
        'driver' => 'eloquent',
        'model' => App\Models\Admin::class,
    ],
],
'passwords' => [
    'users' => [
        'provider' => 'users',
        'table' => 'password_resets',
        'expire' => 60,
        'throttle' => 60,
    ],
    'admins' => [
        'provider' => 'admins',
        'table' => 'password_resets',
        'expire' => 60,
        'throttle' => 60,
    ],
],

5.创建自定义认证中间件

php artisan make:middleware AuthenticateBackend

设置认证

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Auth;

class AuthenticateBackend
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if (Auth::guard('admin')->guest()) {
            if ($request->ajax() || $request->wantsJson()) {
                return response('Unauthorized.', 401);
            } else {
                return redirect()->guest('admin/login');
            }
        }
        return $next($request);
    }
}

在App\Http\Kernel.php中添加自定义的认证中间件

protected $routeMiddleware = [
    //....
    'admin' => \App\Http\Middleware\AuthenticateBackend::class,
];

6.修改身份验证异常处理程序

在app\Exceptions\Handler.php中添加如下方法:

/**
 * Convert an authentication exception into a response.
 *
 * @param \Illuminate\Http\Request $request
 * @param \Illuminate\Auth\AuthenticationException $exception
 * @return \Symfony\Component\HttpFoundation\Response
 */
protected function unauthenticated($request, AuthenticationException $exception)
{
    if ($request->expectsJson()) {
        response()->json(['message' => $exception->getMessage()], 401);
    }
    if (in_array('admin', $exception->guards())) {
        return redirect()->guest('/admin/login');
    }
    return redirect()->guest(route('login'));
}

7.创建后台控制器基类

php artisan make:controller Admin/AdminController

设置认证guards

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class AdminController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth:admin');
    }
}

添加登陆控制器

php artisan make:controller Admin/LoginController

代码如下:


use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Validator;

class LoginController extends Controller
{
    protected $redirectTo = '/admin';
    
    public function __construct()
    {
        $this->middleware('guest:admin', ['except' => 'logout']);
    }
    
    protected function guard()
    {
        return auth()->guard('admin');
    }

    /**
     * 后台登陆
     * @param Request $request
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\RedirectResponse|\Illuminate\View\View
     */
    public function login(Request $request)
    {
        if ($request->isMethod('post')) {
            $validator = Validator::make($request->input(),
                ['email' => 'required','password' => 'required',],
                ['required' => ':attribute 为必填项','min' => ':attribute 长度不符合要求'],
                ['email' => '账号','password' => '密码']
            );
            if ($validator->fails()) {
                return back()->withErrors($validator)->withInput();
            }
            if ($this->guard()->attempt(['email'=>$request->email, 'password'=>$request->password])) {
                return $request->ajax() || $request->wantsJson() ? new JsonResponse(['code' => 0], 200) : redirect('/admin/login');
            } else {
                return $request->ajax() || $request->wantsJson() ? new JsonResponse(['code' => -1], 204) : back()->with('error', '账号或密码错误')->withInput();
            }
        }
        return view('admin.login');
    }

    /**
     * 退出登陆
     * @return mixed
     */
    public function logout()
    {
        if($this->guard()->user()){
            $this->guard()->logout();
        }

        return $request->wantsJson()
            ? new JsonResponse([], 204)
            : redirect('/admin/login');
    }
}

8.添加路由

Route::get('/', function () {
    return view('welcome');
});

Auth::routes();

Route::get('/home', 'HomeController@index')->name('home');

Route::namespace('Admin')->group(function() {
    Route::any('/admin/login', 'LoginController@login');
    Route::any('/admin/logout', 'LoginController@logout')->name('admin.logout');
    Route::get('/admin', 'DashboardController@index');
});

拆分路由配置文件

接下来,我们将实现将前台后的路由配置在不同的路由配置文件中,如下:

routes\web.php
routes\admin.php

首选,我们需要在routes文件夹创建admin.php配置文件,将上面的配置抽离出来

//routes\admin.php
Route::namespace('Admin')->group(function() {
    Route::any('/admin/login', 'LoginController@login');
    Route::any('/admin/logout', 'LoginController@logout')->name('admin.logout');
    Route::get('/admin', 'DashboardController@index');
});
加载路由配置

app\Providers\RouteServiceProvider.php

    /**
     * Define your route model bindings, pattern filters, etc.
     *
     * @return void
     */
    public function boot()
    {
        $this->configureRateLimiting();

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

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

            Route::middleware('admin')
                ->namespace($this->namespace)
                ->group(base_path('routes/admin.php'));
        });
    }
添加中间件分组

app\Http\Kernel.php

/**
 * The application's route middleware groups.
 *
 * @var array
 */
protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        // \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'admin' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        // \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'api' => [
        'throttle:api',
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
];

至此配置完成