SpringBoot(Java)プロジェクトでAzureAD認証を追加するための実装方法について記載していく。
依存関係の追加
Azure AD認証を導入したいプロジェクトのbuild.gradleに「Spring Cloud Azure Starter Active Directory」の依存関係を追加する。
dependencies {
// Spring Cloud Azure Starter Active Directory
implementation 'com.azure.spring:spring-cloud-azure-starter-active-directory'
}
application.ymlに設定追加
application.ymlに下記の設定を追加する。どのAzureADで認証を行うのかを設定している。
テナントID、クライアントID、クライアントシークレットはAzure Portal上で確認可能。
spring: cloud: azure: active-directory: application-type: web-application # Azure AD認証を有効化する enabled: true profile: # Azure Tenant ID tenant-id: xxxxx-xxxx-xxx-xxx-xxxxx credential: # Azureでサービス プリンシパル認証を実行する際に使用するクライアントID client-id: xxxxxx-xxx-xxx-xxxx-xxxxxxxx # Azureでサービス プリンシパル認証を実行する際に使用するクライアントシークレット client-secret: xxxxx~xxxxxxx authorization-clients: graph: scopes: email,openid # AzureADのautoconfigureを無効化する(Spring Securityの設定方法が古くアプリ起動時に例外が発生するため) autoconfigure: exclude: com.azure.spring.cloud.autoconfigure.aad.AadAutoConfiguration
AuzreAD認証のユーザー情報を構築するサービス
リクエストからログイン者のメールアドレスを取得して、対象のメールアドレスがDBに登録されているかどうか検索する。
今回は標準のユーザインスタンスを返却しているが、このサービスクラスの中で独自ユーザクラスにラップしたものを作成して返却することも可能。
※AzureAD認証自体はアプリの外側で実施されるため、このクラスにリクエストが送られてきたタイミングで既にAzureAD認証は完了している。
import java.util.List; import org.apache.commons.lang3.StringUtils; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest; import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService; import org.springframework.security.oauth2.client.userinfo.OAuth2UserService; import org.springframework.security.oauth2.core.oidc.user.OidcUser; /** * AuzreAD認証のユーザー情報を構築するサービス。<br> */ @Transactional public class AzureAd2UserService implements OAuth2UserService<OidcUserRequest, OidcUser> { /** {@link LoginUserDao} */ private LoginUserDao loginUserDao; /** * コンストラクタ。<br> */ public AzureAd2UserService() { } /** * コンストラクタ。<br> * * @param loginUserDao * {@link LoginUserDao} */ public AzureAd2VeUserService(LoginUserDao loginUserDao) { this.loginUserDao = loginUserDao; } /** * 認証後のユーザー情報を元に、DBを検索し拡張したユーザー情報を返す * * @param userRequest * 認証リクエスト * @return 拡張ユーザー情報 */ @Override public OidcUser loadUser(OidcUserRequest userRequest) { OidcUserService service = new OidcUserService(); // 認証処理後のユーザー情報を取得 OidcUser oidcUser = service.loadUser(userRequest); // ログインユーザーがDBに登録されているかどうかを確認する LoginUser loginUser = loginUserDao.selectById(oidcUser.getEmail()); if (loginUser == null) { // nullの場合は、アプリへのアクセス権限が付与されていないためエラーとする throw new AccessDeniedException( "[ログインユーザ]テーブルに該当のメールアドレスがされていません。 メールアドレス=[%s]".formatted(oidcUser.getEmail())); } return oidcUser; } }
JavaConfig
Azure AD認証周りの設定を定義するためのJavaConfigクラス。
application.ymlでautoconfigurationをOFFにしたため、最低限必要なJavaConfigについてこのクラスでインポートを実施する。
@Import({ AadPropertiesConfiguration.class, AadResourceServerConfiguration.class, AadOAuth2ClientConfiguration.class })
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Profile; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.logout.LogoutHandler; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import com.azure.spring.cloud.autoconfigure.aad.configuration.AadOAuth2ClientConfiguration; import com.azure.spring.cloud.autoconfigure.aad.configuration.AadPropertiesConfiguration; import com.azure.spring.cloud.autoconfigure.aad.configuration.AadResourceServerConfiguration; /** * AzureAD認証を利用を前提としたSpring Securityの定義クラス。 */ @EnableWebSecurity @Import({ AadPropertiesConfiguration.class, AadResourceServerConfiguration.class, AadOAuth2ClientConfiguration.class }) public class SecurityConfiguration { /** ログアウトハンドラー */ private LogoutHandler logoutHandler; /** {@link ServiceAdminAuthorityComplexDao} */ @Autowired private LoginUserDao loginUserDao; /** * コンストラクタ<br> * * @param logoutHandler * ログアウトハンドラー */ public SecurityConfiguration(LogoutHandler logoutHandler) { this.logoutHandler = logoutHandler; } /** * {@link SecurityFilterChain}をDIコンテナに登録する。<br> * * @param http * {@link HttpSecurity} * @return {@link SecurityFilterChain} * @throws Exception * セキュリティ設定時に例外が発生した場合 */ @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { // 認証処理の設定 http.authorizeHttpRequests() // 認証対象外のURL指定 .mvcMatchers("/images/**", "/css/**", "/js/**", "/webjars/**") .permitAll() // 上記以外は認証が必要 .anyRequest().authenticated() // 認可エラーが発生した際にハンドリングする設定 .and().exceptionHandling().accessDeniedHandler(this.getForbiddenAccessDeniedHandler()) // AzureAD認証はOAuth2認証を使用して設定する .and() .oauth2Login(oauth2 -> { oauth2.userInfoEndpoint( userInfo -> userInfo.oidcUserService(request -> { var service = getAzureAd2VeUserService(); return service.loadUser(request); })); // 認証時に例外が発生した場合にハンドリングする設定 oauth2.failureHandler(this.getDefaultAuthenticationFailureHandler()); }); // ログアウト処理の設定 http.logout() .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) .addLogoutHandler(logoutHandler) .invalidateHttpSession(true) // ログアウト時にセッションを無効にする .clearAuthentication(true) // ログアウト時に認証情報を削除する .deleteCookies("JSESSIONID").permitAll(); // ログアウト時にCookieを削除する return http.build(); } /** * {@link DefaultAuthenticationFailureHandler}のオブジェクトを返す。 * * @return DefaultAuthenticationFailureHandlerのオブジェクト */ private DefaultAuthenticationFailureHandler getDefaultAuthenticationFailureHandler() { return new DefaultAuthenticationFailureHandler(); } /** * {@link ForbiddenAccessDeniedHandler}のオブジェクトを返す。 * * @return ForbiddenAccessDeniedHandlerのオブジェクト */ private ForbiddenAccessDeniedHandler getForbiddenAccessDeniedHandler() { return new ForbiddenAccessDeniedHandler(); } /** * {@link AzureAd2UserService}を取得する * * @return {@link AzureAd2UserService} */ private AzureAd2UserService getAzureAd2UserService() { return new AzureAd2UserService(loginUserDao); } }
参考
Microsoft Entra 用の Spring Boot Starter の開発者ガイド - Java on Azure | Microsoft Learn