I. Vue.js인증권한
1. pinia
(1) 필요성
1)
store에 있는 전역객체는 말그대로 전역적으로 있지만 리액티브한것을 쓰기 위해서 피니아를 쓴다.
2)
피이나 설치는
- npm install pinia
를 한다.
(2) 파일세팅
1) 파일명변경
폴더명을 stores 로 바꾸고 useUserDtailsStore.js 만들기
2)useUserDtailsStore.js
import { defineStore } from "pinia";
export default useUserDetailsStore = defineStore("userDetails",{
});
3)
import { createApp } from 'vue'
import { createRouter, createWebHashHistory } from 'vue-router'
import { createPinia } from 'pinia'
const pinia = createPinia();
// Vue.createApp이 글로벌 라이브러리이다.
createApp(App)
.use(router)
.use(pinia)
.mount('#app') // -> ES6 라이브러리이다.
여기 옵션즈에다가 무엇을 넣어주어야해
(3) state
기존(SSR)에는 session이나 Cookie를 사용했지만, 피니아를 이용하면 해결이 가능하다.
다른 구성요소와 데이터 공유가 가능해져
1) 세팅
import { defineStore } from "pinia";
export default useUserDetailsStore = defineStore("userDetails",{
state: () => ({
id : 0,
username : null,
email : null,
role : null
}),
});
이렇게 전역변수를 준비해준다.
2) 목적
그런데 header부분에 로그인 상태에 따라 보이는게 달라져야하는데,
이거를 reactive 하게 해야해
3) 헤더부분 로그인아이콘 세팅
<Header>
<script setup>
// import userDetails from '../../stores/UserDetails';
import { useUserDetailsStore } from '../../stores/useUserDetailsStore';
let userDetails = useUserDetailsStore();
</script>
<template>
<!-- ----------------------헤더---------------------------- -->
<header class="header-container">
<h1 class="d-none">알랜드</h1>
<div>
<router-link to="index" title="index페이지로 이동합니다.">
<img src="/image/logo.svg" />
</router-link>
<a class="icon icon-menu">메뉴</a>
</div>
<nav class="nav-wrap">
<h1 class="d-none">네비게이션 목록</h1>
<ul>
<li>
<router-link
to="index"
class="icon icon-home"
title="index페이지로 이동합니다."
>홈</router-link
>
</li>
<li>
<router-link v-if="userDetails.username == null "
to="/login"
class="icon icon-sign-on"
title="로그인">
</router-link>
<router-link v-if="userDetails.username != null "
to="/logout"
class="icon icon-sign-out"
title="로그아웃">
</router-link>
</li>
</ul>
</nav>
</header>
</template>
Header가 달라짐
(4) getters (for 로그아웃 기능)
1) 세팅
계산하거나 속성으로 사용을 한다
일단 getters를 세팅하자
<useUserDetailsStore.js>
import { defineStore } from "pinia";
// export default useUserDetailsStore = defineStore("userDetails",{
// state: () => ({
export const useUserDetailsStore = defineStore("userDetails", {
state: () => ({
id : 0,
username : null,
email : null,
role : null
}),
getters:{
isAuthenticated:(state)=>state.username == null? false:true
}
});
isAuthenticated 는 게산된 속성이다. boolean 형식으로 인증여부를 가릴 수있다.
그렇다면 <login.vue>를 보자
<script setup>
import { reactive } from 'vue';
import { useRouter} from 'vue-router';
// import userDetails from '../stores/UserDetails';
import { useUserDetailsStore } from '../stores/useUserDetailsStore';
// 전역객체 불러오기
let userDetails = useUserDetailsStore();
let router = useRouter();
//json 만들어주기
let user = reactive({
username : "",
password : "",
role : "",
});
async function loginHandler() {
console.log(user.username);
let response = await fetch("http://localhost:8090/members/login", {
method : "POST",
headers : {
"Accept" : "application/json",
"content-type":"application/x-www-form-urlencoded"
},
body:`username=${user.username}&password=${user.password}`
});
let json = await response.json();
console.log(json.result.email);
console.log(json);
//전영객체에다가 json 하니씩 담아주기
userDetails.username = json.result.userName;
// userDetails.password = json.result.pwd;
userDetails.email = json.result.email;
// console.log(userDetails);
router.push("/index");
}
로그인을 했을 때 index로 보내주는 것은 router를 import 하고 router.push() 를 해주면된다
2)
그렇다면 로그아웃의 경우 어떻게 해야할까?
<script setup>
// import userDetails from '../../stores/UserDetails';
import { useUserDetailsStore } from '../../stores/useUserDetailsStore';
import { useRouter} from 'vue-router';
let userDetails = useUserDetailsStore();
let router = useRouter();
function logoutHandler() {
console.log("logout test");
userDetails.id = 0;
userDetails.username = null;
userDetails.email = null;
router.push("/index");
}
</script>
<template>
<!-- ----------------------헤더---------------------------- -->
<header class="header-container">
<h1 class="d-none">알랜드</h1>
<div>
<router-link to="index" title="index페이지로 이동합니다.">
<img src="/image/logo.svg" />
</router-link>
<a class="icon icon-menu">메뉴</a>
</div>
<nav class="nav-wrap">
<h1 class="d-none">네비게이션 목록</h1>
<ul>
<li>
<router-link
to="index"
class="icon icon-home"
title="index페이지로 이동합니다."
>홈</router-link
>
</li>
<li>
<router-link v-if="!userDetails.isAuthenticated"
to="/login"
class="icon icon-sign-on"
title="로그인">
</router-link>
<router-link v-if="userDetails.isAuthenticated"
to="/logout"
class="icon icon-sign-out"
title="로그아웃"
@click.prvent ="logoutHandler"
>
</router-link>
</li>
</ul>
</nav>
</header>
</template>
v-if 를 isAuthenticated 로 해준다. 그리고 마찬가지로 router.push()를 해주면된다.
(5) actions을 이용하기
1)
<script setup>
// import userDetails from '../../stores/UserDetails';
import { useUserDetailsStore } from '../../stores/useUserDetailsStore';
import { useRouter} from 'vue-router';
let userDetails = useUserDetailsStore();
let router = useRouter();
function logoutHandler() {
console.log("logout test");
userDetails.logout();
router.push("/index");
}
</script>
actions에다가 logout() 이라는 메소드를 넣어주었다.
import { defineStore } from "pinia";
// export default useUserDetailsStore = defineStore("userDetails",{
// state: () => ({
export const useUserDetailsStore = defineStore("userDetails", {
state: () => ({
id : 0,
username : null,
email : null,
role : null
}),
getters:{
isAuthenticated:(state)=>state.username == null? false:true
},
actions: {
logout(){
userDetails.id = 0;
userDetails.username = null;
userDetails.email = null;
}
}
});
null 로 해서 logout()을 만들어준다.
(4) admin 붙여주기
1)
그런데 허락받지 않은 페이지로 함부로 이동해서는 아니된다.
이 경우 허락받지 않은 페이지가 필요함
2)
<admin/Layout.vue>
<script setup>
import Header from '../inc/Header.vue'
import Aside from './Aside.vue'
import Footer from '../inc/Footer.vue'
</script>
<template>
<Header />
<Aside />
<router-view></router-view>
<Footer />
<div class="slash-background">
<div></div>
<div></div>
<div></div>
</div>
</template>
<style scoped>
body{
background-color: var(--color-bg-2);
}
</style>
Admin이 이용하는 layout 구조를 정리한다.
3)
import { createApp } from 'vue'
import { createRouter, createWebHashHistory } from 'vue-router'
import { createPinia} from 'pinia'
import App from './App.vue'
import Layout from './components/inc/Layout.vue'
import Index from './components/Index.vue'
import Login from './components/Login.vue'
import AdminLayout from './components/admin/Layout.vue'
import AdminMenuList from './components/admin/menu/List.vue'
// 2. Define some routes
// Each route should map to a component.
// We'll talk about nested routes later.
const routes = [
{ path: '/', component: Layout, children:[
{ path: 'index', component: Index},
{ path: 'login', component: Login}
] },
//따로하자!
{ path: '/admin', component: AdminLayout, children:[
{ path: 'menu', children:[
{path: 'list' , component: AdminMenuList},
// {path: 'detail' , component: MenuDetail}
]},
] },
]
// 3. Create the router instance and pass the `routes` option
// You can pass in additional options here, but let's
// keep it simple for now.
const router = createRouter({
// 4. Provide the history implementation to use. We are using the hash history for simplicity here.
history: createWebHashHistory(),
routes, // short for `routes: routes`
})
const pinia = createPinia();
// VueElement.createApp() //글로벌 라이브러리
createApp(App)
.use(router)
.use(pinia)
.mount('#app') //->ES6 라이브러리
adminLayout 은 안에 list url 을 매핑시켜준다. 그렇다면 AdminMenuList 를 넣을 수있다.
1. 보충
2. 회고
1) 피니아로 전역객체를 리액티브하게한다는것이 신기하다
2) 그리고 레이아웃 만드는것을 반복하니 감이 생긴다.
'배움 __IL > TIL 1기' 카테고리의 다른 글
TIL 1기를 끝내며... (0) | 2023.06.15 |
---|---|
TIL : 103번째- 230504 [5-1-목] (1) | 2023.05.04 |
TIL : 102번째- 230503 [5-1-수] (0) | 2023.05.03 |
TIL : 101번째- 230501 [5-1-월] (0) | 2023.05.01 |
TIL : 100번째- 230428 [4-4-금] (0) | 2023.04.28 |