Vue SPA에서 OIDC-Client를 사용한 암시적 권한 부여 기반 SSO 구현

1. 개요

본 문서에서는 JavaScript 클라이언트 인증을 구현하는 방법을 다룬다. 이전 예제를 바탕으로 Vue CLI로 생성한 클라이언트 애플리케이션에서 oidc-client-js 라이브러리를 사용하여 인증을 처리한다. 클라이언트 자격 증명은 기본적으로 cookie에 저장된다.

2. 서버측 Client 설정

순수 JavaScript 클라이언트를 추가하려면 새로운 클라이언트 등록이 필요하며, 브라우저 URL을 통한 액세스 토큰 전달을 명시적으로 허용해야 한다. Config 클래스에서 다음 설정을 추가한다:

new Client
{
    ClientId = "javascript-client",
    ClientName = "Vue Application",
    RequireConsent = false,
    AllowAccessTokensViaBrowser = true,
    AllowedGrantTypes = GrantTypes.Implicit,
    RedirectUris = { "http://localhost:8080/callback" },
    PostLogoutRedirectUris = { "http://localhost:8080/logout" },
    AllowedScopes = new List<string>
    {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile
    }
}

3. Vue 클라이언트 구현

3.1 프로젝트 생성

// vue-cli를 사용하여 프로젝트 생성
vue create authclient

// 라우터 모듈 설치
npm install vue-router --save

// OIDC 클라이언트 라이브러리 설치
npm install oidc-client --save

3.2 라우터 설정 파일 생성

home 및 callback 두 개의 페이지를 위한 라우트를 정의한다.

import Vue from 'vue'
import Router from 'vue-router'

import callBack from '@/pages/callBack.vue'
import home from '@/pages/home.vue'

Vue.use(Router)

export default new Router({
    mode: 'history',
    routes: [
        {
            path: '/',
            component: home
        },
        {
            path: '/callback',
            name: 'callback',
            component: callBack
        }
    ]
})

3.3 페이지 컴포넌트 생성

Home 컴포넌트

<template>
  <div class="container">
    <h1>메인 페이지</h1>
  </div>
</template>

<script>
export default {
  name: 'HomePage',
  data() {
    return {
      message: '환영합니다'
    }
  }
}
</script>

<style scoped>
.container {
  text-align: center;
  padding: 20px;
}
</style>

Callback 컴포넌트

<template>
  <div>인증 처리 중...</div>
</template>

<script>
export default {
  name: 'AuthCallback',
  mounted() {
    this.$userManager.signinRedirectCallback()
      .then((user) => {
        console.log('사용자 정보:', user)

        window.history.replaceState(
          {},
          window.document.title,
          window.location.origin + window.location.pathname
        )

        window.location.href = '/'
      })
      .catch((err) => {
        console.error('인증 오류:', err)
      })
  }
}
</script>

3.4 SSO 모듈 설정

OIDC 클라이언트 설정을 위한 별도 모듈을 생성한다.

import Oidc from 'oidc-client'

const currentHost = location.origin
const authServerUrl = 'http://localhost:5010'

const userManager = new Oidc.UserManager({
    authority: authServerUrl,
    client_id: 'javascript-client',
    post_logout_redirect_uri: `${currentHost}/logout`,
    redirect_uri: `${currentHost}/callback`,
    silent_redirect_uri: `${currentHost}/callback`,
    accessTokenExpiringNotificationTime: 300,
    silentRequestTimeout: 5000,
    response_type: 'token id_token',
    scope: 'openid profile',
    filterProtocolClaims: true
})

userManager.events.addUserSignedOut(async () => {
    await userManager.removeUser()
    try {
        await userManager.signinRedirect()
    } catch (error) {
        console.error('로그아웃 처리 중 오류 발생:', error)
    }
})

export default userManager

3.5 main.js에서 모듈 등록

import Vue from 'vue'
import App from './App.vue'

import userManager from './sso.js'
import router from './router.js'

Vue.config.productionTip = false

Vue.prototype.$userManager = userManager

router.beforeEach(async (to, from, next) => {
  if (to.name === 'callback') {
    next()
  } else if (to.name === 'logout') {
    console.log('로그아웃 요청 처리')
  } else {
    const user = await userManager.getUser()
    if (user) {
      next()
    } else {
      userManager.signinRedirect().catch(error => {
        console.error('리다이렉션 오류:', error)
      })
    }
  }
})

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

4. 실행 및 테스트

애플리케이션 실행 단계는 다음과 같다:

  1. 먼저 인증 서버를启动了한다
  2. 그 다음 Vue 클라이언트를 실행한다
  3. 클라이언트 라우터 가드가 인증 서버(localhost:5010)의 로그인 페이지로 리다이렉트한다
  4. 사전에 설정한 사용자 자격 증명으로 로그인한다
  5. 인증 성공 후 callback 페이지로 이동한 후 클라이언트 메인 페이지로 전환되며, cookie와 sessionStorage에 세션 정보가 저장된다

5. 프로젝트 구조

최종 프로젝트 디렉토리 구조는 아래와 같다:

authclient/
├── src/
│   ├── pages/
│   │   ├── home.vue
│   │   └── callBack.vue
│   ├── App.vue
│   ├── main.js
│   ├── router.js
│   └── sso.js
├── package.json
└── vue.config.js

태그: vue oidc single-sign-on authentication oauth2

5월 23일 05:47에 게시됨