1. 序章

デフォルトでは、 JHipster アプリケーションは、ローカルデータストアを使用してユーザー名とパスワードを保持します。 ただし、実際の多くのシナリオでは、認証に既存の外部サービスを使用することが望ましい場合があります。

このチュートリアルでは、JHipsterでの認証に外部サービスを使用する方法を見ていきます。 これは、LDAP、ソーシャルログインなどのよく知られたサービス、またはユーザー名とパスワードを受け入れる任意のサービスである可能性があります。

2. JHipsterでの認証

JHipsterは、認証に SpringSecurityを使用します。 AuthenticationManagerクラスは、ユーザー名とパスワードの検証を担当します。

JHipsterのデフォルトのAuthenticationManagerは、ユーザー名とパスワードをローカルデータストアと照合するだけです。 これは、MySQL、PostgreSQL、MongoDB、またはJHipsterがサポートする代替のいずれかである可能性があります。

AuthenticationManagerは初期ログインにのみ使用されることに注意してください。 ユーザーが認証されると、後続のAPI呼び出しに使用されるJSON Web Token(JWT)を受け取ります。

2.1. JHipsterでの認証の変更

しかし、ユーザー名とパスワードを含むデータストア、または認証を実行するサービスがすでにある場合はどうなるでしょうか。

カスタム認証スキームを提供するには、AuthenticationManagerタイプの新しいBeanを作成するだけです。 これは、デフォルトの実装よりも優先されます。

以下は、カスタムAuthenticationManagerを作成する方法を示す例です。 実装する方法は1つだけです。

public class CustomAuthenticationManager implements AuthenticationManager {
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        try {
            ResponseEntity<LoginResponse> response =
                restTemplate.postForEntity(REMOTE_LOGIN_URL, loginRequest, LoginResponse.class);
            
            if(response.getStatusCode().is2xxSuccessful()) {
                String login = authentication.getPrincipal().toString();
                User user = userService.getUserWithAuthoritiesByLogin(login)
                  .orElseGet(() -> userService.createUser(
                    createUserDTO(response.getBody(), authentication)));
                return createAuthentication(authentication, user);
            }
            else {
                throw new BadCredentialsException("Invalid username or password");
            }
        }
        catch (Exception e) {
            throw new AuthenticationServiceException("Failed to login", e);
        }
    }
}

この例では、Authenticationオブジェクトから外部APIにユーザー名と資格情報を渡します。

呼び出しが成功すると、成功を示す新しいUsersnamePasswordAuthenticationTokenが返されます。 ローカルユーザーエントリも作成することに注意してください。これについては後でで説明します。

呼び出しが失敗した場合、SpringSecurityが適切にフォールバックするようにAuthenticationExceptionのバリアントをスローします

この例は、カスタム認証の基本を示すために意図的に単純化されています。 ただし、LDAPバインディングや認証などのより複雑な操作を実行したり、OAuthを使用したりする可能性があります。

3. その他の考慮事項

これまで、JHipsterの認証フローに焦点を当ててきました。 ただし、JHipsterアプリケーションには、変更が必要な他のいくつかの領域があります。

3.1. フロントエンドコード

デフォルトのJHipsterコードは、次のユーザー登録およびアクティベーションプロセスを実装します。

  • ユーザーは、メールやその他の必要な詳細を使用してアカウントにサインアップします
  • JHipsterはアカウントを作成し、それを非アクティブとして設定してから、アクティベーションリンクを含む電子メールを新しいユーザーに送信します
  • リンクをクリックすると、ユーザーのアカウントはアクティブとしてマークされます

パスワードのリセットについても同様のフローがあります。

これらはすべて、JHipsterがユーザーアカウントを管理しているときに意味があります。 ただし、認証を外部サービスに依存している場合は、これらは必要ありません。

したがって、ユーザーがこれらのアカウント管理機能にアクセスできないようにするための措置を講じる必要があります

これは、JHipsterアプリケーションで使用されているフレームワークに応じて、AngularまたはReactコードからそれらを削除することを意味します。

例としてAngularを使用すると、デフォルトのログインプロンプトには、パスワードのリセットと登録へのリンクが含まれています。 app / shared / login /login.component.htmlからそれらを削除する必要があります。

<div class="alert alert-warning">
  <a class="alert-link" (click)="requestResetPassword()">Did you forget your password?</a>
</div>
<div class="alert alert-warning">
  <span>You don't have an account yet?</span>
   <a class="alert-link" (click)="register()">Register a new account</a>
</div>

また、 app / layouts / navbar /navbar.component.htmlから不要なナビゲーションメニュー項目を削除する必要があります。

<li *ngSwitchCase="true">
  <a class="dropdown-item" routerLink="password" routerLinkActive="active" (click)="collapseNavbar()">
    <fa-icon icon="clock" fixedWidth="true"></fa-icon>
    <span>Password</span>
  </a>
</li>

<li *ngSwitchCase="false">
  <a class="dropdown-item" routerLink="register" routerLinkActive="active" (click)="collapseNavbar()">
    <fa-icon icon="user-plus" fixedWidth="true"></fa-icon>
    <span>Register</span>
  </a>
</li>

すべてのリンクを削除しても、ユーザーは手動でこれらのページに移動できました。 最後のステップは、 app / account /account.route.tsから未使用のAngularルートを削除することです。

これを行った後、設定ルートのみを残す必要があります。

import { settingsRoute } from './';
const ACCOUNT_ROUTES = [settingsRoute];

3.2. Java API

ほとんどの場合、フロントエンドのアカウント管理コードを削除するだけで十分です。 ただし、アカウント管理コードが呼び出されないようにするために、関連するJavaAPIをロックダウンすることもできます。

これを行う最も簡単な方法は、 SecurityConfiguration クラスを更新して、関連付けられたURLへのすべてのリクエストを拒否することです。

.antMatchers("/api/register").denyAll()
.antMatchers("/api/activate").denyAll()
.antMatchers("/api/account/reset-password/init").denyAll()
.antMatchers("/api/account/reset-password/finish").denyAll()

これにより、コードを削除しなくても、APIへのリモートアクセスが防止されます。

3.3. メールテンプレート

JHipsterアプリケーションには、アカウントの登録、アクティブ化、およびパスワードのリセット用の一連のデフォルトの電子メールテンプレートが付属しています。 前の手順では、デフォルトの電子メールが送信されないようにしますが、場合によっては、それらを再利用したい場合があります。

たとえば、ユーザーが初めてログインしたときにウェルカムメールを送信したい場合があります。 デフォルトのテンプレートにはアカウントのアクティブ化の手順が含まれているため、変更する必要があります。

すべてのメールテンプレートはresources/ templates /mailにあります。 これらは、Thymeleafを使用してJavaコードから電子メールにデータを渡すHTMLファイルです。

テンプレートを編集して目的のテキストとレイアウトを含め、MailServiceを使用して送信するだけです。

3.4. 役割

ローカルのJHipsterユーザーエントリを作成するときは、少なくとも1つの役割があることを確認する必要もあります。 通常、新しいアカウントにはデフォルトのUSERロールで十分です。

外部サービスが独自の役割マッピングを提供する場合、2つの追加手順があります。

  1. JHipsterにカスタムロールが存在することを確認します
  2. カスタムAuthenticationManagerを更新して、新しいユーザーを作成するときにカスタムロールを設定します

JHipsterは、ユーザーに役割を追加および削除するための管理インターフェイスも提供します。

3.5. アカウントの削除

JHipsterはアカウント削除管理ビューとAPIも提供していることは言及する価値があります。 このビューは、管理者ユーザーのみが使用できます。

アカウント登録とパスワードのリセットの場合と同じように、このコードを削除して制限することはできますが、実際には必要ありません。 カスタムAuthenticationManagerは、誰かがログインしたときに常に新しいアカウントエントリを作成するため、アカウントを削除しても実際にはあまり効果がありません。

4. 結論

このチュートリアルでは、デフォルトのJHipster認証コードを独自の認証スキームに置き換える方法を説明しました。 これは、LDAP、OIDC、またはユーザー名とパスワードを受け入れるその他のサービスである可能性があります。

また、外部認証サービスを使用するには、JHipsterアプリケーションの他の領域にいくつかの変更を加える必要があることもわかりました。 これには、フロントエンドビュー、APIなどが含まれます。

いつものように、このチュートリアルのサンプルコードは、GitHubから入手できます。