Laravel 9 Sanctum, Bootstrap5, Vue 3 및 Vite를 사용하여 단일 페이지 애플리케이션에 대한 완전한 등록 및 로그인 기능을 만듭니다.
목차
- 1단계: Laravel 프로젝트 생성
- 2단계: 데이터베이스 세부 정보 구성
- 3단계: 설치 laravel/ui
- 4단계: Vue 3 설치
- 5단계: vitejs/plugin-vue 플러그인 설치
- 6단계: vite.config.js 파일 업데이트
- 7단계: vite.config.js에서 부트스트랩 경로 가져오기
- 8단계: NPM 종속성 설치
- 9단계: bootstrap.js 업데이트
- 10단계: JS 폴더에 Bootstrap 5 SCSS 가져오기
- 11단계: Vite Dev Server 시작
- 12단계: Laravel Sanctum 설치
- 13단계: Laravel Sanctum 구성
- 14단계: 데이터베이스 마이그레이션
- 15단계: 프런트엔드 설정
1단계: Laravel 프로젝트 생성
먼저 터미널을 열고 다음 명령을 실행하여 새로운 Laravel 프로젝트를 만듭니다.
composer create-project --prefer-dist laravel/laravel:^9.0 lara9sanctum-vue3-vite
또는 Laravel 설치 프로그램을 글로벌 컴포저 종속성으로 설치한 경우:
laravel new lara9sanctum-vue3-vite
2단계: 데이터베이스 세부 정보 구성
.env 데이터베이스 세부정보 열기 및 업데이트
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=<DATABASE NAME>
DB_USERNAME=<DATABASE USERNAME>
DB_PASSWORD=<DATABASE PASSWORD>
3단계: 설치 laravel/ui
composer require laravel/ui
php artisan ui vue --auth
4단계: Vue 3 설치
이제 노드 모듈을 설치한 후 애플리케이션에 vue 3을 설치해야 합니다. 이를 위해서는 터미널 npm install vue@next vue-loader@next 에서 다음 명령을 실행하세요 . vue-loader는 단일 파일 구성 요소라는 형식으로 Vue 구성 요소를 작성할 수 있는 웹팩용 로더 입니다 . vue-loader@next는 웹팩이 SFC라는 단일 파일 구성 요소에서 Vue 구성 요소를 작성하기 위한 로더입니다.
npm install vue@next vue-loader@next
5단계: vitejs/plugin-vue 플러그인 설치
laravel 9 최신 릴리스에서는 laravel에 vue3 또는 vue를 설치하기 위해 vitejs/plugin-vue 플러그인을 설치합니다. 이 플러그인은 vite에서 vuejs 애플리케이션을 실행하는 데 필요한 종속성을 제공합니다. Vite는 코드를 Rollup과 함께 묶고 localhost:3000 포트를 실행하여 핫 새로 고침 기능을 제공하는 빌드 명령입니다.
npm i @vitejs/plugin-vue
6단계: vite.config.js 파일 업데이트
Vite는 최신 JavaScript 애플리케이션을 위한 모듈 번들러 입니다 . vite.config.js를 열고 다음 코드를 복사하여 붙여넣습니다. 파일 상단에 있는 vite에서 먼저 송장을 정의하고 laravel-vite-plugin도 가져옵니다. 여기에서 플러그인()은 js 및 CSS 파일의 경로를 취하고 애플리케이션에 대한 번들을 생성합니다. 플러그인 배열에 vue()를 추가해야 합니다.
// vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [
vue(),
laravel([
'resources/js/app.js',
]),
],
});
7단계: vite.config.js에서 부트스트랩 경로 가져오기
먼저 vite.config.js를 변경하고 부트스트랩 5 경로를 추가하고 resources/css/app.css를 제거해야 합니다.
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue'
import path from 'path'
export default defineConfig({
plugins: [
vue(),
laravel([
'resource/scss/app.scss',
'resources/js/app.js',
]),
],
resolve: {
alias: {
'~bootstrap': path.resolve(__dirname, 'node_modules/bootstrap'),
'@': '/resources/js',
}
},
});
8단계: NPM 종속성 설치
프런트엔드 종속 항목을 설치하려면 다음 명령어를 실행하세요.
npm install
9단계: bootstrap.js 업데이트
import 대신에 사용해야 합니다 require.
import loadash from 'lodash'
window._ = loadash
import * as Popper from '@popperjs/core'
window.Popper = Popper
import 'bootstrap'
/**
* We'll load the axios HTTP library which allows us to easily issue requests
* to our Laravel back-end. This library automatically handles sending the
* CSRF token as a header based on the value of the "XSRF" token cookie.
*/
import axios from 'axios'
window.axios = axios
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
/**
* Echo exposes an expressive API for subscribing to channels and listening
* for events that are broadcast by Laravel. Echo and event broadcasting
* allows your team to easily build robust real-time web applications.
*/
/*import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
forceTLS: true
});*/
10단계: JS 폴더에 Bootstrap 5 SCSS 가져오기
이제 resources/js/app.js 에서 부트스트랩 5 SCSS 경로를 가져와야 합니다.
리소스/js/app.js
import './bootstrap';
import '../sass/app.scss'
11단계: Vite Dev Server 시작
이제 vue 3을 설치한 후 다음 명령을 실행하기 위해 vite용 개발 서버를 시작해야 하며 resources/js/app.js 파일과 resources/css/app.css 파일을 감시합니다. 또한 http://localhost:3000에서 vite 서버를 시작합니다. vite hot reload용이므로 브라우저에서 열 수 없으며 백그라운드에서 실행되고 js 및 CSS와 같은 애플리케이션 자산을 감시합니다.
npm run dev
12단계: Laravel Sanctum 설치
공식 Laravel 웹사이트에서 문서를 찾을 수 있습니다.
composer require laravel/sanctum
13단계: Laravel Sanctum 구성
config/sanctum.php 다음 코드를 열고 업데이트하세요.
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'localhost,127.0.0.1')),
프로덕션에 배포할 때 이를 변경해야 하므로 허용된 도메인 목록을 쉼표로 구분하여 파일 SANCTUM_STATEFUL_DOMAINS 에 추가하는 .env 것이 좋습니다.
파일을 열고 .env 다음 줄을 추가하세요
SANCTUM_STATEFUL_DOMAINS=localhost:<PORT NUMBER>
세션 드라이버 변경
에서 .env세션 드라이버를 file 으로 업데이트합니다 cookie.
SESSION_DRIVER=cookie
CORS 구성
다음 코드를 열고 config/cors.php 파일에 업데이트합니다.
'paths' => [
'api/*',
'/login',
'/logout',
'/sanctum/csrf-cookie'
],
또한 supports_credentials 옵션을 다음으로 설정하십시오 true.
'supports_credentials' => true,
로그인 양식을 보관하고 일부 비밀을 표시하는 Vue 구성 요소를 만들어 보겠습니다.
14단계: 데이터베이스 마이그레이션
php artisan migrate
15단계: 프런트엔드 설정
이전에 php artisan ui vue를 사용하여 프런트엔드 코드를 생성했을 때 예제 구성 요소가 resources/js/components/ExampleComponent.vue. 로그인, 등록 및 대시보드 페이지에 대한 다른 구성 요소를 만들어 보겠습니다.
Vue 라우터란 무엇인가요?
Vue Router는 브라우저의 URL/기록과 Vue의 구성 요소 간의 연결을 도와 특정 경로가 연관된 모든 뷰를 렌더링할 수 있도록 합니다.
Vue 라우터의 특징
- 중첩 경로
- 경로 매개변수, 쿼리
- 동적 경로 일치
- 자동 활성 CSS 클래스와의 링크
- 그리고 더 많은
설치하자 vue-router
npm install vue-router
이제 로그인 및 등록을 위한 구성 요소를 생성합니다.
Login.vue 를 사용하여 resources/js/comComponents 폴더 이름 안에 파일을 만듭니다 .
resources/js/components/Login.vue
<template>
<div class="container h-100">
<div class="row h-100 align-items-center">
<div class="col-12 col-md-6 offset-md-3">
<div class="card shadow sm">
<div class="card-body">
<h1 class="text-center">Login</h1>
<hr/>
<form action="javascript:void(0)" class="row" method="post">
<div class="col-12" v-if="Object.keys(validationErrors).length > 0">
<div class="alert alert-danger">
<ul class="mb-0">
<li v-for="(value, key) in validationErrors" :key="key">{{ value[0] }}</li>
</ul>
</div>
</div>
<div class="form-group col-12">
<label for="email" class="font-weight-bold">Email</label>
<input type="text" v-model="auth.email" name="email" id="email" class="form-control">
</div>
<div class="form-group col-12 my-2">
<label for="password" class="font-weight-bold">Password</label>
<input type="password" v-model="auth.password" name="password" id="password" class="form-control">
</div>
<div class="col-12 mb-2">
<button type="submit" :disabled="processing" @click="login" class="btn btn-primary btn-block">
{{ processing ? "Please wait" : "Login" }}
</button>
</div>
<div class="col-12 text-center">
<label>Don't have an account? <router-link :to="{name:'register'}">Register Now!</router-link></label>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
name:"login",
data(){
return {
auth:{
email:"",
password:""
},
validationErrors:{},
processing:false
}
},
methods:{
...mapActions({
signIn:'auth/login'
}),
async login(){
this.processing = true
await axios.get('/sanctum/csrf-cookie')
await axios.post('/login',this.auth).then(({data})=>{
this.signIn()
}).catch(({response})=>{
if(response.status===422){
this.validationErrors = response.data.errors
}else{
this.validationErrors = {}
alert(response.data.message)
}
}).finally(()=>{
this.processing = false
})
},
}
}
</script>
Register.vue를 사용하여 resources/js/comComponents 폴더 이름 안에 파일을 생성하세요 .
<template>
<div class="container h-100">
<div class="row h-100 align-items-center">
<div class="col-12 col-md-6 offset-md-3">
<div class="card shadow sm">
<div class="card-body">
<h1 class="text-center">Register</h1>
<hr/>
<form action="javascript:void(0)" @submit="register" class="row" method="post">
<div class="col-12" v-if="Object.keys(validationErrors).length > 0">
<div class="alert alert-danger">
<ul class="mb-0">
<li v-for="(value, key) in validationErrors" :key="key">{{ value[0] }}</li>
</ul>
</div>
</div>
<div class="form-group col-12">
<label for="name" class="font-weight-bold">Name</label>
<input type="text" name="name" v-model="user.name" id="name" placeholder="Enter name" class="form-control">
</div>
<div class="form-group col-12 my-2">
<label for="email" class="font-weight-bold">Email</label>
<input type="text" name="email" v-model="user.email" id="email" placeholder="Enter Email" class="form-control">
</div>
<div class="form-group col-12">
<label for="password" class="font-weight-bold">Password</label>
<input type="password" name="password" v-model="user.password" id="password" placeholder="Enter Password" class="form-control">
</div>
<div class="form-group col-12 my-2">
<label for="password_confirmation" class="font-weight-bold">Confirm Password</label>
<input type="password_confirmation" name="password_confirmation" v-model="user.password_confirmation" id="password_confirmation" placeholder="Enter Password" class="form-control">
</div>
<div class="col-12 mb-2">
<button type="submit" :disabled="processing" class="btn btn-primary btn-block">
{{ processing ? "Please wait" : "Register" }}
</button>
</div>
<div class="col-12 text-center">
<label>Already have an account? <router-link :to="{name:'login'}">Login Now!</router-link></label>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
name:'register',
data(){
return {
user:{
name:"",
email:"",
password:"",
password_confirmation:""
},
validationErrors:{},
processing:false
}
},
methods:{
...mapActions({
signIn:'auth/login'
}),
async register(){
this.processing = true
await axios.get('/sanctum/csrf-cookie')
await axios.post('/register',this.user).then(response=>{
this.validationErrors = {}
this.signIn()
}).catch(({response})=>{
if(response.status===422){
this.validationErrors = response.data.errors
}else{
this.validationErrors = {}
alert(response.data.message)
}
}).finally(()=>{
this.processing = false
})
}
}
}
</script>
인증된 모든 페이지에 대한 레이아웃 구성 요소를 만듭니다. 따라서 모든 페이지 구성 요소에 머리글, 바닥글 및 기타 구성 요소를 추가할 필요가 없으므로 여기에서는 Dashboard.vue라는 레이아웃 구성 요소를 만들었습니다. 여기 구성 요소에 머리글, 바닥글 및 라우터 보기를 추가하여 모든 구성 요소가 이 라우터 보기에서 렌더링되도록 합니다.
resources/js/components/layouts/Default.vue
import {mapActions} from 'vuex'
export default {
name:"default-layout",
data(){
return {
user:this.$store.state.auth.user
}
},
methods:{
...mapActions({
signOut:"auth/logout"
}),
async logout(){
await axios.post('/logout').then(({data})=>{
this.signOut()
this.$router.push({name:"login"})
})
}
}
}
resources/js/components/Dashboard.vue
<template>
<div class="container">
<div class="row">
<div class="col-12">
<div class="card shadow-sm">
<div class="card-header">
<h3>Dashboard</h3>
</div>
<div class="card-body">
<p class="mb-0">You are logged in as <b>{{user.email}}</b></p>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name:"dashboard",
data(){
return {
user:this.$store.state.auth.user
}
}
}
</script>
이제 이 페이지 구성 요소를 라우터에 추가하세요.
새 파일 만들기 resources/js/router/index.js
import { createWebHistory, createRouter } from 'vue-router'
import store from '@/store'
/* Guest Component */
const Login = () => import('@/components/Login.vue')
const Register = () => import('@/components/Register.vue')
/* Guest Component */
/* Layouts */
const DahboardLayout = () => import('@/components/layouts/Default.vue')
/* Layouts */
/* Authenticated Component */
const Dashboard = () => import('@/components/Dashboard.vue')
/* Authenticated Component */
const routes = [
{
name: "login",
path: "/login",
component: Login,
meta: {
middleware: "guest",
title: `Login`
}
},
{
name: "register",
path: "/register",
component: Register,
meta: {
middleware: "guest",
title: `Register`
}
},
{
path: "/",
component: DahboardLayout,
meta: {
middleware: "auth"
},
children: [
{
name: "dashboard",
path: '/',
component: Dashboard,
meta: {
title: `Dashboard`
}
}
]
}
]
const router = createRouter({
history: createWebHistory(),
routes, // short for `routes: routes`
})
router.beforeEach((to, from, next) => {
document.title = to.meta.title
if (to.meta.middleware == "guest") {
if (store.state.auth.authenticated) {
next({ name: "dashboard" })
}
next()
} else {
if (store.state.auth.authenticated) {
next()
} else {
next({ name: "login" })
}
}
})
export default router
라우터 추가 resources/js/app.js
import './bootstrap';
import '../sass/app.scss'
import Router from '@/router'
import { createApp } from 'vue/dist/vue.esm-bundler';
const app = createApp({})
app.use(Router)
app.mount('#app')
이러한 요청을 하기 전에 API에 대한 기본 URL을 설정하고(이러한 내용은 현재 요청에 포함되어 있지 않음) 옵션을 활성화해야 합니다 withCredentials .
해당 파일을 열고 resources/js/bootstrap.js다음 코드를 추가합니다.
window.axios.defaults.withCredentials = true
여기서 an withCredentials 옵션은 정말 중요합니다. 이 Axios는 모든 요청과 함께 인증 쿠키를 자동으로 보내도록 지시합니다.
Vuex란 무엇인가요?
Vuex 는 Vue용 상태 관리 패턴 + 라이브러리입니다. js 애플리케이션. 상태가 예측 가능한 방식으로만 변경될 수 있도록 보장하는 규칙을 사용하여 애플리케이션의 모든 구성 요소에 대한 중앙 집중식 저장소 역할을 합니다.
글쎄요, 우리는 클라이언트에서 전체적으로 인증된 '상태'를 유지하고 싶기 때문에 여기서는 Vuex와 같은 상태 관리 라이브러리를 사용하는 것이 합리적입니다. 또한 인증 여부(예: 탐색)를 구성 요소 내에서 쉽게 확인할 수 있습니다.
설치하자 Vuex
npm install vuex --save
먼저 resources/js/store/auth.js 다음을 사용하여 파일을 만듭니다.
import axios from 'axios'
import router from '@/router'
export default {
namespaced: true,
state:{
authenticated:false,
user:{}
},
getters:{
authenticated(state){
return state.authenticated
},
user(state){
return state.user
}
},
mutations:{
SET_AUTHENTICATED (state, value) {
state.authenticated = value
},
SET_USER (state, value) {
state.user = value
}
},
actions:{
login({commit}){
return axios.get('/api/user').then(({data})=>{
commit('SET_USER',data)
commit('SET_AUTHENTICATED',true)
router.push({name:'dashboard'})
}).catch(({response:{data}})=>{
commit('SET_USER',{})
commit('SET_AUTHENTICATED',false)
})
},
logout({commit}){
commit('SET_USER',{})
commit('SET_AUTHENTICATED',false)
}
}
}
속성 state 에는 인증 여부가 포함되며, 인증되면 가져올 사용자 세부 정보가 포함됩니다.
우리는 getters 그 상태로 돌아왔습니다.
우리 mutations 의 업데이트는 state. 예를 들어, 성공적으로 인증되면 인증됨을 설정하기 위한 변형을 커밋 true 하고 사용자 세부 정보를 설정하기 위한 또 다른 변형을 커밋합니다.
때로는 브라우저 로컬 저장소에 일부 정보를 유지하기 위해 VueJS 웹 앱이 필요합니다. 로컬 설정, 계정 정보 또는 일부 토큰일 수 있습니다. 페이지가 새로 고쳐지면 우리는 그것들을 잃고 싶지 않습니다. 이것이 우리가 vuex-persistedstate를 사용해야 하는 이유입니다 .
설치하다 vuex-persistedstate
npm i vuex-persistedstate
이제 NET Framework의 Vuex에 인증 모듈을 추가하세요 resources/js/store/index.js.
import { createStore } from 'vuex'
import createPersistedState from 'vuex-persistedstate'
import auth from '@/store/auth'
const store = createStore({
plugins:[
createPersistedState()
],
modules:{
auth
}
})
export default store
Vuex 추가 resources/js/app.js
import './bootstrap';
import '../sass/app.scss'
import Router from '@/router'
import store from '@/store'
import { createApp } from 'vue/dist/vue.esm-bundler';
const app = createApp({})
app.use(Router)
app.use(store)
app.mount('#app')
resources/views/welcome.blade.php를 열고 다음 코드를 교체하세요:
@vite(['resources/js/app.js'])
이제 web.php 및 api.php 경로 파일에 경로를 정의하십시오. 경로 폴더 로 이동하여 web.php 파일을 열고 다음 경로를 업데이트합니다.
경로 / web.php
<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('{any}', function () {
return view('welcome');
})->where('any', '.*');
Auth::routes();
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
이제 프로젝트를 실행할 시간입니다.
php artisan serve
브라우저에서 localhost:<PORT NUMBER>를 엽니다 .
출처 : https://morioh.com/a/538596e08ccf/laravel-9-sanctum-vue-3-vite-spa
'vue' 카테고리의 다른 글
vue3 vite 공통레이아웃 라우터 분기 처리 (0) | 2024.03.26 |
---|