Vue3 + KeyCloakで簡単なログイン実装

# はじめに
業務で認証・認可用のプロダクト/サービスを選定する必要があり、調べたりドキュメント読んだりするだけだと分からないので実際に触ってみた記録

# 環境
```
Windows 11 Pro
Vue.js 3.3.4
node.js v16.12.0
npm 8.1.0
keycloak-js 22.0.5
docker 20.10.23, build 7155243
```

# KeyCloak構築
基本的には公式サイトを見てそのままやれました。

https://www.keycloak.org/getting-started/getting-started-docker

1. インストール&起動
    ```bash
    # ローカル側の8080~8082はすでに別アプリが動いていたので8083に変更
    > docker run -p 8083:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin 
    quay.io/keycloak/keycloak:22.0.5 start-dev
    ```
1. `http://localhost:8083/admin` に遷移
1. admin / adminでログイン
1. masterじゃないrealmを作成
1. ユーザーも適当に作成
    ※お試しなのでTemporaryはOFF
1. `http://localhost:8083/realms/myrealm/account` に遷移し、作成したユーザーでログインできることを確認
    (ポートを8083に変えたのを忘れて公式サイトに記載されているリンクを踏んで404になってあれ～？となっていた :joy: )
1. clientも適当に作成
    Valid redirect URIsは`http://127.0.0.1:5173/*`と`http://localhost:5173/*`、
    Web originsは`http://127.0.0.1:5173`と`http://localhost:5173`にする
    ※`5173`はvue(vite)サーバーが起動するポートにする

ここまででKeyCloak側の設定は完了


# Vue構築
```bash
> npm init vue@latest
√ Project name: ... keycloaktest
√ Add TypeScript? ... Yes
√ Add JSX Support? ... No
√ Add Vue Router for Single Page Application development? ... Yes
√ Add Pinia for state management? ... No
√ Add Vitest for Unit Testing? ... No
√ Add an End-to-End Testing Solution? » No
√ Add ESLint for code quality? ... Yes
√ Add Prettier for code formatting? ... Yes
> cd keycloaktest
> npm i
> npm run dev
```
↑ここまででVueのサンプルが起動することを確認
```bash
> npm i keycloak-js
```

# Vueでkeycloak-jsを使う

## 下準備
<details><summary>記事のメインではないので省略</summary>

`App.vue`を以下に変更
```vue
<script setup lang="ts">
  import { RouterView } from 'vue-router'
</script>

<template>
  <RouterView />
</template>
```

`src/components`に`TopPage.vue`を作成
```vue
<script setup lang="ts">
  import { RouterLink } from 'vue-router'
</script>

<template>
  <div>topページ</div>

  <RouterLink to="/mypage">マイページへ</RouterLink>
</template>
```

`src/components`に`MyPage.vue`を作成
```vue
<script setup lang="ts">
</script>

<template>
  <div>mypage</div>
</template>
```

`router/index.ts`を以下に変更
```typescript
import { createRouter, createWebHistory } from 'vue-router'
import TopPage from '../components/TopPage.vue'
import MyPage from '../components/MyPage.vue'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'top',
      component: TopPage
    },
    {
      path: '/mypage',
      name: 'mypage',
      component: MyPage
    }
  ]
})

export default router
```
これで下準備は完了です。

</details>

[こちら](https://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter)の公式ドキュメントを参考に、`MyPage.vue`を修正
```diff_vue
<script setup lang="ts">
+ import { ref } from 'vue'
+ import Keycloak from 'keycloak-js'
+ 
+ const keycloak = new Keycloak({
+   url: 'http://localhost:8083',
+   realm: 'testrealm',
+   clientId: 'localvue'
+ })
+ 
+ let isLogin = ref(false)
+ 
+ keycloak.init({
+   onLoad: 'login-required',
+   checkLoginIframe: false
+ })
+ .then((authenticated) => isLogin.value = authenticated)
+ .catch((e) => console.error(e))
+ 
+ const logout = () => keycloak.logout({ redirectUri: 'http://localhost:5173/' })
</script>

<template>
+ <template v-if="isLogin">
    <div>mypage</div>
+   <button @click="logout">ログアウト</button>
+ </template>
</template>
```

トップ画面で「マイページへ」リンクをクリックすると`/mypage`に遷移し、`keycloak.init()`実行時に未ログインであればKeyCloakのログイン画面に遷移します。
そこで先程作成した一般ユーザーでログインすると、Vueの`/mypage`ページにリダイレクトされてマイページが表示できます。
これでログインできました！
ログアウトボタンをクリックするとログアウトし、トップ画面にリダイレクトされます。

# 感想
思ったよりは簡単に使えました。
実装時のイメージもついたと思います。
ただ、どのように自社製フレームワークに組み込んでいくか等は全然決まってないので（おい）
社内で確認して要件を確定しつつ、どのプロダクト・サービスが最適なのか検討したいと思います。

# 参考

https://qiita.com/maaaashi/items/b99e123129735deb5576