OAuth2によるユーザーの認証
OAuth 2.0の認証プロトコルを使用してLiferayのヘッドレスREST APIにアクセスするアプリケーションを作成できます。 提供されているサンプルReactアプリは、OAuth2トークンベースの3種類の認証フロー(認証コードフロー、クライアント認証情報フロー、パスワードフロー)のデモを実行しています。 OAuth2 管理パネルの詳細については、 OAuth2 アプリケーションの作成を参照してください。
Liferay DXPのセットアップ
新しいLiferay DXPインスタンスを起動し、以下を実行します。
docker run -it -m 8g -p 8080:8080 liferay/dxp:2024.q2.11。
メールアドレス test@liferay.com とパスワード test を使用して、http://localhost:8080でLiferayにサインインしてください。 プロンプトが表示されたら、パスワードを learn に変更します。
-
グローバルメニュー()を開き、 コントロールパネル → セキュリティ → OAuth 2 管理 に移動します。
-
Add ( ) をクリックして、新しい OAuth2 アプリケーションを作成します。
-
アプリケーションに名前を付ける(例:foo)。ウェブサイトのURLを
http://localhost:3000
に、コールバックURIをhttp://localhost:3000/grant-type-authorization-code
に設定する。 Save をクリックします。 -
クライアントIDとクライアントシークレットをクリップボードにコピーします。クライアントシークレットを取得するには、 Edit をクリックします。ポップアップウィンドウから値をコピーします。
これらの値は、後でサンプルReactアプリで必要になります。
-
ページ上部の[Scopes]タブをクリックします。下にスクロールし、 LIFERAY.HEADLESS.ADMIN.USER をクリックし、 read data on your behalf にチェックを入れます。
保存 をクリックします。これで、OAuth2アプリケーションにAdmin User APIカテゴリの読み取り権限が付与されました。
-
次に、 Global Menu( Global Menu ) を開き、 Control Panel タブをクリックし、 System Settings → Security Tools に進みます。
-
[Portal Cross-Origin Resource Sharing (CORS)] タブに移動し、[Default Portal CORS Configuration] をクリックします。
-
値
/o/headless-admin-user/*
の URL パターン を追加し、 保存 をクリックします。これで、headless-admin-user
カテゴリのAPIに対してCORSが有効になる。
サンプルReactアプリのデプロイ
-
OAuth2 React App をダウンロードして解凍します。
curl https://resources.learn.liferay.com/dxp/latest/en/headless-delivery/using-oauth2/liferay-c2b6.zip -O
unzip liferay-c2b6.zip
cd liferay-c2b6
-
node
とyarn
がインストールされていることを確認します。 そうでない場合は、セットアップスクリプトを実行し、プロンプトに従います。./setup_tutorial.sh
-
アプリのルート・ディレクトリに移動し、Reactサーバーを起動する。
cd c2b6-custom-element
yarn install && yarn start
認証コードのフロー
認証コードフローでは、アプリケーションに権限を与える前に、ユーザーが認証情報でログインし、認証を承認する必要があります。 他のフローでは、この追加ステップを回避することができます。
-
http://localhost:3000で動作しているReactアプリを開き、ページ上部の Authorization Code Flow をクリックします。
-
Liferay authorize URL には
http://localhost:8080/o/oauth2/authorize
と入力します。 クリップボードからクライアントIDを貼り付けます。 [Authorize] をクリックします。 -
まだログインしていない場合、認証ページに移動する前にLiferayのログインページにリダイレクトされます。 ユーザー名とパスワード(例: test@liferay.com:learn)を入力し、 [サインイン] をクリックします。 認証ページで、 [認証する] をクリックします。 すでにログインしている場合は、認証ページに直接送られます。
Reactアプリにリダイレクトされます。 次のAPIコールに使用される認証コードが表示されることに注意。
-
Liferay トークンの URL には
http://localhost:8080/o/oauth2/token
と入力してください。 クライアントIDとクライアントシークレットをクリップボードから貼り付けます。 [Get Token] をクリックします。 今後のREST API呼び出しに使用できる認証トークンが表示されることに注意。 -
Liferay get user URL には
http://localhost:8080/o/headless-admin-user/v1.0/user-accounts
と入力します。 Get Data をクリックする。 React アプリは、トークン・ベースの認証を使用してLiferayにREST API呼び出しを行い、Liferayユーザーのリストを返します。
クライアント認証情報フロー
クライアント認証情報フローは、通常、サーバー間のやり取りに使用され、ユーザーは関与しません。
-
http://localhost:3000で実行中のReactアプリを開き、ページ上部の [Client Credentials Flow] をクリックします。
-
Liferay トークンの URL には
http://localhost:8080/o/oauth2/token
と入力してください。 クライアントIDとクライアントシークレットをクリップボードから貼り付けます。 [Get Token] をクリックします。 今後のREST API呼び出しに使用できる認証トークンが表示されることに注意。 -
Liferay get user URL には
http://localhost:8080/o/headless-admin-user/v1.0/user-accounts
と入力します。 Get Data をクリックする。 React アプリは、トークン・ベースの認証を使用してLiferayにREST API呼び出しを行い、Liferayユーザーのリストを返します。
パスワードフロー
パスワードフローの認証では、Reactアプリはユーザー名とパスワードをリクエストで直接渡します。
パスワードフローでは、ユーザー名とパスワードはアプリケーションに直接公開されます。 そのため、ユーザーはアプリケーションを信頼する必要があります。 APIリクエストでユーザー名とパスワードを渡すこともリスクを伴います。 パスワードフローを使用することは推奨されません。
-
http://localhost:3000で実行中のReactアプリを開き、ページ上部の [Password Flow] をクリックします。
-
Liferay トークンの URL には
http://localhost:8080/o/oauth2/token
と入力してください。 -
クライアントIDとクライアントシークレットをクリップボードから貼り付けます。
-
ユーザー名とパスワードを入力してください(例: test@liferay.com:learn)。
-
[Get Token] をクリックします。 今後のREST API呼び出しに使用できる認証トークンが表示されることに注意。
-
Liferay get user URL には
http://localhost:8080/o/headless-admin-user/v1.0/user-accounts
と入力します。 Get Data をクリックする。 React アプリは、トークン・ベースの認証を使用してLiferayにREST API呼び出しを行い、Liferayユーザーのリストを返します。
コードを調べる
Reactアプリの components
フォルダには、ボタンをクリックすることで発生するイベントを処理するためのUI要素とロジックが定義されています。 例えば、 Authorize.js
ファイルは認証ページにリダイレクトし、 Token.js
はアクセストークンを取得し、 Users.js
はユーザーのリストを取得します。 各認証フローは、これらのコンポーネントの一部または全部を使用する。
認証トークンを取得するAPIリクエストとGETリクエストは、 utils
フォルダ内の Requests.js
ファイルで定義されています。
src
├── components
│ ├── Authorize.js
│ ├── Token.js
│ ├── Users.js
├── routes
│ ├── grant-type-authorization-code
│ | ├── AuthorizationCode.js
│ ├── grant-type-client-credentials
│ | ├── ClientCredentials.js
│ ├── grant-type-password
│ | ├── Password.js
├── utils
│ ├── Requests.js
├── App.js
└── index.js
認証許可タイプ
grant-type-authorization-code
フローの AuthorizationCode.js
ファイルは、3つのコンポーネント(Authorize.js
、 Token.js
、 Users.js
)をすべて使用する。
<h1>Authorization Code Flow</h1>
Callback URI: http://localhost:3000/grant-type-authorization-code (or wherever the React app is running)
<br />
Scope: Headless Admin User (e.g. Liferay.Headless.Admin.User.everything.read)
<br />
CORS: Configure Portal CORS URL Pattern (e.g. /o/headless-admin-user/*)
<Authorize />
<Token
grantType='authorization_code'
handleToken={handleToken}
/>
<Users token={token} />
コードでは、 Authorize.js
コンポーネントが最初のステップを処理する。 [Authorize] ボタンをクリックすると、認証要求が行われます。
function Authorize() {
const [authUrl, setAuthUrl] = React.useState('');
const [clientId, setClientId] = React.useState('');
function handleAuthorize(event) {
event.preventDefault();
try {
window.location.replace(
authUrl + '?response_type=code&client_id=' + clientId
);
}
catch (error) {
throw new Error(error);
}
}
const urlSearchParams = new URLSearchParams(window.location.search);
var code = urlSearchParams.get('code');
return (
<div>
<h2>Authorize</h2>
<input
onChange={(event) => setAuthUrl(event.target.value)}
placeholder="Liferay Authorize URL"
style={{width: 500}}
type="text"
value={authUrl}
/>
(e.g. http://localhost:8080/o/oauth2/authorize)
<br />
<input
onChange={(event) => setClientId(event.target.value)}
placeholder="Client ID"
style={{width: 500}}
type="text"
value={clientId}
/>
<br />
<form onSubmit={handleAuthorize}>
<button type='onSubmit'>Authorize</button>
</form>
{code && (
<div>
<br />
Authorization Code:
<br />
{code}
</div>
)}
</div>
);
}
リダイレクトと同時に、ワンタイム認証コードがURL内でアプリに引き渡されます(例: http://localhost:3000/grant-type-authorization-code?code={code}
)。
Token.js
コンポーネントが次のステップを処理する。 [Get Token] をクリックすると、 Requests.js
ファイル内の getAuthToken
関数が呼び出されます。
import {getAuthToken} from '../utils/Requests';
function Token({handleToken, grantType}) {
const [clientId, setClientId] = React.useState('');
const [clientSecret, setClientSecret] = React.useState('');
const [password, setPassword] = React.useState('');
const [token, setToken] = React.useState('');
const [tokenUrl, setTokenUrl] = React.useState('');
const [username, setUsername] = React.useState('');
async function handleGetToken() {
const token = await getAuthToken({clientId, clientSecret, grantType, password, tokenUrl, username});
handleToken(token);
setToken(token);
}
return (
<div className='Token'>
<h2>Get Token</h2>
<input
onChange={(event) => setTokenUrl(event.target.value)}
placeholder="Liferay Token URL"
style={{width: 500}}
type="text"
value={tokenUrl}
/>
(e.g. http://localhost:8080/o/oauth2/token)
<br />
<input
onChange={(event) => setClientId(event.target.value)}
placeholder="Client ID"
style={{width: 500}}
type="text"
value={clientId}
/>
<br />
<input
onChange={(event) => setClientSecret(event.target.value)}
placeholder="Client Secret"
style={{width: 500}}
type="text"
value={clientSecret}
/>
<br />
{grantType === 'password' && (
<div>
<input
onChange={(client) => setUsername(client.target.value)}
placeholder="User Name"
style={{width: 500}}
type="text"
value={username}
/>
<br />
<input
onChange={(client) =>
setPassword(client.target.value)
}
placeholder="User Password"
style={{width: 500}}
type="text"
value={password}
/>
<br />
</div>
)}
<button onClick={handleGetToken}>Get Token</button>
{token && (
<div>
<br />
Authorization Token:
<br />
{token.access_token}
</div>
)}
</div>
);
}
Token.js
コンポーネントでは、パラメータ client_id
、 client_secret
、 code
、 grant_type
、 redirect_uri
がこのAPIリクエストで送信される。 パラメータが有効であれば、Liferayはアクセストークンを含むJSONレスポンスを返します。
応答例:
{
"access_token": "2fda85abec524112dae612d35e9f9abd71650d364dee47c645b7574c6bffe91",
"token_type": "Bearer",
"expires_in": 600,
"scope": "Liferay.Headless.Admin.User.everything.read"
}
Users.js
コンポーネントは、 access_token
のレスポンスを解析する。
最後に、 Get Data をクリックすると、 Requests.js
ファイル内の getUsers
関数が呼び出される。
クライアント認証情報許可タイプ
grant-type-client-credentials
フローの ClientCredentials.js
ファイルは、2つのコンポーネント(すなわち Token.js
と Users.js
)を使用する。
function ClientCredentials() {
const [token, setToken] = React.useState({});
function handleToken(token) {
setToken(token);
}
return (
<div>
<h1>Client Credentials Code Flow</h1>
Scope: Headless Admin User (e.g. Liferay.Headless.Admin.User.everything.read)
<br />
CORS: Configure Portal CORS URL Pattern (e.g. /o/headless-admin-user/*)
<Token
grantType='client_credentials'
handleToken={handleToken}
/>
<Users token={token} />
</div>
);
}
Token.js
コンポーネントでは、パラメータ client_id
、 client_secret
、 grant_type
がAPIリクエストで送信される。 パラメータが有効であれば、Liferayはアクセストークンを含むJSONレスポンスを返します。
Users.js
コンポーネントは、 access_token
のレスポンスを解析する。
最後に、 Get Data をクリックすると、 Requests.js
ファイル内の getUsers
関数が呼び出される。
パスワード許可タイプ
grant-type-password
フローの Password.js
ファイルは、2つのコンポーネント(すなわち、 Token.js
と Users.js
)を使用している。
function Password() {
const [token, setToken] = React.useState({});
function handleToken(token) {
setToken(token);
}
return (
<div>
<h1>Password Flow</h1>
Scope: Headless Admin User (e.g. Liferay.Headless.Admin.User.everything.read)
<br />
CORS: Configure Portal CORS URL Pattern (e.g. /o/headless-admin-user/*)
<Token
grantType='password'
handleToken={handleToken}
/>
<Users token={token} />
</div>
);
}
Token.js
コンポーネントでは、パラメータ client_id
, client_secret
, grant_type
, password
, username
がAPIリクエストのパラメータとして送信される。 パラメータが有効であれば、Liferayサーバーはアクセストークンを含むJSONレスポンスを返します。
Users.js
コンポーネントは、 access_token
のレスポンスを解析する。
最後に、 Get Data をクリックすると、 Requests.js
ファイル内の getUsers
関数が呼び出される。