LoginSignup
1
0

Azure Static Web Apps用のNuxtモジュールを公開しました

Posted at

Nuxt 3では、Azure Static Web Apps(以下Azure SWA)にデプロイするための設定が用意されています。
しかしAzure SWAで提供されている機能を使おうとすると、そのままではいろいろと不都合な状態にあります。

こうした状態を解消するためのNuxtモジュールである、nuxt-swaライブラリを公開しました。(記事執筆時点でv0.5.0)

何が困るのか?

  • 認証機能(/.auth/...)などをサーバーサイドから呼べない
  • ルート規則がPage Routing時に機能しない

認証機能(/.auth/...)などをサーバーサイドから呼べない

Azure SWAでは、組み込みの認証機能を利用するAPIエンドポイントが以下のように提供されています。

  • /.auth/login/{認証プロバイダ名}: ログイン
  • /.auth/me: ログイン中のユーザー情報(Client Principal)を取得
  • /.auth/logout: ログアウト

しかしながら、NuxtはSSR時に、内部API(/始まり)に対するfetchリクエストを全て内部実装の直接呼び出しに変換します。(Direct call)
そのため、以下のようなコードはサーバーサイド側で[Vue Router warn]: No match found for location with path "..."といったエラーを発生させます。

<template>
  <button @click="navigateTo('/.auth/logout')">ログアウト</button>
</template>

<script setup lang="ts">
const { clientPrincipal } = await $fetch('/.auth/me')
</script>

また、現在パブリックプレビューであるData API Builderのエンドポイント(/data-api/配下)についても同様です。

ルート規則がPage Routing時に機能しない

Azure SWAは、特定のルートへのアクセスを認証済みユーザーのみに制限する機能も持っています。

staticwebapp.config.json
{
  "routes": [
    {
      // /profile 以下はログインユーザーのみ閲覧可能
      "route": "/profile*",
      "allowedRoles": ["authenticated"]
    },
    {
      // /admin/index.html はadministratorロールを持つユーザーのみ閲覧可能
      "route": "/admin/index.html",
      "allowedRoles": ["administrator"]
    },
    {
      // /api/ 以下のPUT, POST, PATCH, DELETEリクエストはadministratorロールを持つユーザーのみ
      "route": "/api/*",
      "methods": ["PUT", "POST", "PATCH", "DELETE"],
      "allowedRoles": ["administrator"]
    }
  ]
}

しかし、これが機能するのはAzure SWAに対して直接リクエストを発行した場合のみになります。
そのためクライアント側でルーティングを実施した場合(例: Vue Router)や、前述のようなAPIのDirect callが発生した場合は、認証がスキップされてしまいます。

nuxt-swaが提供する機能

下記は一例ですので、ほかの機能についてはドキュメントをご覧ください。

SWA組み込みAPIに対するプロキシ

/.auth/以下および、/data-api/以下のルートにリクエストがあった場合、ドメインを付与したフルパスにプロキシするイベントハンドラーを組み込んでいます。

「Azure Functions側で付与されるx-ms-original-urlを読み取ることでドメインを判別する」仕組みなので、サーバー側API(/serverフォルダ配下)から$fetchを呼び出す際はリクエストヘッダーを明示的にバイパスする必要がある点に留意してください。

Global Page Middleware

Pageコンポーネントで以下のように設定することで、モジュール内部で指定したロールを持っていない場合はレンダリング前に401/403エラーを返します。

<script setup lang="ts">
definePageMeta({ allowedRoles: 'authenticated' })
</script>

<template>
<div>Private Page!</div>
</template>

既存のstaticwebapp.config.jsonとの併用も可能ですが、初期リクエスト時(Azure SWAのエラーページ)とページルーティング時(Nuxtのエラーページ)で表示されるエラーページが変わってしまうため、上記設定に寄せることをオススメします。

組み込み認証を利用するためのComposable関数

const {
  clientPrincipal, // 認証情報
  isLoggedIn, // ログインしているかどうか
  hasRole,  // ロールを持つかどうかを返すcomputed<boolean>を生成する関数
  login, // navigateTo(`/.auth/login/{provider}`)
  logout, // navigateTo(`/.auth/logout`)
} = await useEasyAuth()

サーバー側でユーザー情報を取得するユーティリティ関数の提供

export default defineEventHandler(event => {
  // リクエストしたユーザーの認証情報を取得
  const clientPrincipal = getClientPrincipal(event)
})

export default defineEventHandler(event => {
  // administratorロールを持つか
  if (!hasRole(event, 'administrator')) {
    throw createError({ statusCode: 403 })
  }
})

nitro.azure.configに対する型定義の提供

image.png

上記設定がない場合は、モジュール側でも警告します。

今後の展望(ToDo)

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0