배움 __IL/TIL 1기

TIL : 104번째- 230508 [5-2-월]

Mo_bi!e 2023. 5. 8. 19:11

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