结合 Laravel 5.5 和 Vue SPA 基于 jwt-auth 实现 API 认证(含Vue.js安装)

https://xueyuanjun.com/post/9178.html

上一篇我们简单演示了 Laravel 5.5 中 RESTful API 的构建、认证和测试,本教程将在上一篇教程的基础上进行升华,我们将结合 Laravel 和 Vue 单页面应用(SPA),在此双剑合壁的基础上引入 jwt-auth 实现 API 认证,由于 Laravel 集成了对 Vue 的支持,所以在 Laravel 应用中使用 Vue 也是如鱼得水,非常顺畅,整篇教程涉及到的工具包括:

  • Node.js
  • Laravel 5.5
  • jwt-auth
  • NPM
  • Vue.js 2.x
  • Vue-router
  • Vue-axios
  • @websanova/vue-auth

初始化前端

我们将会在上一篇创建应用的基础上进行开发。

首先在项目根目录下运行以下命令安装前端依赖:

 

 

1

npm install

然后安装一些必要的 Vue 组件:

 

 

1

npm install --save-dev vue-axios vue-router vue-loader vue-template-compiler

接下来我们来创建应用所需的 Vue 模板和视图。

在 resources/assets/js 目录下新建 App.vue

 

 

1

<template>

2

    <div class="panel panel-default">

3

        <div class="panel-heading">

4

            <nav>

5

                <ul class="list-inline">

6

                    <li>

7

                        <router-link :to="{ name: 'home' }">首页</router-link>

8

                    </li>

9

                    <li class="pull-right">

10

                        <router-link :to="{ name: 'login' }">登录</router-link>

11

                    </li>

12

                    <li class="pull-right">

13

                        <router-link :to="{ name: 'register' }">注册</router-link>

14

                    </li>

15

                </ul>

16

            </nav>

17

        </div>

18

        <div class="panel-body">

19

            <router-view></router-view>

20

        </div>

21

    </div>

22

</template>

在 resources/assets/js/components 目录下新增 Home.vue

 

 

1

<template>

2

    <h1>Laravel 5 Vue SPA 认证</h1>

3

</template>

替换 resouces/assets/js/app.js 内容如下:

 

 

1

import Vue from 'vue';

2

import VueRouter from 'vue-router';

3

import App from './App.vue';

4

import Home from './components/Home.vue';

5

6

Vue.use(VueRouter);

7

8

const router = new VueRouter({

9

    routes: [

10

        {

11

            path: '/',

12

            name: 'home',

13

            component: Home

14

        },

15

    ]

16

});

17

18

new Vue({

19

        el: '#app',

20

        router: router,

21

        render: app => app(App)

22

});

替换 resources/views/welcome.blade.php 内容如下:

 

 

1

<!DOCTYPE html>

2

<html>

3

<head>

4

    <meta charset="utf-8">

5

    <meta name="csrf-token" content="{{ csrf_token() }}">

6

    <title>Laravel</title>

7

8

    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">

9

10

</head>

11

<body>

12

<div class="container">

13

    <div id="app"></div>

14

</div>

15

<script src="/js/app.js"></script>

16

</body>

17

</html>

最后在项目根目录下运行 npm run watch,就可以在浏览器中通过 http://apidemo.test 访问新首页了:

创建 Vue 组件

接下来我们来创建需要的 Vue 组件。

在 resources/assets/js/components 目录下新建 Register.vue

 

 

1

<template>

2

    <div>

3

        <div class="alert alert-danger" v-if="error && !success">

4

            <p>出错了,很遗憾,未能完成注册</p>

5

        </div>

6

        <div class="alert alert-success" v-if="success">

7

            <p>注册完成,你现在可以<router-link :to="{name:'login'}">登录</router-link>了</p>

8

        </div>

9

        <form autocomplete="off" @submit.prevent="register" v-if="!success" method="post">

10

            <div class="form-group" v-bind:class="{ 'has-error': error && errors.name }">

11

                <label for="name">用户名</label>

12

                <input type="text" id="name" class="form-control" v-model="name" required>

13

                <span class="help-block" v-if="error && errors.name">{{ errors.name }}</span>

14

            </div>

15

            <div class="form-group" v-bind:class="{ 'has-error': error && errors.email }">

16

                <label for="email">邮箱</label>

17

                <input type="email" id="email" class="form-control" placeholder="user@example.com" v-model="email" required>

18

                <span class="help-block" v-if="error && errors.email">{{ errors.email }}</span>

19

            </div>

20

            <div class="form-group" v-bind:class="{ 'has-error': error && errors.password }">

21

                <label for="password">密码</label>

22

                <input type="password" id="password" class="form-control" v-model="password" required>

23

                <span class="help-block" v-if="error && errors.password">{{ errors.password }}</span>

24

            </div>

25

            <button type="submit" class="btn btn-default">提交</button>

26

        </form>

27

    </div>

28

</template>

在同一目录下创建 Login.vue

 

 

1

<template>

2

    <div>

3

        <div class="alert alert-danger" v-if="error">

4

            <p>出错了,请检查邮箱/密码是否正确</p>

5

        </div>

6

        <form autocomplete="off" @submit.prevent="login" method="post">

7

            <div class="form-group">

8

                <label for="email">邮箱</label>

9

                <input type="email" id="email" class="form-control" placeholder="user@example.com" v-model="email" required>

10

            </div>

11

            <div class="form-group">

12

                <label for="password">密码</label>

13

                <input type="password" id="password" class="form-control" v-model="password" required>

14

            </div>

15

            <button type="submit" class="btn btn-default">登录</button>

16

        </form>

17

    </div>

18

</template>

最后在该目录下新建 Dashboard.vue

 

 

1

<template>

2

    <h1>Laravel 5 – 酷炫的后台</h1>

3

</template>

编辑 resources/assets/js/app.js 文件内容如下:

 

 

1

import Vue from 'vue';

2

import VueRouter from 'vue-router';

3

import axios from 'axios';

4

import VueAxios from 'vue-axios';

5

import App from './App.vue';

6

import Dashboard from './components/Dashboard.vue';

7

import Home from './components/Home.vue';

8

import Register from './components/Register.vue';

9

import Login from './components/Login.vue';

10

Vue.use(VueRouter);

11

Vue.use(VueAxios, axios);

12

axios.defaults.baseURL = 'http://apidemo.test/api';

13

const router = new VueRouter({

14

    routes: [{

15

        path: '/',

16

        name: 'home',

17

        component: Home

18

    },{

19

        path: '/register',

20

        name: 'register',

21

        component: Register

22

    },{

23

        path: '/login',

24

        name: 'login',

25

        component: Login

26

    }]

27

});

@websanova/vue-auth

@websanova/vue-auth 是客户端负责处理认证的库,它会注入一个 $auth 对象来提供很多有用的函数:比如 register() 来处理用户注册,login() 来处理用户登录,user() 来访问当前登录用户数据,logout() 来处理退出操作等等。

首先安装这个库:

 

 

1

npm install @websanova/vue-auth

再次编辑 resources/assets/js/app.js

 

 

1

import Vue from 'vue';

2

import VueRouter from 'vue-router';

3

import axios from 'axios';

4

import VueAxios from 'vue-axios';

5

import App from './App.vue';

6

import Dashboard from './components/Dashboard.vue';

7

import Home from './components/Home.vue';

8

import Register from './components/Register.vue';

9

import Login from './components/Login.vue';

10

Vue.use(VueRouter);

11

Vue.use(VueAxios, axios);

12

axios.defaults.baseURL = 'http://apidemo.test/api';

13

const router = new VueRouter({

14

    routes: [{

15

        path: '/',

16

        name: 'home',

17

        component: Home

18

    },{

19

        path: '/register',

20

        name: 'register',

21

        component: Register,

22

        meta: {

23

            auth: false

24

        }

25

    },{

26

        path: '/login',

27

        name: 'login',

28

        component: Login,

29

        meta: {

30

            auth: false

31

        }

32

    },{

33

        path: '/dashboard',

34

        name: 'dashboard',

35

        component: Dashboard,

36

        meta: {

37

            auth: true

38

        }

39

    }]

40

});

41

Vue.router = router

42

Vue.use(require('@websanova/vue-auth'), {

43

   auth: require('@websanova/vue-auth/drivers/auth/bearer.js'),

44

   http: require('@websanova/vue-auth/drivers/http/axios.1.x.js'),

45

   router: require('@websanova/vue-auth/drivers/router/vue-router.2.x.js'),

46

});

47

App.router = Vue.router

48

new Vue(App).$mount('#app');

在新增的代码中,我们首先引入刚刚安装的库并且做了一些配置:

使用 bearer 在请求期间添加认证 token 到请求头,以便服务端读取解析这个 token:

 

 

1

auth: require(‘@websanova/vue-auth/drivers/auth/bearer.js’)

配置 vue-auth 使用 axios 来发送 HTTP 请求:

 

 

1

http: require(‘@websanova/vue-auth/drivers/http/axios.1.x.js’)

我们还配置 vue-auth 使用 vue-router:

 

 

1

router: require(‘@websanova/vue-auth/drivers/router/vue-router.2.x.js’)

最后,注意到:

 

 

1

meta: {

2

    auth: true

3

}

这个配置,该配置用于指定访问路由是否需要认证。

想要了解更多可以访问 @websanova/vue-auth Github 仓库。

现在运行 npm run watch,再访问后台 http://apidemo.test/#/dashboard,就会跳转到登录页面:

jwt-auth

本教程中我们将使用 jwt-auth 来实现 API 认证,所以接下来安装这个扩展包:

 

 

1

composer require tymon/jwt-auth

安装完成后在配置文件 config/app.php 中注册服务提供者和别名:

 

 

1

...

2

'providers' => [

3

    ...

4

    Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class,

5

]

6

...

7

'aliases' => [

8

    ...

9

    'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,

10

]

发布资源和配置:

 

 

1

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\JWTAuthServiceProvider"

在发布的配置中生成key:

 

 

1

php artisan jwt:generate

如果上述命令执行报错,可以通过这个链接解决。

编辑 app/Http/Kernel.php 添加 jwt.auth 和 jwt.refresh 到应用路由中间件数组:

 

 

1

protected $routeMiddleware = [

2

    ...

3

    'jwt.auth' => \Tymon\JWTAuth\Middleware\GetUserFromToken::class,

4

    'jwt.refresh' => \Tymon\JWTAuth\Middleware\RefreshToken::class,

5

];

完成以上操作接下来就行注册路由,创建控制器,进行 API 功能验证了。

注册接口实现

现在 routes/api.php 中注册路由:

 

 

1

Route::post('auth/register', 'AuthController@register');

创建认证所需控制器:

 

 

1

php artisan make:controller AuthController

我们再创建一个 FormRequest 来处理注册请求验证:

 

 

1

php artisan make:request RegisterFormRequest

首先编写 FormRequest 处理类的验证规则代码:

 

 

1

class RegisterFormRequest extends FormRequest

2

{

3

    public function authorize()

4

    {

5

         return true;

6

    }

7

    public function rules()

8

    {

9

        return [

10

            'name' => 'required|string|unique:users',

11

            'email' => 'required|email|unique:users',

12

            'password' => 'required|string|min:6|max:10',

13

        ];

14

    }

15

}

接下来在控制器 AuthController 中创建一个 register 方法:

 

 

1

public function register(RegisterFormRequest $request)

2

{

3

    $user = new User;

4

    $user->email = $request->email;

5

    $user->name = $request->name;

6

    $user->password = bcrypt($request->password);

7

    $user->save();

8

    return response([

9

        'status' => 'success',

10

        'data' => $user

11

       ], 200);

12

 }
学院君友情提醒:直接拷贝代码的同学注意在代码中引入相应类的命名空间,不要报错了又来数落文档不负责,学院君很无辜,文档更无辜?。

最后在 Register.vue 文件最后添加如下代码:

 

 

1

<script> 

2

    export default {

3

        data(){

4

            return {

5

                name: '',

6

                email: '',

7

                password: '',

8

                error: false,

9

                errors: {},

10

                success: false

11

            };

12

        },

13

        methods: {

14

            register(){

15

                var app = this

16

                this.$auth.register({

17

                    params: {

18

                        name: app.name,

19

                        email: app.email,

20

                        password: app.password

21

                    }, 

22

                    success: function () {

23

                        app.success = true

24

                    },

25

                    error: function (resp) {

26

                        app.error = true;

27

                        app.errors = resp.response.data.errors;

28

                    },

29

                    redirect: null

30

                });                

31

            }

32

        }

33

    }

34

</script>

再次运行 npm run watch,然后在浏览器中通过 http://apidemo.test/#/register 访问注册页面进行注册:

如果注册失败,报错页面如下:

注册成功则页面显示如下:

登录接口实现

回到 AuthController 添加 login() 方法:

 

 

1

public function login(Request $request)

2

{

3

    $credentials = $request->only('email', 'password');

4

    if ( ! $token = JWTAuth::attempt($credentials)) {

5

            return response([

6

                'status' => 'error',

7

                'error' => 'invalid.credentials',

8

                'msg' => 'Invalid Credentials.'

9

            ], 400);

10

    }

11

    return response(['status' => 'success'])

12

        ->header('Authorization', $token);

13

}

此外我们继续添加 user() 和 refresh() 方法到该控制器:

 

 

1

public function user(Request $request)

2

{

3

    $user = User::find(Auth::user()->id);

4

    return response([

5

            'status' => 'success',

6

            'data' => $user

7

        ]);

8

}

9

public function refresh()

10

{

11

    return response([

12

            'status' => 'success'

13

        ]);

14

}

其中 user() 方法用于获取当前登录用户数据,而 refresh() 方法用于检查当前登录用户 token 是否仍然有效。

当然,不要忘了给上面新增的控制器方法注册路由:

 

 

1

Route::post('auth/login', 'AuthController@login');

2

Route::group(['middleware' => 'jwt.auth'], function(){

3

  Route::get('auth/user', 'AuthController@user');

4

});

5

Route::group(['middleware' => 'jwt.refresh'], function(){

6

  Route::get('auth/refresh', 'AuthController@refresh');

7

});

最后将以下代码添加到 Login.vue 最后:

 

 

1

<script>

2

  export default {

3

    data(){

4

      return {

5

        email: null,

6

        password: null,

7

        error: false

8

      }

9

    },

10

    methods: {

11

      login(){

12

        var app = this

13

        this.$auth.login({

14

            params: {

15

              email: app.email,

16

              password: app.password

17

            }, 

18

            success: function () {},

19

            error: function () {},

20

            rememberMe: true,

21

            redirect: '/dashboard',

22

            fetchUser: true,

23

        });       

24

      },

25

    }

26

  } 

27

</script>

运行 npm run watch, 进入登录页面 http://apidemo.test/#/login 输入之前注册用户信息进行登录:

登录成功后页面跳转到后台 http://apidemo.test/#/dashboard

退出接口实现

最后,我们添加 logout() 方法到控制器 AuthController

 

 

1

public function logout()

2

{

3

    JWTAuth::invalidate();

4

    return response([

5

        'status' => 'success',

6

        'msg' => 'Logged out Successfully.'

7

    ], 200);

8

}

该方法会确保用户从后台退出,从而使 token 失效,进而从客户端清除。

在 routes/api.php 注册对应路由:

 

 

1

Route::group(['middleware' => 'jwt.auth'], function(){

2

   ...

3

   Route::post('auth/logout', 'AuthController@logout');

4

});

然后编辑 App.vue 文件:

 

 

1

<template>

2

    <div class="panel panel-default">

3

        <div class="panel-heading">

4

            <nav>

5

                <ul class="list-inline">

6

                    <li>

7

                        <router-link :to="{ name: 'home' }">首页</router-link>

8

                    </li>

9

                    <li v-if="!$auth.check()" class="pull-right">

10

                        <router-link :to="{ name: 'login' }">登录</router-link>

11

                    </li>

12

                    <li v-if="!$auth.check()" class="pull-right">

13

                        <router-link :to="{ name: 'register' }">注册</router-link>

14

                    </li>

15

                    <li v-if="$auth.check()" class="pull-right">

16

                        <a href="#" @click.prevent="$auth.logout()">退出</a>

17

                    </li>

18

                </ul>

19

            </nav>

20

        </div>

21

        <div class="panel-body">

22

            <router-view></router-view>

23

        </div>

24

    </div>

25

</template>

$auth.check() 用于检查用户是否登录,$auth.logout() 用于用户退出请求。

运行 npm run watch,刷新 http://apidemo.test/#/dashboard,页面显示如下:

点击「退出」按钮,用户退出,页面跳转到首页:

至此,我们已经集合 Laravel + Vue 基于 jwt-auth 实现了 API 基本认证功能。下一篇我们来讲讲如何将 Laravel 5.5 新增的 Eloquent API Resource 功能集成进来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值