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:2025.q1.6-lts
メールアドレス test@liferay.com とパスワード testを使用して、 http://localhost:8080 で Liferay にサインインします。 プロンプトが表示されたら、パスワードを learnに変更します。
-
グローバル メニュー (
) を開き、 コントロール パネル → セキュリティ → OAuth 2 管理に移動します。 -
新規をクリックします。
-
アプリケーションに名前をつけます(例:foo)。 ウェブサイトの URL を
http://localhost:3000に設定し、コールバック URI をhttp://localhost:3000/grant-type-authorization-codeに設定します。 [保存]をクリックします。
-
クライアントIDとクライアントシークレットをクリップボードにコピーします。 クライアントシークレットを取得するには、 編集をクリックします。 ポップアップウィンドウから値をコピーします。
これらの値は、サンプルのReactアプリで後ほど必要になります。
-
ページ上部の スコープ タブをクリックします。 下にスクロールして、 LIFERAY.HEADLESS.ADMIN.USERをクリックし、 あなたに代わってデータを読み取るのボックスをオンにします。

[保存]をクリックします。 OAuth2アプリケーションに、管理者ユーザーAPIカテゴリの読み取り権限が付与されました。
-
次に、 グローバル メニュー (
) を開き、 コントロール パネル → システム設定 → セキュリティ ツールに移動します。 -
[Portal Cross-Origin Resource Sharing (CORS)]タブで、 [Default Portal CORS Configuration]をクリックしてください。
-
値
/o/headless-admin-user/*を持つ URL パターン を追加します。 -
[保存]をクリックします。 これにより、API の
headless-admin-userカテゴリに対して CORS が有効になります。
サンプルReactアプリをデプロイする
-
OAuth2 React Appをダウンロードして解凍します。
curl https://resources.learn.liferay.com/examples/liferay-c2b6.zip -Ounzip liferay-c2b6.zipcd liferay-c2b6 -
nodeとyarnがインストールされていることを確認します。 そうでない場合は、セットアップスクリプトを実行し、プロンプトに従います。./setup_tutorial.sh -
アプリのルート ディレクトリに移動し、React サーバーを起動します。
cd c2b6-custom-elementyarn install && yarn start
認証コードのフロー
認証コードフローでは、アプリケーションに権限を与える前に、ユーザーが認証情報でログインし、認証を承認する必要があります。 他のフローでは、この追加ステップを回避することができます。
-
http://localhost:3000で実行されている React アプリを開き、ページの上部にある Authorization Code Flow をクリックします。
-
Liferay 承認 URL として
http://localhost:8080/o/oauth2/authorizeを入力します。 クリップボードからクライアント ID を貼り付けます。 承認をクリックします。 -
まだログインしていない場合、認証ページに移動する前にLiferayのログインページにリダイレクトされます。 ユーザー名とパスワード(例: test@liferay.com:learn)を入力し、 [サインイン]をクリックします。 認証ページで、 [認証する]をクリックします。 すでにログインしている場合は、認証ページに直接移動します。
![アプリケーションを承認するには、[承認] をクリックします。](https://resources.learn.liferay.com/images/dxp/latest/en/integration/headless-apis/using-liferay-as-a-headless-platform/using-oauth2/using-oauth2-to-authorize-users/images/03.png)
Reactアプリにリダイレクトされます。 次の API 呼び出しを行うために使用される承認コードが表示されることに注意してください。
-
Liferay トークン URL として
http://localhost:8080/o/oauth2/tokenを入力します。 クリップボードからクライアント ID とクライアント シークレットを貼り付けます。 トークンを取得をクリックします。 今後の REST API 呼び出しに使用できる認証トークンが表示されることに注意してください。注同じインスタンスでトークンを要求する場合、Liferay はネットワーク トラフィックを生成しません。
-
Liferay のユーザー取得 URL として
http://localhost:8080/o/headless-admin-user/v1.0/user-accountsと入力します。 [データの取得]をクリックします。 React アプリは、トークン・ベースの認証を使用してLiferayにREST API呼び出しを行い、Liferayユーザーのリストを返します。
クライアント認証情報フロー
クライアント認証情報フローは、通常、サーバー間のやり取りに使用され、ユーザーは関与しません。
-
http://localhost:3000で実行されている React アプリを開き、ページの上部にある クライアント資格情報フロー をクリックします。
-
Liferay トークン URL として
http://localhost:8080/o/oauth2/tokenを入力します。 クリップボードからクライアント ID とクライアント シークレットを貼り付けます。 トークンを取得をクリックします。 今後の REST API 呼び出しに使用できる認証トークンが表示されることに注意してください。 -
Liferay のユーザー取得 URL として
http://localhost:8080/o/headless-admin-user/v1.0/user-accountsと入力します。 [データの取得]をクリックします。 React アプリは、トークン・ベースの認証を使用してLiferayにREST API呼び出しを行い、Liferayユーザーのリストを返します。
パスワードフロー
パスワードフローの認証では、Reactアプリはユーザー名とパスワードをリクエストで直接渡します。
パスワードフローでは、ユーザー名とパスワードはアプリケーションに直接公開されます。 そのため、ユーザーはアプリケーションを信頼する必要があります。 APIリクエストでユーザー名とパスワードを渡すこともリスクを伴います。 パスワードフローを使用することは推奨されません。
-
http://localhost:3000で実行されている React アプリを開き、ページの上部にある パスワード フロー をクリックします。
-
Liferay トークン URL として
http://localhost:8080/o/oauth2/tokenを入力します。 -
クリップボードからクライアント ID とクライアント シークレットを貼り付けます。
-
ユーザー名とパスワードを入力します(例: test@liferay.com:learn)。
-
トークンを取得をクリックします。 今後の REST API 呼び出しに使用できる認証トークンが表示されることに注意してください。
-
Liferay のユーザー取得 URL として
http://localhost:8080/o/headless-admin-user/v1.0/user-accountsと入力します。 [データの取得]をクリックします。 React アプリは、トークン・ベースの認証を使用してLiferayにREST API呼び出しを行い、Liferayユーザーのリストを返します。
コードを調べる
React アプリの コンポーネント フォルダーは、ボタンをクリックすることで発生するイベントを処理するための 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のレスポンスを解析します。
最後に、 [データを取得] をクリックすると、 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のレスポンスを解析します。
最後に、 [データを取得] をクリックすると、 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のレスポンスを解析します。
最後に、 [データを取得] をクリックすると、 Requests.js ファイル内の getUsers 関数が呼び出されます。