フロントエンドを一つのサーバにして、サイトキーを使ってバックエンドを切り替える

デザインは共通でコンテンツの内容がお客様によって違うような、B2BのサービスをKurocoを利用して構築する場合、フロントエンドを共通にして、バックエンドをお客様毎に切り替えるといった使い方が可能です。
Kurocoのデモサイトで、パッケージにもなっている「シンプルな会員制サイト」はフロントエンドを共通にした利用方法となっています。
サイトURL:https://dev-nuxt-auth.g.kuroco-front.app/
Githubリポジトリ:https://github.com/diverta/front_nuxt_auth

本チュートリアルでは企業コード(サイトキー)でバックエンドを切り替えるというB2Bアプリケーションの構築方法を説明します。

このページはKurocoとNuxt.jsでのプロジェクトが構築済みであり、下記のチュートリアルを実施済みであることを前提としています。
Kurocoビギナーズガイド
KurocoとNuxt.jsで、コンテンツ一覧ページを作成する
KurocoとNuxt.jsで、ログイン画面を構築する

メインサイトのコンテンツ登録をする

お客様から申し込みがあった場合に、コピーをしてお客様用の新たなバックエンド(サブサイト)を作成する運用を想定します。
そこでまずはマスタとなるメインサイトのコンテンツを登録します。
なお、本チュートリアルではメインサイトのサイトキーをsample-b2b-service、サブサイトのサイトキーをsample-b2b-service-001とします。

コンテンツの登録

まずはKurocoの管理画面でコンテンツを定義します。
[コンテンツ定義]をクリックします。 fetched from Gyazo

[追加]をクリックします。 fetched from Gyazo

コンテンツ定義編集画面でお好きな名前を入力し、コンテンツの項目を設定し、[追加する]をクリックします。
今回は下記のように設定しています。

Image from Gyazo

次にコンテンツを追加します。
[コンテンツ]->[ご契約者様専用コンテンツ]をクリックします。
Image from Gyazo

[追加]をクリックします。
Image from Gyazo

先ほど定義したコンテンツの項目が表示されますので、コンテンツを入力して[追加する]をクリックします。
今回は下記のように登録しています。
Image from Gyazo

追加したコンテンツ定義のID(8)とコンテンツのID(4)は後ほど利用するのでメモしておきます。

Image from Gyazo

Image from Gyazo

APIの登録

続いてAPIの登録をします。
Kurocoの管理画面から[Default API]をクリックします。
Image from Gyazo

[追加]をクリックします。
Image from Gyazo

タイトル、版、ディスクリプションを入力して[追加する]をクリックします。
Image from Gyazo

追加したAPIに遷移します。
Image from Gyazo

続いて、セキュリティの設定をします。
[セキュリティ]をクリックします。
Image from Gyazo

[Cookie]を選択して[保存する]をクリックします。
fetched from Gyazo

続いて、CORSの設定をします。
[CORSを設定する] をクリックします。
Image from Gyazo

CORS_ALLOW_ORIGINSの [Add Origin] をクリックし、下記を追加します。

  • http://localhost:3000
  • フロントエンドドメイン (ここではhttps://sample-b2b-service.g.kuroco-front.app)

CORS_ALLOW_METHODSの [Add Method] をクリックし、下記を追加します。

  • GET
  • POST
  • OPTIONS

設定できたら[保存する]をクリックします。
Image from Gyazo

次に先ほど作成したコンテンツ「ご契約者様専用コンテンツ」を取得するエンドポイントを作成します。
[エンドポイントの設定]をクリックします。
Image from Gyazo

下記のように設定し、[追加する]をクリックします。

設定項目設定
パスservice_top
有効/無効有効
モデルカテゴリーコンテンツ
モデルTopics
オペレーションDetails
topics_group_id作成したコンテンツ定義のグループID(8)

Image from Gyazo Image from Gyazo Image from Gyazo

以上で、Kuroco側の設定は完了です。

フロントエンドを作成する

ご契約者様専用コンテンツのページを追加する

まずは先ほど作成したご契約者様専用コンテンツを表示するためのフロンエンド部分を作成します。

pages のディレクトリに owners-page のフォルダを作成し、index.vue のファイルを作成します。

/pages/owners-page/index.vue
<template>
  <div>
    <h1>{{ response.details.ext_col_01}}</h1>
    <p>{{ response.details.ext_col_02}}</p>

  <button type="button" @click="logout">
  ログアウト
  </button>
  </div>
</template>

<script>
import { mapActions } from 'vuex'

export default {
  middleware: 'auth',
  async asyncData({$axios}) {
    try {
      const response = await $axios.$get('/rcms-api/4/service_top/4')
      return { response }
    } catch (e) {
      console.log(e.message)
    }
  },
  methods: {
    ...mapActions(['logout'])
  }
}
</script>

エンドポイントを叩くURLをログイン時に変更させる

続いて、エンドポイントを叩くURLをフロントエンドから変更できるように記述を調整します。
/pages/login/index.vueと、/store/index.jsのコードを次のように変更します。

こちらでは/store/index.jsの以下の記述で、入力されたsitekeyを元にリクエスト先のAPIを変更しています。

this.$axios.defaults.baseURL = getters.hostname;
/pages/login/index.vue
<template>
    <form @submit.prevent="login">
      <p v-if="loginStatus !== null" :style="{ color: resultMessageColor }">
        {{ resultMessage }}
      </p>

        <input v-model="sitekey" name="sitekey" type="sitekey" placeholder="sitekey">
        <input v-model="email" name="email" type="email" placeholder="email">
        <input
            v-model="password"
            name="password"
            type="password"
            placeholder="password"
        >
        <button type="submit">
            ログイン
        </button>

        <div>
            <nuxt-link to="/news/">
                ニュース一覧ページへ
            </nuxt-link>
        </div>
        <div>
            <nuxt-link to="/owners-page/">
                契約者専用ページへ
            </nuxt-link>
        </div>
    </form>
</template>

<script>
export default {
    data () {
        return {
            sitekey: '',
            email: '',
            password: '',
            loginStatus: null,
            resultMessage: null
        }
    },
    computed: {
        resultMessageColor () {
            switch (this.loginStatus) {
            case 'success':
                return 'green'
            case 'failure':
                return 'red'
            default:
                return ''
            }
        }
    },
    methods: {
        async login () {
            try {
                const payload = {
                    sitekey: this.sitekey,
                    loginInfo: {
                        email: this.email,
                        password: this.password
                    }
                }
                await this.$store.dispatch('login', payload)
                this.loginStatus = 'success'
                this.resultMessage = 'ログインに成功しました。'
            } catch (e) {
                this.loginStatus = 'failure'
                this.resultMessage = 'ログインに失敗しました。'
            }
        }
    }
}
</script>
/store/index.js
export const state = () => ({
    profile: null
})

export const getters = {
    authenticated (state) {
        return state.profile !== null
    },
    hostname () {
        try {
            const sitekey = localStorage.getItem('sitekey');
            if (sitekey === '' || sitekey === 'undefined' || sitekey === 'null') {
                throw new Error('unknown sitekey');
            }
            return `https://${sitekey}.g.kuroco.app`;
        } catch (e) {
            return false;
        }
    }
}

export const mutations = {
    setProfile (state, { profile }) {
        state.profile = profile
    },
}

export const actions = {
    async login ({ commit, getters }, payload) {
        localStorage.setItem('sitekey', payload.sitekey);
        this.$axios.defaults.baseURL = getters.hostname;

        await this.$axios.$post('/rcms-api/3/login', payload.loginInfo)
        const profileRes = await this.$axios.$get('/rcms-api/3/profile', { withCredentials: true })
        commit('setProfile', { profile: profileRes.data })        
    },

    async logout ({ commit }) {
        try {
            await this.$axios.$post('/rcms-api/3/logout')
        } catch {
             /** No Process */
             /** エラーが返却されてきた場合は、結果的にログアウトできているものとみなし、これを無視します。 */
            }
            commit('setProfile', { profile: null })

            this.$router.push('/login')
        },

    async restoreLoginState ({ commit, dispatch, getters }) {
        if (!getters.hostname) {
            await dispatch('logout')
            throw new Error('need to login')
        }
        try {
            this.$axios.defaults.baseURL = getters.hostname;
            const profileRes = await this.$axios.$get('/rcms-api/3/profile', { withCredentials: true })
            commit('setProfile', { profile: profileRes.data });
        } catch {
            await dispatch('logout')
            throw new Error('need to login')
        }
    }
}

以上でフロントエンドの準備は完了です。

ユーザー用のバックエンドを作成する

サブサイトの追加をする

Kurocoの管理画面から契約者用のバックエンド(サブサイト)を作成します。
[サイト一覧]をクリックします。
Image from Gyazo

[追加]をクリックします。
Image from Gyazo

下記のように設定して[追加する]をクリックします。

項目設定
コピー元のサイト名コピー元となるサイトを選択します。(ここではsample-b2b-service)
サイト名株式会社ディバータ様サイト
サイトキーsample-b2b-service-001
URLフロントエンド共有にチェックを入れて、https://sample-b2b-service.g.kuroco-front.appを選択します。
メールアドレスサイトの構築完了メールの送付先
初期パスワード初期パスワード
会社名株式会社ディバータ
名前DIVERTA TARO

Image from Gyazo

サブサイトのコンテンツを調整する

サブサイトの追加が完了したら、サブサイトのコンテンツを調整します。
メインサイトのサイト一覧に追加したサブサイトが表示されるので、[管理画面]をクリックします。
Image from Gyazo

サブサイトにログインします。
Image from Gyazo

サブサイトのご契約者様専用コンテンツをクリックします。
Image from Gyazo

コンテンツ一覧から[契約者ページトップ]をクリックします。
Image from Gyazo

コンテンツの内容を対象のユーザー向けに調整して[更新する]をクリックします。
Image from Gyazo

サブサイトのAPIを確認する

サブサイトの追加時にフロントエンド共有へチェックを入れていると、設定したフロントエンドのURLが自動的にアカウント設定と、APIのCORS設定に追加されます。
CORS設定の確認をするため、サブサイトのAPIから[B2Bサービスページ]のAPIをクリックします。
Image from Gyazo

[CORSを設定する]をクリックします。
Image from Gyazo

CORS_ALLOW_ORIGINSにフロントエンド共有で選択したフロントエンドURLが追加されていることを確認できました。
Image from Gyazo

以上で設定が完了となりますので、フロントエンドから動作の確認をしてみます。

サイトキーによって表示が変わることを確認する

作成したサイトにアクセスし、入力するsitekeyによって表示されるコンテンツが変わることを確認します。

Image from Gyazo

以上で、フロントエンドを共通にして、バックエンドをお客様毎に切り替える機能を構築できました。
このように追加したお客様専用ページに、メール送信の機能や、コンテンツの投稿機能、コメント機能などを実装することで、B2B向けサービスをKurocoで構築できます。

今回は管理画面からコンテンツの内容を調整しましたが、APIを利用してユーザー自身でコンテンツの追加・更新ができるように実装できます。
また、サイトの追加自体をAPI利用により実行も可能です。

サブサイトのKuroco利用料金はメインサイトにまとめて請求されます。

お探しのページは見つかりましたか?解決しない場合は、問い合わせフォームからお問い合わせいただくか、Slackコミュニティにご参加ください。