外部サービスを使用したJHipster認証

1. 前書き

デフォルトでは、https://www.jhipster.tech/ [JHipster]アプリケーションはローカルデータストアを使用してユーザー名とパスワードを保持します。 ただし、実際の多くのシナリオでは、認証に既存の外部サービスを使用することが望ましい場合があります。
このチュートリアルでは、JHipsterでの認証に外部サービスを使用する方法を見ていきます。 これは、LDAP、ソーシャルログイン、またはユーザー名とパスワードを受け入れる任意のサービスなど、よく知られているサービスです。

2. JHipsterでの認証

JHipsterは認証にlink:/security-spring[Spring Security]を使用します。 * _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に渡します。
呼び出しが成功すると、成功を示す新しい_UsernamePasswordAuthenticationToken_を返します。 *後で説明するローカルユーザーエントリも作成します*。
呼び出しが失敗した場合、Spring Securityが適切にフォールバックできるように、_AuthenticationException_ *の一部のバリアントをスローします。
この例は、カスタム認証の基本を示すために意図的にシンプルになっています。 ただし、LDAPバインドおよび認証やhttps://developer.okta.com/blog/2018/03/01/develop-microservices-jhipster-oauth[use 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>
and
<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>
すべてのリンクを削除しても、*ユーザーはこれらのページに手動で移動できます*。 最後のステップは、未使用のAngularルートを_app / account / account.route.ts_から削除することです。
これを行った後、設定ルートのみが残るはずです:
import { settingsRoute } from './';
const ACCOUNT_ROUTES = [settingsRoute];

3.2. Java API

ほとんどの場合、フロントエンドのアカウント管理コードを削除するだけで十分です。 ただし、*アカウント管理コードが呼び出されないようにするために、関連するJava API *をロックダウンすることもできます。
これを行う最も簡単な方法は、_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_にあります。 これらは、https://www.baeldung.com/thymeleaf-in-spring-mvc [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などが含まれます。
いつものように、このチュートリアルのサンプルコードはhttps://github.com/eugenp/tutorials/tree/master/jhipster-5[GitHubで]から入手できます。