Files
2022-01-20 20:30:18 +01:00

6.3 KiB

id, title, challengeType, forumTopicId, dashedName
id title challengeType forumTopicId dashedName
589a69f5f9fc0f352b528e70 ソーシャル認証の実装 2 301559 implementation-of-social-authentication

--description--

アプリでこの種の認証を行うには、以下のパスに従います。

  1. ユーザーは、特定のストラテジー (たとえば、GitHub) を使用して認証を受けるためのルートに自身を送信するボタンまたはリンクをクリックします。
  2. ルートは passport.authenticate('github') を呼び出し、ユーザーを GitHub へリダイレクトします。
  3. ユーザーがたどり着いた GitHub のページで、ユーザーがまだログインしていない場合はログインが許可されます。 次に、アプリからのプロファイルへのアクセスを承認するようユーザーに求めます。
  4. ユーザーはアプリの特定のコールバック URL に戻り、ユーザーが承認した場合はプロファイルが返されます。
  5. これでユーザーが認証され、アプリでは、プロファイルが返却されたプロファイルかどうかを確認します。そうでない場合はデータベースに保存します。

OAuth を使用したストラテジーでは、少なくともクライアント IDクライアント シークレットが必要です。サービスはこれらを使用して、認証リクエストが誰からのものか、またそれが有効かどうかを確認します。 これらは、認証を実装しようとしている GitHub などのサイトから取得され、アプリに固有のものです。これらの情報は共有すべきではありません。したがって、公開リポジトリにアップロードしたり、コード内に直接書き込んだりしないでください。 通常は、それらを .env ファイルに保存し、process.env.GITHUB_CLIENT_ID などのように参照します。 このチャレンジでは、GitHub ストラテジーを使用します。

GitHub からのクライアント ID とシークレットの取得は、「開発者設定」のアカウントプロファイル設定で実行され、その後は「OAuth アプリケーション」で実行されます。 「Register a new application (新しいアプリを登録する)」をクリックし、アプリに名前を付け、URL を Replit のホームページに貼り付けます (プロジェクトコードの URL ではありません)。最後に、コールバック URL をホームページと同じ URL に貼り付けますが、/auth/github/callback を追加します。 ユーザーはここにリダイレクトされ、GitHub で認証された後、処理が行われます。 返された情報を 'GITHUB_CLIENT_ID' および 'GITHUB_CLIENT_SECRET' として .env ファイルに保存します。

routes.js ファイルで、showRegistration: true の後に、showSocialAuth: true をホームページルートに追加します。 GET リクエストを受け付けるルートを 2 つ作成します。それらは、/auth/github/auth/github/callback です。 1 つ目は、Passport を呼び出して 'github' を認証するだけです。 2 つ目は、Passport を呼び出して 'github' を認証した結果失敗し、/ へリダイレクトした後、リダイレクトが成功した場合は /profile へリダイレクトします(前回のプロジェクトと同様です)。

/auth/github/callback の内容は、たとえば通常のログイン処理と似たものになります。

app.route('/login')
  .post(passport.authenticate('local', { failureRedirect: '/' }), (req,res) => {
    res.redirect('/profile');
  });

正しいと思ったら、ページを送信してください。 エラーが発生している場合は、ここまでに完了したプロジェクトをこちらで確認できます。

--hints--

ルート /auth/github が正確である必要があります。

async (getUserInput) => {
  try {
    const res = await fetch(getUserInput('url') + '/_api/routes.js');
    if (res.ok) {
      const data = await res.text();
      assert.match(
          data.replace(/\s/g, ''),
          /passport.authenticate.*?github/g,
          'Route auth/github should only call passport.authenticate with github'
        );
    } else {
      throw new Error(res.statusText);
    }
    const res2 = await fetch(getUserInput('url') + '/_api/app-stack');
    if (res2.ok) {
      const data2 = JSON.parse(await res2.json());
      const dataLayer = data2.find(layer => layer?.route?.path === '/auth/github');
      assert.deepInclude(dataLayer?.route, { methods: {get: true}, path: "/auth/github"});
      assert.deepInclude(dataLayer?.route?.stack?.[0], {method: "get", name: "authenticate"});
    } else {
      throw new Error(res2.statusText);
    }
  } catch (err) {
    throw new Error(err);
  }
}

ルート /auth/github/callback が正確である必要があります。

async (getUserInput) => {
  try {
    const res = await fetch(getUserInput('url') + '/_api/routes.js');
    if (res.ok) {
      const data = await res.text();
      assert.match(
        data.replace(/\s/g, ''),
        /failureRedirect:("|')\/\1/g,
        'Route auth/github/callback should accept a get request and call passport.authenticate for github with a failure redirect to home'
      );
    } else {
      throw new Error(res.statusText);
    }
    const res2 = await fetch(getUserInput('url') + '/_api/app-stack');
    if (res2.ok) {
      const data2 = JSON.parse(await res2.json());
      const dataLayer = data2.find(layer => layer?.route?.path === '/auth/github/callback');
      assert.deepInclude(dataLayer?.route, { methods: {get: true}, path: "/auth/github/callback"});
      assert.deepInclude(dataLayer?.route?.stack?.[0], {method: "get", name: "authenticate"});
    } else {
      throw new Error(res2.statusText);
    }
  } catch (err) {
    throw new Error(err);
  }
}

--solutions--

/**
  Backend challenges don't need solutions, 
  because they would need to be tested against a full working project. 
  Please check our contributing guidelines to learn more.
*/