最近、ReactクライアントでIdentityServer4を使用して認証をセットアップしようとしています。IdentityServerドキュメントのAdding a JavaScript client
チュートリアル(一部)を実行しました: https:/ /media.readthedocs.org/pdf/identityserver4/release/identityserver4.pdfQuickstart7_JavaScriptClient
ファイルも使用します。
欠点は、Reactをフロントエンドとして使用していることと、Reactに関する私の知識が、チュートリアルで使用されているのと同じ機能を実装するのに十分ではないことです。 Reactを使用します。
それにもかかわらず、私は読み始め、とにかくそれを使い始めようとしました。 IdentityServerプロジェクトとAPIが設定され、正しく機能しているようです(他のクライアントでもテストされています)。
まず、oidc-client.jsをビジュアルコードプロジェクトに追加しました。次に、最初にレンダリングされるページ(Authentication.jsという名前)を作成しました。ここには、ログイン、コールAPI、ログアウトボタンが含まれています。このページ(Authentication.js)は次のようになります。
import React, { Component } from 'react';
import {login, logout, api, log} from '../../testoidc'
import {Route, Link} from 'react-router';
export default class Authentication extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<div>
<button id="login" onClick={() => {login()}}>Login</button>
<button id="api" onClick={() => {api()}}>Call API</button>
<button id="logout" onClick={() => {logout()}}>Logout</button>
<pre id="results"></pre>
</div>
<div>
<Route exact path="/callback" render={() => {window.location.href="callback.html"}} />
{/* {<Route path='/callback' component={callback}>callback</Route>} */}
</div>
</div>
);
}
}
Testoidc.jsファイル(上記でインポートしたもの)に、使用するすべてのoidc関数(サンプルプロジェクトのapp.js)を追加しました。ルート部分は、callback.htmlを使用可能にする必要があります。そのファイルはそのままにしておきます(これはおそらく間違っています)。
Testoidc.jsファイルには、次のような関数が含まれています。
import Oidc from 'oidc-client'
export function log() {
document.getElementById('results').innerText = '';
Array.prototype.forEach.call(arguments, function (msg) {
if (msg instanceof Error) {
msg = "Error: " + msg.message;
}
else if (typeof msg !== 'string') {
msg = JSON.stringify(msg, null, 2);
}
document.getElementById('results').innerHTML += msg + '\r\n';
});
}
var config = {
authority: "http://localhost:5000",
client_id: "js",
redirect_uri: "http://localhost:3000/callback.html",
response_type: "id_token token",
scope:"openid profile api1",
post_logout_redirect_uri : "http://localhost:3000/index.html",
};
var mgr = new Oidc.UserManager(config);
mgr.getUser().then(function (user) {
if (user) {
log("User logged in", user.profile);
}
else {
log("User not logged in");
}
});
export function login() {
mgr.signinRedirect();
}
export function api() {
mgr.getUser().then(function (user) {
var url = "http://localhost:5001/identity";
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onload = function () {
log(xhr.status, JSON.parse(xhr.responseText));
}
xhr.setRequestHeader("Authorization", "Bearer " + user.access_token);
xhr.send();
});
}
export function logout() {
mgr.signoutRedirect();
}
うまくいかないことがいくつかあります。ログインボタンをクリックすると、identityServerのログインページにリダイレクトされます(これで問題ありません)。有効な認証情報でログインすると、React app: http:// localhost:3000/callback.html#id_token = Token にリダイレクトされます
Identityプロジェクトのこのクライアントは、次のように定義されています。
new Client
{
ClientId = "js",
ClientName = "JavaScript Client",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
// where to redirect to after login
RedirectUris = { "http://localhost:3000/callback.html" },
// where to redirect to after logout
PostLogoutRedirectUris = { "http://localhost:3000/index.html" },
AllowedCorsOrigins = { "http://localhost:3000" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1"
}
}
コールバック関数が呼び出されることはないようですが、非常に長いトークンが後ろにあるコールバックURLに留まっています。
また、ログイン後、getUser関数は「ログインしていないユーザー」を表示し続け、「APIを呼び出す」ボタンはトークンがないことを示し続けます。したがって、明らかに物事は正しく機能していません。私はそれがどこで間違っているのかわからない。検査すると、ローカルストレージに生成されたトークンがあることがわかります。
また、ログアウトボタンをクリックすると、Identity Hostのログアウトページにリダイレクトされますが、ログアウトをクリックすると、クライアントにリダイレクトされません。
私の質問は:
誰かが私を正しい方向に向けることができますか?おそらくここで間違っていることがもっとありますが、現時点ではどこから始めればいいのか悩んでいます。
IdentityServer4は、OIDCのバックエンド実装にすぎません。そのため、指定するAPIを使用してクライアントにフローを実装するだけで済みます。 oidc-client.jsファイルが何であるかはわかりませんが、おそらく自分で実装したのと同じことをしています。フロー自体は非常に単純です。
client_id
とredirect_uri
(および状態、ノンス)を使用してユーザーを認証サーバーにリダイレクトしますclient_id
とredirect_uri
が一致するかどうかを確認します。redirect_uri
に新しいパラメーターでリダイレクトします。あなたの場合、URLは次のようになります:https://example.com/cb#access_token=...&id_token=...&stuff-like-nonce-and-state
ロジックを実現する最も簡単な方法は、まずロジックを実行するコンポーネントに解決するルートをルーターに設定することです。このコンポーネントは「非表示」にすることができます。何もレンダリングする必要さえありません。次のようにルートを設定できます:
<Route path="/cb" component={AuthorizeCallback} />
次に、AuthorizeCallback
コンポーネントにOIDCクライアントロジックを実装します。コンポーネントでは、URLを解析するだけです。 location.hash を使用して、URLの#access_token=...&id_token=...&stuff-like-nonce-and-state
部分にアクセスできます。 RLSearchParams または qs のようなサードパーティのライブラリを使用できます。次に、値をどこかに保存します(sessionStorage、localStorage、および可能であればCookie)。他に行うことは、実装の詳細です。たとえば、私のアプリの1つで、ユーザーがアプリでアクセスしていたアクティブページを記憶するために、sessionStorageに値を保存し、そのストレージの値をAuthorizeCallback
に使用して、ユーザーを適切なページ。したがって、認証サーバーはAuthorizeCallback
に解決される「/ cb」にリダイレクトし、このコンポーネントはユーザーの場所に基づいて目的の場所(場所が設定されていない場合は「/」)にリダイレクトします。
また、承認サーバーのセッションCookieの有効期限が切れていない場合、トークンの有効期限が切れているか、トークンが削除されていても、再ログインする必要はありません。これは、トークンの有効期限が切れている場合に役立ちますが、ログアウトすると問題が発生する可能性があります。そのため、ログアウトするときに、ストレージからトークンを削除する直前に、トークンを削除/期限切れにするリクエストを承認サーバーに送信する必要があります。