Laravel教程:使用Laravel Sanctum 作为 API 认证来构建 Vue.js 应用
source link: https://zhuanlan.zhihu.com/p/130226534
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Laravel教程:使用Laravel Sanctum 作为 API 认证来构建 Vue.js 应用
原文链接:https://learnku.com/laravel/t/43077
讨论请前往专业的 Laravel 开发者论坛:https://learnku.com/Laravel
身份验证系统是大多数现代应用程序的重要组成部分,因此应适当实施。
在本文中,您将学习到如何使用 Vue.js 和 Laravel Sanctum (以前的 Airlock )构建身份验证系统。
我们会创建一个前后端分离的项目,前后端将通过 REST API
相互交互。
让我开始吧!
后端 (Laravel)
有关 Laravel 安装说明,请移步 官方文档 。
在终端中创建一个新的 Laravel 项目
laravel new my-app
composer create-project --prefer-dist laravel/laravel my-app
我正在使用 Laravel Valet,它会自动将应用创建在 http://my-app.test
域名下。
你可以根据你本地的开发环境来配置并访问它。
创建一个名为 my-app
的数据库,并在 .env
文件中设置数据库连接,DB_DATABASE=my-app
。
安装 Laravel Sanctum
composer require laravel/sanctum
使用 vendor:publish
命令发布 Sanctum 配置文件和数据库迁移文件。sanctum
配置文件会创建在 config
目录中。
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
运行数据库迁移,以创建用于存储API令牌的数据库表:
php artisan migrate
将 Sanctum 中间件添加到 app/Http/Kernel.php 中的 api
中间件组中
../app/Http/Kernel.php
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;
...
protected $middlewareGroups = [
...
'api' => [
EnsureFrontendRequestsAreStateful::class,
'throttle:60,1',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
...
],
要为用户使用令牌,我们必须在 app/User.php 的 User
模型中添加 HasApiTokens
。
../app/User.php
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
}
第5步 #5
让我们为 User
模型创建一个 Seeder。我们稍后会需要它来测试登录过程。
php artisan make:seeder UsersTableSeeder
现在,让我们在database/seeds/UsersTableSeeder.php 的 run()
方法中,插入以下代码:
DB::table('users')->insert([
'name' => 'John Doe',
'email' => '[email protected]',
'password' => Hash::make('password')
]);
给 users
表生成 user, 让我们运行:
php artisan db:seed --class=UsersTableSeeder
现在我们的数据库里有一个新用户叫 "John Doe",邮箱是 "[email protected]",密码是 "password"。
第6步 #6
让我们在routes/api.php文件中创建一个/login
路由:
../routes/api.php
use App\User;
use Illuminate\Support\Facades\Hash;
Route::post('/login', function (Request $request) {
$data = $request->validate([
'email' => 'required|email',
'password' => 'required'
]);
$user = User::where('email', $request->email)->first();
if (!$user || !Hash::check($request->password, $user->password)) {
return response([
'message' => ['These credentials do not match our records.']
], 404);
}
$token = $user->createToken('my-app-token')->plainTextToken;
$response = [
'user' => $user,
'token' => $token
];
return response($response, 201);
});
第7步 #7
让我们发送一个以邮件[email protected]
和密码password
为参数的POST请求到http://my-app.test/api/login
路由。你可以使用Postman或Insomnia软件包来完成。
如果一切顺利,我们会收到一个JSON对象作为对我们请求的响应:
{
"user": {
"id": 1,
"name": "John Doe",
"email": "[email protected]",
"email_verified_at": null,
"created_at": null,
"updated_at": null
},
"token": "AbQzDgXa..."
}
第8步 #8
接下来,我们需要改变一些中间件。我们在/routes/api.php文件中把auth:api
替换成auth:sanctum
:
../routes/api.php
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
第9步 #9
在我们开发前端之前,我们必须先设置跨源请求CORS处理。
../config/cors.php
'paths' => ['api/*', 'login', 'logout'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
../.env
SANCTUM_STATEFUL_DOMAINS=127.0.0.1
前端 (Vue.js)
我们将使用 Vuex来进行状态管理, 用Vue Router 进行路由以及 axios 来进行HTTP请求
我们将使用 Vue CLI 来创建一个新的Vue项目。 如果你不熟悉这个标准的Vue.js开发工具,请阅读这个 指南.
在我们项目的目录中,让我们运行以下命令
vue create my-vue-app
选择 Manually select features
,然后选择Router
和 Vuex
在成功创建了my-vue-app
项目后,运行以下命令:
cd my-vue-app
npm run serve
现在我们的应用程序应该可以在http://localhost:8080/
域名中被访问。
让我们创建一个新的Login
视图文件
..src/views/Login.vue
<template>
<div>
<h1>Login</h1>
<form @submit.prevent="login">
<input type="email" name="email" v-model="email">
<input type="password" name="password" v-model="password">
<button type="submit">Login</button>
</form>
</div>
</template>
<script>
export default {
data () {
return {
email: '',
password: ''
}
},
methods: {
login () {
this.$store
.dispatch('login', {
email: this.email,
password: this.password
})
.then(() => {
this.$router.push({ name: 'About' })
})
.catch(err => {
console.log(err)
})
}
}
}
</script>
在 "Vue Router "中,我们必须为 "Login "视图实现一个路由。
../src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// 路由级别代码分割
// 这会为这个路由生成一个单独的块(about.[hash].js)。
// 当路由被访问的时候进行懒加载.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
},
{
path: '/login',
name: 'Login',
component: () => import(/* webpackChunkName: "login" */ '../views/Login.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
现在,如果我们在浏览器中导航到http://localhost:8080/login
,我们可以看到一个登录页面。
我们必须在前端目录下安装axios来进行HTTP请求:
npm install axios
让我们在Vuex中实现一些用户认证操作(login/logout)
。
../src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
Vue.use(Vuex)
axios.defaults.baseURL = 'http://app-backend.test/api'
export default new Vuex.Store({
state: {
user: null
},
mutations: {
setUserData (state, userData) {
state.user = userData
localStorage.setItem('user', JSON.stringify(userData))
axios.defaults.headers.common.Authorization = `Bearer ${userData.token}`
},
clearUserData () {
localStorage.removeItem('user')
location.reload()
}
},
actions: {
login ({ commit }, credentials) {
return axios
.post('/login', credentials)
.then(({ data }) => {
commit('setUserData', data)
})
},
logout ({ commit }) {
commit('clearUserData')
}
},
getters : {
isLogged: state => !!state.user
}
})
登录成功后,我们要在user
变量和localStorage
中存储一些用户数据。
让我们来定义已认证和未认证页面的路由。
我们可以让 About
页面只对认证过的用户开放。
为了这个目的,让我们把 meta
字段添加到 About
路径中。
让我们使用Vue Router的beforeEach
方法来检查用户是否登录。如果用户没有通过认证,我们将把他们重定向回登录页面。
../src/router.index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
meta: {
auth: true
},
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
},
{
path: '/login',
name: 'Login',
component: () => import(/* webpackChunkName: "login" */ '../views/Login.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
router.beforeEach((to, from, next) => {
const loggedIn = localStorage.getItem('user')
if (to.matched.some(record => record.meta.auth) && !loggedIn) {
next('/login')
return
}
next()
})
export default router
如果用户刷新了一个页面怎么办?要不要让他重新登录?
当然不是!
让我们在 Vue
实例中添加一个 created()
方法来处理这种情况。
created () {
const userInfo = localStorage.getItem('user')
if (userInfo) {
const userData = JSON.parse(userInfo)
this.$store.commit('setUserData', userData)
}
}
我们还需要处理令牌过期或用户未授权的情况。
让我们在created()
方法中通过使用拦截器来实现。
然后我们修改后的 main.js
文件看起来是这样的:
../src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
router,
store,
created () {
const userInfo = localStorage.getItem('user')
if (userInfo) {
const userData = JSON.parse(userInfo)
this.$store.commit('setUserData', userData)
}
axios.interceptors.response.use(
response => response,
error => {
if (error.response.status === 401) {
this.$store.dispatch('logout')
}
return Promise.reject(error)
}
)
},
render: h => h(App)
}).$mount('#app')
我们还没有实现 Logout
功能。让我们在 App.vue
文件中实现这个功能。
另外,让我们只在用户登录时显示About
和 Logout
按钮。
../src/App.vue
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about" v-if="isLogged">About</router-link>
<router-link to="/login" v-else>Login</router-link>
<button type="button" @click="logout()" v-if="isLogged">
Logout
</button>
</div>
<router-view/>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters([
'isLogged'
])
},
methods: {
logout () {
this.$store.dispatch('logout')
}
}
}
</script>
好了,我们的教程结束了。
希望这些信息对你有所帮助!
原文链接:https://learnku.com/laravel/t/43077
讨论请前往专业的 Laravel 开发者论坛:https://learnku.com/Laravel
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK