メインコンテンツへスキップ
このチュートリアルは、Java EE Webアプリケーションにユーザーログインを追加する方法について説明します。ログインして、アカウント用に構成された例を参考にこのクイックタートに従うことをお勧めします。
1

システム要件

このチュートリアルとサンプルプロジェクトは次を使用してテストが完了しています:
  • Java 11
2

Auth0を構成する

アプリケーションキーを取得する

Auth0にサインアップしたときには、新しいアプリケーションが作成されたか、すでに作成済みであった可能性があります。Auth0と通信するには、アプリケーションについての詳細が必要になります。これらの詳細は、Auth0 Dashboardのアプリケーションの設定セクションで入手できます。
以下の情報が必要です。
  • Domain (ドメイン)
  • Client ID(クライアントID)
  • Client Secret(クライアントシークレット)
このページの上部からサンプルをダウンロードした場合は、これらの詳細が入力されます。

Callback URLを構成する

Callback URLはアプリケーション内にあるURLで、Auth0は認証後にユーザーをここにリダイレクトします。アプリのCallback URLはアプリケーションの設定にある**[Allowed Callback URLs(許可されているコールバックURL)]**フィールドに追加する必要があります。このフィールドが設定されていない場合、ユーザーはアプリケーションにログインできず、エラーが返されます。
このページの上部からダウンロードしたサンプルプロジェクトに沿って進めている場合には、**[Allowed Callback URLs(許可されているコールバックURL)]**フィールドにhttp://localhost:3000/callbackを追加する必要があります。

ログアウトURLを構成する

ログアウトURLはアプリケーション内にあるURLで、Auth0は認可サーバーからのログアウト後にユーザーをここに戻すことができます。これは、returnToクエリパラメーターで指定されます。アプリのログアウトURLはアプリケーションの設定にある**[Allowed Logout URLs(許可されているログアウトURL)]**フィールドに追加する必要があります。このフィールドが設定されていない場合、ユーザーはアプリケーションからログアウトできず、エラーが返されます。
このページの上部からダウンロードしたサンプルプロジェクトに沿って進めている場合には、**[Allowed Logout URLs(許可されているログアウトURL)]**フィールドにhttp://localhost:3000/を追加する必要があります。
3

JavaEEにAuth0の使用を構成する

依存関係をセットアップする

Java EEアプリケーションをAuth0と統合するには、以下の依存関係を追加します。
  • javax.javaee-api :Java EE 8を使ってアプリケーションを作成するために必要なJava EE 8 APIです。実際の統合はアプリケーションコンテナーが提供するため、WARファイルに含める必要はありません。
  • javax.security.enterprise :EEアプリケーションでセキュリティ上の懸念に対処できるようにするJava EE 8 Security APIです。javax.javaee-apiの依存関係と同様に、統合はアプリケーションコンテナーが提供するため、WARファイルには含まれません。
  • auth0-java-mvc-commonsAuth0 Java MVC SDKは、サーバー側のMVC WebアプリケーションにAuth0とJavaを使用できるようにします。これは、アプリケーションがAuth0を使ったユーザー認証で呼び出すべき認可URLを生成します。
Mavenを使用している場合は、次の依存関係をpom.xmlに追加します:
<!-- pom.xml -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>mvc-auth-commons</artifactId>
<version>[1.0, 2.0)</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.security.enterprise</groupId>
<artifactId>javax.security.enterprise-api</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
Gradleを使用している場合は、次をbuild.gradleに追加します:
// build.gradle
providedCompile 'javax:javaee-api:8.0.1'
providedCompile 'javax.security.enterprise:javax.security.enterprise-api:1.0'
implementation 'com.auth0:mvc-auth-commons:1. '

Java EEアプリケーションを構成する

このチュートリアルに付属のサンプルはJSPを使用して作成され、WildFlyアプリケーションサーバーでテストが完了しています。他のアプリケーションコンテナーや技術を使用して作業する場合には、一部の手順を調整する必要があるかもしれません。
Java EEアプリケーションは、Auth0アプリケーションを使ってユーザーを認証するために、いくつかの情報を必要とします。この情報の保管にはデプロイメント記述子であるweb.xmlファイルを使用できますが、別の安全な場所に保管することもできます。この情報は、ユーザーがアプリケーションにログインできるように、auth0-java-mvc-commons ライブラリーを構成するために使用されます。ライブラリーとその構成オプションについては、ライブラリーのREADMEを参照してください。
4

Java EE Securityを構成する

Java EE 8 Security APIには新たにHttpAuthenticationMechanismインターフェイスが搭載され、アプリケーションがユーザーの資格情報を取得できるようにしています。Basic認証とフォームベースの認証にはデフォルトの実装があり、カスタム認証ストラテジーを構成しやすくしています。Auth0を使用して認証するには、以下のインターフェイスをカスタムで実装します。
  • HttpAuthenticationMechanism:Auth0から戻されるユーザーの認証ワークフローを処理します(JavaDoc)。
  • IdentityStore:ユーザーの資格情報を検証します(JavaDoc)。
  • CallerPrincipal:現在のHTTP要求の呼び出し元プリンシパルを表します(JavaDoc)。
  • Credential:呼び出し元が認証に使用する資格情報を表します(JavaDoc)。
まず、アプリケーションがAuth0設定を使用できるように、@ApplicationScoped Beanを作成してWebコンテキストから値を取得し、getterを通して利用できるようにします。次に、現在の要求の呼び出し元を表すカスタムのCallerPrincipalを作成します:
// src/main/java/com/auth0/example/security/Auth0JwtPrincipal.java
public class Auth0JwtPrincipal extends CallerPrincipal {
private final DecodedJWT idToken;



Auth0JwtPrincipal(DecodedJWT idToken) {

    super(idToken.getClaim(&quot;name&quot;).asString());

    this.idToken = idToken;

}



public DecodedJWT getIdToken() {

    return this.idToken;

}

}
これで、ユーザーの資格情報を表すために使用されるカスタムのCredentialが実装できるようになりました。これには、プリンシパルについての情報が保管されます:
// src/main/java/com/auth0/example/security/Auth0JwtCredential.java
class Auth0JwtCredential implements Credential {
private Auth0JwtPrincipal auth0JwtPrincipal;



Auth0JwtCredential(String token) {

    DecodedJWT decodedJWT = JWT.decode(token);

    this.auth0JwtPrincipal = new Auth0JwtPrincipal(decodedJWT);

}



Auth0JwtPrincipal getAuth0JwtPrincipal() {

    return auth0JwtPrincipal;

}

}
これで、呼び出し元プリンシパルと資格情報を表すクラスが定義できました。次に、IdentityStoreのカスタム実装を作成します。このクラスはユーザー資格情報の検証に使用されます。
// src/main/java/com/auth0/example/security/Auth0JwtIdentityStore.java
@ApplicationScoped
public class Auth0JwtIdentityStore implements IdentityStore {
@Override

public CredentialValidationResult validate(final Credential credential) {

    CredentialValidationResult result = CredentialValidationResult.NOT_VALIDATED_RESULT;

    if (credential instanceof Auth0JwtCredential) {

        Auth0JwtCredential auth0JwtCredential = (Auth0JwtCredential) credential;

        result = new CredentialValidationResult(auth0JwtCredential.getAuth0JwtPrincipal());

    }

    return result;

}

}
credentialAuth0Credentialの場合はユーザーの呼び出しが認証され有効であるため、正常として、資格情報を使って作成されたCredentialValidationResultが返されます。Auth0Credentialでない場合には、CredentialValidationResult.NOT_VALIDATED_RESULTが返されます。これらのすべてを使用するHttpAuthenticationMechanismインターフェイスを実装する前に、Beanを作成して、Auth0 Java MVC SDKにある構成済みのAuthenticationControllerインスタンスが提供されるようにします。AuthenticationControllerはユーザーがログインする認可URLの構築と、ユーザーを認証するトークン交換の処理に使用されます。
  • Auth0アプリケーションにRS256署名アルゴリズム (新しいAuth0アプリケーション作成時のデフォルト)の使用が構成されている場合には、JwkProviderを構成して、トークン署名の検証に使われる公開鍵を取得するようにします。その他の構成オプションについては、jwks-rsa-javaレポジトリを参照してください。
  • Auth0アプリケーションにHS256署名アルゴリズム の使用が構成されている場合には、JwkProviderを構成する必要はありません。
使用可能な署名アルゴリズムについては、こちらのドキュメントを参照してください。
以下のサンプルは、RS256署名アルゴリズム の使用にAuthenticationControllerをどのように構成するのかを示しています。
// src/main/java/com/auth0/example/security/Auth0AuthenticationProvider.java
@ApplicationScoped
public class Auth0AuthenticationProvider {
@Produces

public AuthenticationController authenticationController(Auth0AuthenticationConfig config) {

    JwkProvider jwkProvider = new JwkProviderBuilder(config.getDomain()).build();

    return AuthenticationController.newBuilder(config.getDomain(), config.getClientId(), config.getClientSecret())

            .withJwkProvider(jwkProvider)

            .build();

}

}
最後に、カスタムのHttpAuthenticationMechanismを実装します。
// src/main/java/com/auth0/example/security/Auth0AuthenticationMechanism.java
@ApplicationScoped
@AutoApplySession
public class Auth0AuthenticationMechanism implements HttpAuthenticationMechanism {
private final AuthenticationController authenticationController;

private final IdentityStoreHandler identityStoreHandler;



@Inject

Auth0AuthenticationMechanism(AuthenticationController authenticationController, IdentityStoreHandler identityStoreHandler) {

    this.authenticationController = authenticationController;

    this.identityStoreHandler = identityStoreHandler;

}



@Override

public AuthenticationStatus validateRequest(HttpServletRequest httpServletRequest,

                                            HttpServletResponse httpServletResponse,

                                            HttpMessageContext httpMessageContext) throws AuthenticationException {



    // Exchange the code for the ID token, and notify container of result.

    if (isCallbackRequest(httpServletRequest)) {

        try {

            Tokens tokens = authenticationController.handle(httpServletRequest, httpServletResponse);

            Auth0JwtCredential auth0JwtCredential = new Auth0JwtCredential(tokens.getIdToken());

            CredentialValidationResult result = identityStoreHandler.validate(auth0JwtCredential);

            return httpMessageContext.notifyContainerAboutLogin(result);

        } catch (IdentityVerificationException e) {

            return httpMessageContext.responseUnauthorized();

        }

    }

    return httpMessageContext.doNothing();

}



private boolean isCallbackRequest(HttpServletRequest request) {

    return request.getRequestURI().equals(&quot;/callback&quot;) &amp;&amp; request.getParameter(&quot;code&quot;) != null;

}

}
このクラスはvalidateRequestメソッドをオーバーライドします。このメソッドはAuth0アプリケーションに対するすべての要求で呼び出され、コンテナーに認証ステータスを通知します。このサンプルでは、認可コードフローを使用して、認証フロー中に認可コードをトークンと交換します。この要求が/callbackエンドポイントに対するもので、code要求パラメーターが含まれている場合には、以下にあるいくつかの重要な処理を行います。
  • AuthenticationControllerhandleメソッドを呼び出して、認可コードをIDトークンおよびアクセストークンと交換する。
  • IDトークンを使用して、新たにAuth0Credentialを作成する。
  • カスタムのIdentityStore実装のvalidateメソッドを呼び出して、検証結果を取得する。
  • アプリケーションコンテナーにログインステータスを通知する。
要求されたリソースが/callbackでない場合には、httpMessageContext.doNothing()を返して、要求の処理が続行できるようにします。後ほど、認証のトリガーやWebビューの表示で認証情報をどのように使用するかについて説明します。最後に、認証したユーザーのセッションをコンテナーが作成できるように、@AutoApplySessionアノテーションが追加されたことに注意してください。
5

認証をトリガーする

ユーザーがログインできるようにするには、/loginパスへの要求を処理するサーブレットを作成します。LoginControllerは、ユーザーがAuth0で認証できるように、正しい認可URLに要求をリダイレクトします。正しい認可URLの構築には、Auth0AuthenticationConfigを通して投入された構成値と、Auth0 Java MVC SDKが提供するAuthenticationControllerが使用されます。このサンプルはデフォルトでopenid profile emailスコープを要求して、アプリケーションが基本的なプロファイル情報を認証済みのユーザーから取得できるようにします。これらのスコープについては、OpenID Connectスコープのドキュメントをお読みください。ユーザーが資格情報を入力し、要求されたアクセス権を認可すると、Auth0はcallbackUrlに対して要求を発行し、IDトークンおよびアクセストークンと交換できるcodeクエリパラメーターを含めます。先ほど説明したように、上記で作成したAuth0HttpAuthenticationMechanismがこの交換を処理し、アプリケーションコンテナーに認証ステータスを通知できるようにします。そうすることで、/callbackパスへの要求を処理するサーブレットは、ログイン前に要求された元のリソースに要求を転送するか、ホームページにリダイレクトするだけで済みます。
// src/main/com/auth0/example/web/CallbackServlet.java
@WebServlet(urlPatterns = {"/callback"})
public class CallbackServlet extends HttpServlet {
@Override

public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {

    String referer = (String) request.getSession().getAttribute(&quot;Referer&quot;);

    String redirectTo = referer != null ? referer : &quot;/&quot;;



    response.sendRedirect(redirectTo);

}

}
6

ユーザー情報を表示する

認証したユーザーのプロファイル情報を取得するには、Auth0JwtPrincipalを使用することができます。HomeServlet.javaのサンプルコードでは、IDトークンでクレームを使ってプロファイルデータを要求属性に設定する方法を例示しています。そのプロファイル情報は、ユーザーについての情報を表示するビューで使用できます。
<!-- src/main/webapp/WEB-INF/jsp/fragments/navbar.jspf -->
<c:choose>
<c:when test="{empty profile}">
<li>
<form action="/login" method="GET">
<input type="submit" value="Login"/>
</form>
</li>
</c:when>
<c:otherwise>
<li>
<a href="#">
<!-- Profile image should be set to the profile picture from the id token -->
<img src="{profile.get('picture').asString()}" alt="Profile picture"/>
</a>
<div>
<!-- Show the user's full name from the id token here -->
<div>"{profile.get('name').asString()}"</div>
<a href="/profile">Profile</a>
<a href="/logout">Log out</a>
</div>
</li>
</c:otherwise>
</c:choose>
7

ログアウトを処理する

ユーザーをログアウトさせるには、アプリケーションセッションを消去して、Auth0からユーザーをログアウトさせる必要があります。これはLogoutServletで処理されます。まず、request.getSession().invalidate()を呼び出して、セッションを消去します。それから、ログアウトURLを構築して、必ずreturnToクエリパラメーターを含めます。ユーザーはログアウト後にこのURLにリダイレクトされます。最後に、アプリケーションのをログアウトURLに応答をリダイレクトします。
8

サンプルを実行する

サンプルを構築し実行するには、Mavenゴールに対してwildfly:runを実行し、このアプリケーションをデプロイした組み込みのWildFlyアプリケーションサーバーを起動します。詳細については、WildFly Maven Pluginのドキュメントを参照してください。LinuxまたはMacOSを使用している場合は、次を行います:
./mvnw clean wildfly:run
Windows:
mvnw.cmd clean wildfly:run
使用しているブラウザーでhttp:``//localhost:3000をポイントします。ログイン リンクを使用して、Auth0テナントにログインまたはサインアップします。ログインに成功すると、ユーザーのプロフィール画像とログインリンクのあるドロップダウンメニューが表示されます。プロファイル リンクをクリックすると、ユーザーのプロファイルページを表示することができます。ドロップダウンメニューにあるログアウト リンクをクリックすると、ログアウトできます。

次のステップ

成功です!ここまで来れば、アプリケーションにログイン、ログアウト、ユーザープロファイル情報が備わっているはずです。これでクイックスタートチュートリアルは終了ですが、機能はまだまだたくさんあります。Auth0でできることについて詳しくは、以下をご覧ください。
  • Auth0 Dashboard - Auth0のテナントやアプリケーションを構成して管理する方法について説明します
  • auth0-java-mvc-common SDK - このチュートリアルで使用されているSDKをより詳しく説明します
  • Auth0 Marketplace - Auth0の機能性を拡張できる各種の統合を見つけられます
I