web-dev-qa-db-ja.com

Auth0:Auth0のサインアップ後にローカルデータベースにユーザーを作成します

Auth0を使用してすべてのユーザーデータをホストしています。独自のバックエンドもあり、その中にUsersテーブルが必要です。これにより、データベースで生成されたuserIdがAuth0のuser_idにマップされます。サインアップ時に2つのフローの間で躊躇しています:

サインアップフロー1:

  1. フロントエンドにロックが表示され、ユーザーがサインアップします。
  2. Auth0がフロントエンドにリダイレクトされた後、フロントエンドにはAuth0 user_idがあります。
  3. フロントエンドはPOST /users(パブリックエンドポイント)でバックエンドを呼び出し、user_idで新しいユーザーを作成します。
  4. バックエンドリソースサーバーへの認証されたリクエストごとに、JWTにはauth0 user_idが含まれているため、dbはuser_idと私のuserIdの間でルックアップを行います。

サインアップフロー2:

  1. フロントエンドにロックが表示され、ユーザーがサインアップします。
  2. バックエンドでPOST /usersを呼び出すAuth0の登録後フックを構成します。この呼び出しにより、データベースのuserIdが生成され、Auth0に返送されます。
  3. このuserIdをAuth0のuser_metadataに入れます。
  4. このuser_metadataはJWTに含まれるため、リソースをフェッチするためのバックエンドへのすべての呼び出しには、データベースのuserIdが含まれます(追加のルックアップは必要ありません)。

2の方がしっかりしている気がします。他のサインアップフローはありますか?一部のauth0のお客様は、私の#2と同様のフローを使用していますか?私は彼らのドキュメントにはあまり見つかりませんでした。

13
amaurymartiny

これは私の最初の投稿ですので、初心者のミスをした場合はすみません。

サインアップフロー1は非常にうまく機能することがわかりました。使用しているテクノロジーを指定していませんが、React、redux、Expressバックエンドを備えたサインアップフロー1を使用して完全に機能するブログがある私のgithubへのリンクを次に示します。

https://github.com/iqbal125/react-redux-fullstack-blog

これらのフレームワークを使用してデモンストレーションを行うので、使用しているフレームワークに合わせてコードを調整できることを願っています。

私のサインアッププロセスは次のとおりです:

  1. フロントエンドは、ロックユーザーがサインアップしたことを示しています
  2. ユーザーはコールバックページにリダイレクトされます。
  3. 次に、コールバックページから「auth-check」ページにリダイレクトします。 auth-checkページにネストされたapi呼び出しがあり、両方ともauth0からユーザーデータを取得し、すぐにapiエンドポイントを呼び出してユーザーデータをdbに保存します。
  4. Api呼び出しは、ユーザーがすでにsql dbにあるかどうかを確認してから、ユーザーデータを保存します。それ以外の場合は何もしません。
  5. その後、ユーザーデータはreduxグローバル状態に保存され、ユーザープロファイルページにデータを表示するために使用できます。
  6. ユーザーがログアウトをクリックすると、authcheckが再度呼び出され、ユーザー情報がグローバル状態から削除されてから、ユーザーがログアウトされます。
  7. その後、auth-checkはホームページにリダイレクトします。



1。フロントエンドは、ロックユーザーがサインアップしたことを示しています

  login() {
    this.auth0.authorize();
   }


2。ユーザーはコールバックページにリダイレクトされます。

私のコールバックページは非常にシンプルで、機能コンポーネントとして使用しています。

  <div>
    <h2>Callback</h2>
  </div>


3。次に、コールバックページから「auth-check」ページにリダイレクトします

これは、auth.js utilコンポーネントのhandleAuthentication()関数を使用して行います。コードはauth0サンプルからわずかに変更されています。

  handleAuthentication() {
    this.auth0.parseHash((err, authResult) => {
      if (authResult && authResult.accessToken && authResult.idToken) {
        this.setSession(authResult);
        this.getProfile();
        setTimeout( function() { history.replace('/authcheck') }, 2000);
      } else if (err) {
        history.replace('/');
        console.log(err);
        alert(`Error: ${err.error}. Check the console for further details.`);
      }
    });
   }

GetProfile()関数を追加したことに気付くでしょう

   getProfile() {
    let accessToken = this.getAccessToken();
    if(accessToken) {
      this.auth0.client.userInfo(accessToken, (err, profile) => {
        if (profile) {
          this.userProfile = { profile };
         }
       });
     }
    }

getAccessToken()関数と一緒に

  getAccessToken() {
    if (localStorage.getItem('access_token')) {
      const accessToken = localStorage.getItem('access_token')
      return accessToken
    }
    else {
      console.log("No accessToken")
      return null
    }
   }

Auth.js utilコンポーネントのこれら2つの関数は、auth0から情報を取得し、それをクラスで宣言した空のオブジェクトに保存できるようにするものです。

  userProfile = {}

Auth-check.jsコンテナに移動します。コンストラクターで関数を宣言することから始め、次に関数自体を宣言します。次に、コンポーネントのレンダリング時に自動的に実行されるcomponentDidMount()ライフサイクルメソッドを呼び出します。

  constructor() {
    super()
    this.send_profile_to_db = this.send_profile_to_db.bind(this)
  }

   send_profile_to_db (profile) {
    const data = profile
    axios.post('api/post/userprofiletodb', data)
    .then(() => axios.get('api/get/userprofilefromdb', {params: {email: profile.profile.email}} )
      .then(res => this.props.db_profile_success(res.data))
      .then(history.replace('/')))
   }

私のライフサイクルメソッドとImは空のdivを返します。

componentDidMount() {
    if(this.props.auth.isAuthenticated()) {
      this.props.login_success()
      this.props.db_profile_success(this.props.auth.userProfile)
      this.send_profile_to_db(this.props.auth.userProfile)
    } else {
      this.props.login_failure()
      this.props.profile_failure()
      this.props.db_profile_failure()
      history.replace('/')
    }
  }

   render() {
    return (
        <div>
       </div>
    )
  }
}

このコードは、あなたが尋ねた質問の核心になっていると思います。

send_profile_to_db()関数から始めます。

ここでは、axiosを使用してリクエストを行っています。 ExpressサーバーへのバックエンドAPI呼び出しの作成を開始し(次の手順で説明します)、axiosを使用してユーザープロファイルをデータオブジェクトパラメーターとして渡します。実際のユーザープロファイルデータがどこから来ているのか疑問に思われるかもしれません。

私のroutes.jsルートコンポーネントで、Authの新しいインスタンスをインポートして初期化しました

export const auth = new Auth();

次に、それを小道具としてAuthCheckコンポーネントに渡しました。

<Route path="/authcheck" render={(props) => <AuthCheck auth={auth} {...props} />} />

これにより、「this.props」を使用してauthクラスのすべてのプロパティにアクセスできます。したがって、最後のステップで初期化した「userProfile = {}」オブジェクトを使用するだけで、ユーザーデータが含まれるようになります。

データベースにデータを投稿した後、データベースからプロファイルを検索するためのパラメーターとしてユーザーの電子メールを使用してaxios getリクエストを呼び出すネストされた「.then()」関数を使用します。データベースプロファイルには、ユーザーの投稿とユーザーのコメントに関するデータが含まれています。これは、アプリでデータを表示するのに役立ちます。次に、別の「.then()」ステートメントとRedux Thunkを使用して、ユーザープロファイルデータをグローバルなredux状態に非同期で保存します。

したがって、要約すると、このauthcheckコンポーネントは4つのことを実行しています。
1。 auth0から取得したユーザープロファイルデータを独自のデータベースに保存します。
2。次に、データを保存した後、すぐにデータベースから同じプロファイルを取得します。
3。ユーザーが認証されているかどうかをアプリに認識させます。
4。他のコンポーネントで使用するために、データベースのユーザープロファイルデータをグローバルredux状態に保存します。

あなたが私に尋ねれば、かなり素晴らしいです!



4。 api呼び出しは、ユーザーがすでにsql dbにあるかどうかを確認してから、ユーザーデータを保存します。それ以外の場合は、何もしません。

これが私のサーバーのセットアップです。ユーザーが「post」および「get」リクエストをデータベース化するため。

router.post('/api/post/userprofiletodb', (req, res, next) => {
  const values = [req.body.profile.nickname, req.body.profile.email, req.body.profile.email_verified]
  pool.query('INSERT INTO users(username, email, date_created, email_verified) VALUES($1, $2, NOW(), $3) ON CONFLICT DO NOTHING', values, (q_err, q_res) => {
    if (q_err) return next(q_err);
    console.log(q_res)
    res.json(q_res.rows);
  });
});

/* Retrieve user profile from db */
router.get('/api/get/userprofilefromdb', (req, res, next) => {
  // const email = [ "%" + req.query.email + "%"]
  const email = String(req.query.email)
  pool.query("SELECT * FROM users WHERE email = $1", [ email ], (q_err, q_res) => {
    res.json(q_res.rows)
  });
});

注意すべきいくつかの事柄:

ルータオブジェクトはexpress.router()です。私はpsqlを使用しています。

「ONCONFLICTDO NOTHING」を追加することを忘れないでください。そうしないと、同じユーザーの複数のバージョンが保存されます。

Auth0が提供するデータポイントは他にもいくつかあると思いますが、結局それらを使用しませんでした。

これがusersテーブルのSQLスキーマです。

CREATE TABLE users (
  uid SERIAL PRIMARY KEY,
  username VARCHAR(255) UNIQUE,
  email VARCHAR(255),
  email_verified BOOLEAN,
  date_created DATE,
  last_login DATE
);



5。その後、ユーザーデータはreduxグローバル状態に保存され、ユーザープロファイルページにデータを表示するために使用できます。

ステップ3でこれを説明することになりました。



6。ユーザーがログアウトをクリックすると、authcheckが再度呼び出され、ユーザー情報がグローバル状態から削除されてから、ユーザーがログアウトされます。

手順3を参照してください



7。その後、auth-checkはホームページにリダイレクトします。

もう一度ステップ3を参照してください笑。


完全に機能するブログだと言ったように、興味がある場合や何かを見逃した場合は、必ず私のリポジトリをチェックしてください。

9
iqbal125