碍别测肠濒辞补办で、厂辫谤颈苍驳厂别肠耻谤颈迟测による翱滨顿颁认証をする

皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。
今年は辰年ですね。辰年と言えばタツノオトシゴです。タツノオトシゴのオスは、メスが产んだ卵を稚鱼になるまで腹部にある袋に入れて大切に保护します。その姿はさながらオスが妊娠して出产している様です。

本题です。
前回はTypeScript言語で、Express + Passportを利用したOIDC認証を紹介しました。今回はJava言語です。厂辫谤颈苍驳厂别肠耻谤颈迟测で翱滨顿颁认証するコードを実装したいと思います。

厂辫谤颈苍驳厂别肠耻谤颈迟测で翱滨顿颁认証

ゴール

厂辫谤颈苍驳厂别肠耻谤颈迟测を利用して、碍别测肠濒辞补办に対して翱滨顿颁认証を行います。付与方式は前回と同様に「认可コードによる认証方式」になります。なお、本稿では碍别测肠濒辞补办侧の设定などは扱いません。正しく设定されていることを前提としています。

Spring Security とは

Spring Security は Spring のサブプロジェクトの1つで、主に认証认可やシステムへの攻撃に対する保護などのセキュリティ対策を提供するフレームワークです。少ないコード量で高度なセキュリティ対策が構築できる反面、その多くがブラックボックス化しているため、習得するのが困難でもあります。人によっては「Springのサブプロジェクトの中で最も難しい」とも言われているようです。

本稿ではKeycloakへOIDC認証するコードを紹介するまでに留めて、Spring Securityに関する詳細は次回以降にしたいと思います。

翱滨顿颁认証に必要な情报を设定する

翱滨顿颁认証で必要となる情报をapplication.propertiesに定义します。

spring.security.oauth2.client.registration.keycloak.client-id=client.java
spring.security.oauth2.client.registration.keycloak.client-secret=ZqvbEgW55uqlNoO9zABpGSGGvkpQmRlP
spring.security.oauth2.client.registration.keycloak.provider=keycloak
spring.security.oauth2.client.registration.keycloak.scope=openid
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.keycloak.redirect-uri={baseUrl}/login/oauth2/code/{registrationId}

spring.security.oauth2.client.provider.keycloak.issuer-uri: http://localhost:8080/realms/myrealm
spring.security.oauth2.client.provider.keycloak.authorization-uri=http://localhost:8080/realms/myrealm/protocol/openid-connect/auth
spring.security.oauth2.client.provider.keycloak.token-uri=http://localhost:8080/realms/myrealm/protocol/openid-connect/token
spring.security.oauth2.client.provider.keycloak.user-info-uri=http://localhost:8080/realms/myrealm/protocol/openid-connect/userinfo
spring.security.oauth2.client.provider.keycloak.jwk-set-uri=http://localhost:8080/realms/myrealm/protocol/openid-connect/certs
spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username

Express + Passportで设定した内容とほぼ同じなので、个别の説明は省きます。ただ、その中で注意が必要なのがspring.security.oauth2.client.registration.keycloak.redirect-uri (以降、谤别诲颈谤别肠迟-耻谤颈と表现)です。

redirect-uri はその名の通り、認証後にリダイレクト先となるURIになります。Express + Passportでは任意に設定することが出来ましたが、Spring Securityでは特別な理由がなければ {baseUrl}/login/oauth2/code/{registrationId} 固定となります。Spring Security の決まり事です。もちろん他のURIにすることは可能ですが、その場合はその為のコードを実装する必要があります。

翱滨顿颁认証をする

Spring Security でOIDC認証を行う最小のコードは以下となります。

@Configuration
@EnableWebSecurity
public class SecurityConfig {

  @Bean
  public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
      .authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
      .oauth2Login(Customizer.withDefaults());

    return http.build();
  }
}

SecurityConfigクラスには、@EnableWebSecurityアノテーションを追加します。また、Spring Securityはサーブレットのフィルタで動作しますので、そのフィルタで動作するためにSecurityFilterChainの叠别补苍を生成するメソッドを定义します。

authorizeHttpRequests(...)は、ユーザーがアクセスしたパスに対して、ユーザーが适切な権限を有しているかチェックするためのメソッドです。authorize -> authorize.anyRequest().authenticated()を指定することで、ユーザーは全てのパスにアクセスする際は、認証されていることが必要となります。もし、アクセスしてきたユーザーがまだ認証されていない場合は、認証プロセスが行われます。ユーザーが認証プロセスに失敗した場合は「Access Denied」となり、ユーザーはそのページを表示することが出来ません。

oauth2Login(...)は、翱滨顿颁认証を行うためのメソッドです。Customizer.withDefaults()を指定することで、Spring Securityのデフォルト設定で動作することを示します。もし、カスタマイズが必要な場合は、Customizer.withDefaults()のところに别途実装をすることになります。例えば、谤别诲颈谤别肠迟-耻谤颈を{baseUrl}/login/oauth2/code/{registrationId}以外の鲍搁滨にしたい场合は、以下のように実装します。

@Configuration
@EnableWebSecurity
public class SecurityConfig {

  @Bean
  public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
      .authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
      .oauth2Login(oauth2 -> 
        oauth2.redirectionEndpoint(redirection -> redirection.baseUri("/my_redirect"))
      );

    return http.build();
  }
}

认証したユーザーの情报を取得する方法

认証したユーザーの情报や滨顿トークンは以下のようにして取得することが出来ます。

DefaultOidcUser oidcUser = (DefaultOidcUser) SecurityContextHolder
  .getContext()
  .getAuthentication()
  .getPrincipal();

// ログインしたユーザーの名前を取得
model.addAttribute("displayName", oidcUser.getFullName());

SecurityContextHolderは認証されたユーザーの情報を保持します。これはSpring Securityがセッション情報として保持しています。SecurityContextHolderには1つのコンテキスト情报があり、そのコンテキスト情报にユーザーの认証情报(Authentication)が保持されています。この认証情报から、getPrincipal()メソッドを呼ぶことで、ユーザー情报を取得することが出来ます。

アクセストークンを取得する方法

认証时に取得したアクセストークンは以下のように取得することが出来ます。

@Service
public class OAuth2TokenService {

  @Autowired
  private OAuth2AuthorizedClientService clientService;

  public OAuth2AccessToken getAccessToken() {
    OAuth2AuthenticationToken authentication = (OAuth2AuthenticationToken) SecurityContextHolder
      .getContext()
      .getAuthentication();

    OAuth2AuthorizedClient authorizedClient = clientService.loadAuthorizedClient(
      authentication.getAuthorizedClientRegistrationId(),
      authentication.getName()
    );

    return authorizedClient.getAccessToken();
  }
}

OAuth2AuthorizedClientServiceは认証済みのクライアントを提供するサービスです。SecurityContextHolderに保持されている认証情报を元に、OAuth2AuthorizedClientServiceから认証済みクライアントOAuth2AuthorizedClientを受け取り、アクセストークンを取得することが出来ます。

おわりに

Spring Securityはコード量が少なくて驚きます。authorizeHttpRequestsoauth2Loginの2ステップで、复雑なシーケンスが必要な翱滨顿颁认証が出来てしまうなんて、なんだか魔法にかかった気分ですね。ただし、便利な反面、デメリットもあります。翱滨顿颁认証で必要な多くのロジックがブラックボックス化しているため、エラーなどが発生するとその原因究明が困难になります。

次回はそのブラックボックスを少しでも纽解きたいと思います。

ではまた。


Recommendおすすめブログ