The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.
このページを編集

JDBCと共にSecurityを使用

このガイドでは、Quarkusアプリケーションがデータベースを使用してユーザーIDを保存する方法を説明します。

前提条件

このガイドを完成させるには、以下が必要です:

  • 約15分

  • IDE

  • JDK 17+がインストールされ、 JAVA_HOME が適切に設定されていること

  • Apache Maven 3.9.9

  • 使用したい場合は、 Quarkus CLI

  • ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること

アーキテクチャ

この例では、3つのエンドポイントを提供する非常にシンプルなマイクロサービスを構築します:

  • /api/public

  • /api/users/me

  • /api/admin

/api/public エンドポイントは匿名でアクセスできます。 /api/admin エンドポイントは RBAC (Role-Based Access Control) で保護されており、 admin の役割を与えられたユーザーのみがアクセスできます。このエンドポイントでは、 @RolesAllowed アノテーションを使用して、アクセス制約を宣言的に強制します。 /api/users/me エンドポイントも RBAC (Role-Based Access Control) で保護されており、 user ロールで付与されたユーザーのみがアクセスできます。レスポンスとして、ユーザーに関する詳細を含むJSONドキュメントを返します。

ソリューション

次の章で紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、完成した例にそのまま進んでも構いません。

Gitレポジトリをクローンするか git clone https://github.com/quarkusio/quarkus-quickstarts.gitアーカイブ をダウンロードします。

ソリューションは security-jdbc-quickstart ディレクトリ にあります。

Mavenプロジェクトの作成

まず、新しいプロジェクトが必要です。以下のコマンドで新規プロジェクトを作成します。

コマンドラインインタフェース
quarkus create app org.acme:security-jdbc-quickstart \
    --extension='elytron-security-jdbc,jdbc-postgresql,rest' \
    --no-code
cd security-jdbc-quickstart

Gradleプロジェクトを作成するには、 --gradle または --gradle-kotlin-dsl オプションを追加します。

Quarkus CLIのインストールと使用方法の詳細については、 Quarkus CLI ガイドを参照してください。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:3.18.4:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=security-jdbc-quickstart \
    -Dextensions='elytron-security-jdbc,jdbc-postgresql,rest' \
    -DnoCode
cd security-jdbc-quickstart

Gradleプロジェクトを作成するには、 -DbuildTool=gradle または -DbuildTool=gradle-kotlin-dsl オプションを追加します。

Windowsユーザーの場合:

  • cmdを使用する場合、(バックスラッシュ \ を使用せず、すべてを同じ行に書かないでください)。

  • Powershellを使用する場合は、 -D パラメータを二重引用符で囲んでください。例: "-DprojectArtifactId=security-jdbc-quickstart"

選択したデータベースコネクタライブラリを追加することを忘れないでください。ここでは、PostgreSQLをIDストアとして使用しています。

このコマンドは新しいプロジェクトを生成し、 elytron-security-jdbc エクステンションをインポートします。これはQuarkusアプリケーション用の wildfly-elytron-realm-jdbc アダプターです。

すでにQuarkusプロジェクトが設定されている場合は、プロジェクトのベースディレクトリーで以下のコマンドを実行することで、プロジェクトに elytron-security-jdbc エクステンションを追加することができます:

コマンドラインインタフェース
quarkus extension add elytron-security-jdbc
Maven
./mvnw quarkus:add-extension -Dextensions='elytron-security-jdbc'
Gradle
./gradlew addExtension --extensions='elytron-security-jdbc'

これにより、ビルドファイルに以下が追加されます:

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-elytron-security-jdbc</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-elytron-security-jdbc")

アプリケーションの記述

まず、 /api/public のエンドポイントを実装することから始めましょう。以下のソースコードからわかるように、これは通常のJakarta RESTリソースに過ぎません:

package org.acme.security.jdbc;

import jakarta.annotation.security.PermitAll;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/api/public")
public class PublicResource {

    @GET
    @PermitAll
    @Produces(MediaType.TEXT_PLAIN)
    public String publicResource() {
        return "public";
   }
}

/api/admin エンドポイントのソースコードも非常にシンプルです。ここでの主な違いは、 admin ロールで付与されたユーザーだけがエンドポイントにアクセスできるように @RolesAllowed アノテーションを使用していることです:

package org.acme.security.jdbc;

import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/api/admin")
public class AdminResource {

    @GET
    @RolesAllowed("admin")
    @Produces(MediaType.TEXT_PLAIN)
    public String adminResource() {
         return "admin";
    }
}

最後に、 /api/users/me エンドポイントを考えてみましょう。下のソースコードを見ればわかるように、 user のロールを持つユーザのみを信頼しています。現在の認証されているプリンシパルへのアクセスを得るために SecurityContext を使用しており、ユーザーの名前を返します。この情報はデータベースから読み込まれます。

package org.acme.security.jdbc;

import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.SecurityContext;

@Path("/api/users")
public class UserResource {

    @GET
    @RolesAllowed("user")
    @Path("/me")
    public String me(@Context SecurityContext securityContext) {
        return securityContext.getUserPrincipal().getName();
    }
}

アプリケーションの設定

elytron-security-jdbc エクステンションは、データベースにアクセスするために少なくとも一つのデータソースが必要です。

quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=quarkus
quarkus.datasource.password=quarkus
quarkus.datasource.jdbc.url=jdbc:postgresql:elytron-security-jdbc

この例では、PostgreSQLをIDストアとして使用し、ユーザとロールでデータベースを初期化します。 この例では、 password の塩漬けとハッシュ化したものをパスワードとして使用します。 BcryptUtil クラスを使用して、MCF(Modular Crypt Format)形式のパスワードを生成することができます。

CREATE TABLE test_user (
  id INT,
  username VARCHAR(255),
  password VARCHAR(255),
  role VARCHAR(255)
);

INSERT INTO test_user (id, username, password, role) VALUES (1, 'admin', '$2a$10$Uc.SZ0hvGJQlYdsAp7be1.lFjmOnc7aAr4L0YY3/VN3oK.F8zJHRG', 'admin');
INSERT INTO test_user (id, username, password, role) VALUES (2, 'user','$2a$10$Uc.SZ0hvGJQlYdsAp7be1.lFjmOnc7aAr4L0YY3/VN3oK.F8zJHRG', 'user');

新規ユーザーを登録する際、以下のようにパスワードを暗号化することができます:

package org.acme.security.jdbc;

import io.quarkus.elytron.security.common.BcryptUtil;

public class AccountService {

    public void signupUser(String username, String password) {
        String encryptedPassword = BcryptUtil.bcryptHash(password);

        // store user with the encrypted password in the database
    }
}

これで、Elytron JDBC Realmを設定することができます。

quarkus.security.jdbc.enabled=true
quarkus.security.jdbc.principal-query.sql=SELECT u.password, u.role FROM test_user u WHERE u.username=? (1)
quarkus.security.jdbc.principal-query.bcrypt-password-mapper.enabled=true (2)
quarkus.security.jdbc.principal-query.bcrypt-password-mapper.password-index=1
quarkus.security.jdbc.principal-query.attribute-mappings.0.index=2 (3)
quarkus.security.jdbc.principal-query.attribute-mappings.0.to=groups

elytron-security-jdbc エクステンションは、ユーザーとそのアイデンティティを認証するために、少なくとも一つのプリンシパルのクエリを必要とします。

1 ユーザーのパスワードと、ロードしたい追加情報を返却するパラメーター化されたSQL文(単一のパラメーター付)を定義しています。
2 パスワードマッパーは、 SELECT フィールドのパスワードフィールドの位置で設定されます。ハッシュはモジュラークリプトフォーマット(MCF)に格納されます。これはソルトと反復回数のインデックスがデフォルトで -1 に設定されているからです。各要素を3つの別々のカラムに分解するために、それらをオーバーライドすることができます。
3 attribute-mappings を使用して、 SELECT の射影フィールド(例:ここでは u.role )をターゲットの Principal 表現の属性にバインドしています。

principal-query の設定では、 index のプロパティーはすべて 1 から始まります (0 ではなく)。

アプリケーションのテスト

アプリケーションが保護され、アイデンティティがデータベースから提供されるようになりました。非常に最初に確認しなければならないことは、匿名アクセスが機能することを確認することです。

$ curl -i -X GET http://localhost:8080/api/public
HTTP/1.1 200 OK
Content-Length: 6
Content-Type: text/plain;charset=UTF-8

public%

では、匿名で保護されたリソースを攻撃してみましょう。

$ curl -i -X GET http://localhost:8080/api/admin
HTTP/1.1 401 Unauthorized
Content-Length: 14
Content-Type: text/html;charset=UTF-8

Not authorized%

ここまでは順調ですが、今度は許可されたユーザーで試してみましょう。

$ curl -i -X GET -u admin:password http://localhost:8080/api/admin
HTTP/1.1 200 OK
Content-Length: 5
Content-Type: text/plain;charset=UTF-8

admin%

admin:password クレデンシャルを提供することで、エクステンションはユーザーを認証し、そのロールをロードします。 admin ユーザは保護されたリソースへのアクセスが許可されます。

ユーザー admin は、この役割を持っていないので、 @RolesAllowed("user") で保護されたリソースへのアクセスを禁止する必要があります。

$ curl -i -X GET -u admin:password http://localhost:8080/api/users/me
HTTP/1.1 403 Forbidden
Content-Length: 34
Content-Type: text/html;charset=UTF-8

Forbidden%

最後に、ユーザー user を使用すると動作し、セキュリティーコンテキストには主要な詳細(例えばユーザー名)が含まれています。

$ curl -i -X GET -u user:password http://localhost:8080/api/users/me
HTTP/1.1 200 OK
Content-Length: 4
Content-Type: text/plain;charset=UTF-8

user%

高度な設定

このガイドでは、簡単な使用例のみを取り上げていますが、このエクステンションは複数のデータソース、複数のプリンシパルクエリの設定、および bcrypt パスワードマッパーを提供しています。

quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=quarkus
quarkus.datasource.password=quarkus
quarkus.datasource.jdbc.url=jdbc:postgresql:multiple-data-sources-users

quarkus.datasource.permissions.db-kind=postgresql
quarkus.datasource.permissions.username=quarkus
quarkus.datasource.permissions.password=quarkus
quarkus.datasource.permissions.jdbc.url=jdbc:postgresql:multiple-data-sources-permissions

quarkus.security.jdbc.enabled=true
quarkus.security.jdbc.principal-query.sql=SELECT u.password FROM test_user u WHERE u.username=?
quarkus.security.jdbc.principal-query.bcrypt-password-mapper.enabled=true
quarkus.security.jdbc.principal-query.bcrypt-password-mapper.password-index=1

quarkus.security.jdbc.principal-query.roles.sql=SELECT r.role_name FROM test_role r, test_user_role ur WHERE ur.username=? AND ur.role_id = r.id
quarkus.security.jdbc.principal-query.roles.datasource=permissions
quarkus.security.jdbc.principal-query.roles.attribute-mappings.0.index=1
quarkus.security.jdbc.principal-query.roles.attribute-mappings.0.to=groups

設定リファレンス

ビルド時に固定される構成プロパティ - 他のすべての構成プロパティは実行時にオーバーライド可能

Configuration property

デフォルト

The realm name

Environment variable: QUARKUS_SECURITY_JDBC_REALM_NAME

Show more

string

Quarkus

If the properties store is enabled.

Environment variable: QUARKUS_SECURITY_JDBC_ENABLED

Show more

boolean

false

The sql query to find the password

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_SQL

Show more

string

The data source to use

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_DATASOURCE

Show more

string

If the clear-password-mapper is enabled.

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_CLEAR_PASSWORD_MAPPER_ENABLED

Show more

boolean

false

The index (1 based numbering) of the column containing the clear password

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_CLEAR_PASSWORD_MAPPER_PASSWORD_INDEX

Show more

int

1

If the bcrypt-password-mapper is enabled.

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_BCRYPT_PASSWORD_MAPPER_ENABLED

Show more

boolean

false

The index (1 based numbering) of the column containing the password hash

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_BCRYPT_PASSWORD_MAPPER_PASSWORD_INDEX

Show more

int

0

A string referencing the password hash encoding ("BASE64" or "HEX")

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_BCRYPT_PASSWORD_MAPPER_HASH_ENCODING

Show more

base64, hex

base64

The index (1 based numbering) of the column containing the Bcrypt salt. The default value of -1 implies that the salt is stored in the password column using the Modular Crypt Format (MCF) standard.

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_BCRYPT_PASSWORD_MAPPER_SALT_INDEX

Show more

int

-1

A string referencing the salt encoding ("BASE64" or "HEX")

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_BCRYPT_PASSWORD_MAPPER_SALT_ENCODING

Show more

base64, hex

base64

The index (1 based numbering) of the column containing the Bcrypt iteration count. The default value of -1 implies that the iteration count is stored in the password column using the Modular Crypt Format (MCF) standard.

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_BCRYPT_PASSWORD_MAPPER_ITERATION_COUNT_INDEX

Show more

int

-1

The index (1 based numbering) of column to map

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_ATTRIBUTE_MAPPINGS__ATTRIBUTE_MAPPINGS__INDEX

Show more

int

0

The target attribute name

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY_ATTRIBUTE_MAPPINGS__ATTRIBUTE_MAPPINGS__TO

Show more

string

required

Named queries

デフォルト

The sql query to find the password

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__QUERY_NAME__SQL

Show more

string

The data source to use

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__QUERY_NAME__DATASOURCE

Show more

string

The index (1 based numbering) of column to map

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__QUERY_NAME__ATTRIBUTE_MAPPINGS__ATTRIBUTE_MAPPINGS__INDEX

Show more

int

0

The target attribute name

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__QUERY_NAME__ATTRIBUTE_MAPPINGS__ATTRIBUTE_MAPPINGS__TO

Show more

string

required

If the clear-password-mapper is enabled.

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__QUERY_NAME__CLEAR_PASSWORD_MAPPER_ENABLED

Show more

boolean

false

The index (1 based numbering) of the column containing the clear password

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__QUERY_NAME__CLEAR_PASSWORD_MAPPER_PASSWORD_INDEX

Show more

int

1

If the bcrypt-password-mapper is enabled.

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__QUERY_NAME__BCRYPT_PASSWORD_MAPPER_ENABLED

Show more

boolean

false

The index (1 based numbering) of the column containing the password hash

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__QUERY_NAME__BCRYPT_PASSWORD_MAPPER_PASSWORD_INDEX

Show more

int

0

A string referencing the password hash encoding ("BASE64" or "HEX")

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__QUERY_NAME__BCRYPT_PASSWORD_MAPPER_HASH_ENCODING

Show more

base64, hex

base64

The index (1 based numbering) of the column containing the Bcrypt salt. The default value of -1 implies that the salt is stored in the password column using the Modular Crypt Format (MCF) standard.

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__QUERY_NAME__BCRYPT_PASSWORD_MAPPER_SALT_INDEX

Show more

int

-1

A string referencing the salt encoding ("BASE64" or "HEX")

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__QUERY_NAME__BCRYPT_PASSWORD_MAPPER_SALT_ENCODING

Show more

base64, hex

base64

The index (1 based numbering) of the column containing the Bcrypt iteration count. The default value of -1 implies that the iteration count is stored in the password column using the Modular Crypt Format (MCF) standard.

Environment variable: QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__QUERY_NAME__BCRYPT_PASSWORD_MAPPER_ITERATION_COUNT_INDEX

Show more

int

-1

関連コンテンツ