本文旨在熟悉laravel框架的使用,以及学习如何搭建一个自己的后台,所以内容较多,相应组件会附带常用的理论知识。文章写于2021.10.18,使用laravel8.6,vue3.0等,用户认证使用了Laravel Fortify 和 Laravel Sanctum.

iShot2021-03-04 21.44.09.png

一、安装laravel

推荐使用linux系统,安装好宝塔后,安装环境:php8.0 + mysql5.7 + nginx,php要安装Fileinfo、exif扩展等。laravel使用composer安装,新建一个站点,进入站点根目录,终端里输入:

  1. composer create-project laravel/laravel cms

执行后,会在站点目录创建cms目录,将目录里的内容全选剪切到站点根目录后,将站点目录设置为755 www:www权限。
然后,修改根目录.env文件,主要有以下几个要修改:

#网址
APP_URL=http://vue.dzbfsj.com
#数据库
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=vue_dzbfsj_com
DB_USERNAME=vue_dzbfsj_com
DB_PASSWORD=ykNLrkAsdnYTeppj

二、安装身份验证组件

需要安装 Laravel Sanctum 和 Laravel Fortify 两个软件包。
Laravel Sanctum 只关心管理 API 令牌和使用会话 cookie 或令牌来认证现有用户。 Sanctum 不提供任何处理用户注册,重置密码等相关的路由。所以我们使用 Laravel Fortify(用于用户注册,重置密码等)和 Laravel Sanctum(API 令牌管理,会话身份认证)。

安装Fortify

首先,使用 Composer 软件包管理器安装 Fortify:

composer require laravel/fortify

下一步,使用 vendor:publish 命令来发布 Fortify 的资源:

php artisan vendor:publish --provider="Laravel\Fortify\FortifyServiceProvider"

生成的配置文件在config/fortify.php,然后迁移数据库:

php artisan migrate

在config/app.php 配置文件的 providers 数组中注册,即添加一行:

App\Providers\FortifyServiceProvider::class,

身份认证

所有的身份认证视图逻辑,都可以使用 Laravel\Fortify\Fortify 类提供的方法来自定义。通常,你应该从应用的 App\Providers\FortifyServiceProvider 类的 boot 方法中调用此方法。Fortify 将负责定义返回此视图的 /login 路由:

public function boot()
{
    //定义登录模板
    Fortify::loginView(function(){
      return view('auth.login');
    });
        //定义登录验证逻辑
    Fortify::authenticateUsing(function(Request $request){
      $user = User::where('email',$request->email)->first();
      if($user && Hash::check($request->password,$user->password)){
        return $user;
      }
    });
      //定义注册模板
    Fortify::registerView(function(){
      return view('auth.register');
    });

    // ...
}

你的登录模板应包括一个向 /login 发出 POST 请求的表单。/login 表单需要一个电子邮件地址、用户名和一个 password。电子邮件、用户名字段与 config/fortify.php 配置文件中的 username 值相匹配。另外,可以提供布尔值 remember 字段来指导用户想要使用 Laravel 提供的「记住我」功能。
如果登录尝试成功,Fortify 会将您重定向到通过应用程序 fortify 配置文件中的 home 配置选项配置的 URI。 如果登录请求是 XHR 请求,将返回 200 HTTP 响应。
如果请求不成功,用户将被重定向回登录页,验证错误将通过共享的 $errors Blade 模板变量 提供给你。 或者,在 XHR 请求的情况下,验证错误将与 422 HTTP 响应一起返回。
更多信息可查阅:https://learnku.com/docs/laravel/8.5/fortify/10424

安装Sanctum

通过 Composer 安装 Laravel Sanctum:

composer require laravel/sanctum

接下来,你需要使用 vendor:publish Artisan 命令发布 Sanctum 的配置和迁移文件。Sanctum 的配置文件将会保存在 config 文件夹中:

php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"

运行数据库迁移。 Sanctum 将创建一个数据库表来存储 API 令牌:

php artisan migrate

将 Sanctum 的中间件添加到您应用的 app/Http/Kernel.php 文件中的 api 中间件组中:

'api' => [
    \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
    'throttle:api',
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
],

常用方法

发布令牌

发布令牌,您可以使用 createToken 方法。 createToken 方法返回一个 Laravel\Sanctum\NewAccessToken 实例。 在存入数据库之前,API 令牌已使用 SHA-256 哈希加密过,但您可以使用 NewAccessToken 实例的 plainTextToken 属性访问令牌的纯文本值。创建令牌后,您应该立即向用户显示此值:

use Illuminate\Http\Request;

Route::post('/tokens/create', function (Request $request) {
    $token = $request->user()->createToken($request->token_name);

    return ['token' => $token->plainTextToken];
});

比如在app登录时,控制器示例代码:

public function login(Request $request){
   $data = $request->validate([
     'phone' => 'required|numeric',
     'password' => 'required'
   ]);
   $user = User::where('phone', $request->phone)->first();
   if (!$user || !Hash::check($request->password, $user->password)) {
      return response(['message' => ['账号或密码错误']], 404);
   }
   $user['token'] = $user->createToken('MyApp')->plainTextToken;
   return response()->json(['code' => 200,'user' => $user,'msg' => '登录成功'], 200);
}

令牌能力

Sanctum 允许您将 「能力」分配给令牌。能力的用途与 OAuth 的「范围」类似。您可以将字符串能力数组作为第二个参数传递给 createToken 方法:

return $user->createTokn('token-name', ['server:update'])->plainTextToken;

在处理由 Sanctum 验证的传入请求时,您可以使用 tokenCan 方法确定令牌是否具有给定的能力:

if ($user->tokenCan('server:update')) {
    //
}

保护路由

为了保护路由,所有传入请求都必须经过身份验证,您应该将 sanctum 身份验证看守器附加到 routes/web.php 和 routes/api.php 中的受保护路由。 如果请求来自第三方,此看守器将确保传入请求被验证为有状态的 cookie 验证请求或包含有效的 API 令牌标头。
Sanctum 将首先尝试使用 Laravel 的典型 session 身份验证 cookie 对传入请求进行身份验证。 如果该 cookie 不存在,则 Sanctum 将尝试使用请求的 Authorization 标头中的令牌来验证请求。 此外,使用 Sanctum 对所有请求进行身份验证可确保我们始终可以在当前经过身份验证的用户实例上调用 tokenCan 方法:

use Illuminate\Http\Request;

Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
    return $request->user();
});

路由组使用:

Route::middleware('auth:sanctum')->group(function () {
    Route::post('cx/{id}', [ApiController::class, 'cxtj']);
});

撤销令牌

为了允许用户撤销发给移动设备的 API 令牌,您可以在 Web 应用程序 UI 的「帐户设置」部分中按名称列出它们,并附带 「撤销」按钮。 当用户点击「撤销」按钮时,您可以从数据库中删除令牌。 请记住,您可以通过 Laravel\Sanctum\HasApiTokens trait 提供的 tokens 关系访问用户的 API 令牌:

// 撤销所有令牌...
$user->tokens()->delete();

// 撤销特定令牌...
$user->tokens()->where('id', $tokenId)->delete();

安装前端组件

我们创建基于 Vue + Inertia 的现代 JavaScript 前端。

安装Inertia

composer require inertiajs/inertia-laravel

创建一个根模板app.blade.php,在resources/views/目录下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
        <link href="{{ mix('/css/app.css') }}" rel="stylesheet" />
        <script src="{{ mix('/js/app.js') }}" defer></script>
    </head>
    <body>
        @inertia
    </body>
</html>

发布中间件

php artisan inertia:middleware

生成后,在App\Http\Kernel中注册HandleInertiaRequests中间件作为web中间件组中的最后一个项目:

'web' => [
    // ...
    \App\Http\Middleware\HandleInertiaRequests::class,
],

此中间件提供了用于设置资产版本的version()方法,以及用于设置共享数据的share()方法。有关更多信息,请参阅这些页面。
创建一个响应:

use Inertia\Inertia;

class EventsController extends Controller
{
    public function show(Event $event)
    {
        return Inertia::render('Event/Show', [
            'event' => $event->only(
                'id',
                'title',
                'start_date',
                'description'
            ),
        ]);
    }
}

安装vue3和适配器

命令行安装,如果没有安装yarn和npm,请先安装

npm install vue@next
npm install @inertiajs/inertia @inertiajs/inertia-vue3
yarn add @inertiajs/inertia @inertiajs/inertia-vue3

修改resources/js/app.js文件内容为:

import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/inertia-vue3'

createInertiaApp({
  resolve: name => require(`./Pages/${name}`),
  setup({ el, App, props, plugin }) {
    createApp({ render: () => h(App, props) })
      .use(plugin)
      .mount(el)
  },
})

resolve回调告诉模板如何加载页面组件。它接收页面名称(字符串),并应返回页面组件模块。默认情况下,根模板要有一个id为app的根元素。如果不同,您可以使用id属性更改此属性。

createInertiaApp({
  id: 'my-app',
  // ...
})

安装Progress indicator,用于进度指示

npm install @inertiajs/progress
yarn add @inertiajs/progress

同样在app.js中启用:

import { InertiaProgress } from '@inertiajs/progress'

InertiaProgress.init()

最终变成:

require('./bootstrap')

import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/inertia-vue3'
import { InertiaProgress } from '@inertiajs/progress' // 如果需要进度指示器

InertiaProgress.init() // 如果需要进度指示器

createInertiaApp({
    resolve: name => require(`./Pages/${name}`),
    setup({ el, App, props, plugin }) {
        createApp({ render: () => h(App, props) })
            .use(plugin)
            .mount(el)
    },
})

安装 @vue/compiler-sfc 和 vue-loader

npm install @vue/compiler-sfc vue-loader@^16.2.0 --save-dev --legacy-peer-deps

修改 webpack.mix.js,添加 vue() 方法
mix.js('resources/js/app.js', 'public/js').vue()
    .postCss('resources/css/app.css', 'public/css', [
        //
    ]);

创建控制器

php artisan make:controller HomeController

内容如下:

namespace App\Http\Controllers;

use Inertia\Inertia;

class HomeController extends Controller
{
    public function index()
    {
        return Inertia::render('Home');
    }
}

创建页面

新增页面 resources/js/Pages/Home.vue

<template>
    <div>hello world</div>
</template>

<script>
export default {
    name: 'Home'
}
</script>

设置路由

use App\Http\Controllers\HomeController;

Route::get('/', [HomeController::class, 'index']);

执行编译

npm install
npm run dev

编译成功后,访问首页,经典的 “hello world” 可以正确地显示在浏览器上了。

安装Element

vue3的UI框架我们选择了较成熟的Element,下面两种方式都可以安装:

# NPM
$ npm install element-plus --save

# Yarn
$ yarn add element-plus

编辑app.js文件,引入组件