SpringSecurityの複数の認証プロバイダー
1. 概要
このクイック記事では、Springセキュリティでユーザーを認証するために複数のメカニズムを使用することに焦点を当てます。
これを行うには、複数の認証プロバイダーを構成します。
2. 認証プロバイダー
AuthenticationProvider は、特定のリポジトリ(データベース、 LDAP 、カスタムサードパーティソースなど)からユーザー情報をフェッチするための抽象化です。 。 ). フェッチされたユーザー情報を使用して、提供された資格情報を検証します。
簡単に言うと、複数の認証プロバイダーが定義されている場合、プロバイダーは宣言された順序で照会されます。
簡単なデモンストレーションとして、カスタム認証プロバイダーとメモリ内認証プロバイダーの2つの認証プロバイダーを構成します。
3. Mavenの依存関係
まず、必要なSpringセキュリティ依存関係をWebアプリケーションに追加しましょう。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
そして、Spring Bootなし:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
これらの依存関係の最新バージョンは、 spring-security-web 、 spring-security-core 、およびspring-security-configにあります。
4. カスタム認証プロバイダー
次に、を実装してカスタム認証プロバイダーを作成しましょう。 AuthneticationProvider インターフェース
authenticate メソッドを実装します–認証を試みます。 入力Authenticationオブジェクトには、ユーザーが指定したユーザー名とパスワードのクレデンシャルが含まれています。
authenticate メソッドは、認証が成功した場合、完全に入力されたAuthenticationオブジェクトを返します。 認証が失敗すると、タイプAuthenticationExceptionの例外がスローされます。
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication auth)
throws AuthenticationException {
String username = auth.getName();
String password = auth.getCredentials()
.toString();
if ("externaluser".equals(username) && "pass".equals(password)) {
return new UsernamePasswordAuthenticationToken
(username, password, Collections.emptyList());
} else {
throw new
BadCredentialsException("External system authentication failed");
}
}
@Override
public boolean supports(Class<?> auth) {
return auth.equals(UsernamePasswordAuthenticationToken.class);
}
}
当然、これはここでの例の目的のための単純な実装です。
5. 複数の認証プロバイダーの構成
次に、CustomAuthenticationProviderとメモリ内認証プロバイダーをSpringセキュリティ構成に追加しましょう。
5.1. Java構成
構成クラスで、AuthenticationManagerBuilderを使用して認証プロバイダーを作成および追加しましょう。
最初にCustomAuthenticationProvider、次に inMemoryAuthentication()を使用したメモリ内認証プロバイダー。
また、URLパターン「 / api /**」へのアクセスを認証する必要があることも確認しています。
@EnableWebSecurity
public class MultipleAuthProvidersSecurityConfig
extends WebSecurityConfigurerAdapter {
@Autowired
CustomAuthenticationProvider customAuthProvider;
@Override
public void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.authenticationProvider(customAuthProvider);
auth.inMemoryAuthentication()
.withUser("memuser")
.password(encoder().encode("pass"))
.roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/api/**")
.authenticated();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
5.2. XML構成
または、Java構成の代わりにXML構成を使用する場合は、次のようにします。
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="memuser" password="pass"
authorities="ROLE_USER" />
</security:user-service>
</security:authentication-provider>
<security:authentication-provider
ref="customAuthenticationProvider" />
</security:authentication-manager>
<security:http>
<security:http-basic />
<security:intercept-url pattern="/api/**"
access="isAuthenticated()" />
</security:http>
6. アプリケーション
次に、2つの認証プロバイダーによって保護される単純なRESTエンドポイントを作成しましょう。
このエンドポイントにアクセスするには、有効なユーザー名とパスワードを指定する必要があります。 認証プロバイダーは、資格情報を検証し、アクセスを許可するかどうかを決定します。
@RestController
public class MultipleAuthController {
@GetMapping("/api/ping")
public String getPing() {
return "OK";
}
}
7. テスト
最後に、安全なアプリケーションへのアクセスをテストしましょう。 アクセスは、有効な資格情報が提供されている場合にのみ許可されます。
@Autowired
private TestRestTemplate restTemplate;
@Test
public void givenMemUsers_whenGetPingWithValidUser_thenOk() {
ResponseEntity<String> result
= makeRestCallToGetPing("memuser", "pass");
assertThat(result.getStatusCodeValue()).isEqualTo(200);
assertThat(result.getBody()).isEqualTo("OK");
}
@Test
public void givenExternalUsers_whenGetPingWithValidUser_thenOK() {
ResponseEntity<String> result
= makeRestCallToGetPing("externaluser", "pass");
assertThat(result.getStatusCodeValue()).isEqualTo(200);
assertThat(result.getBody()).isEqualTo("OK");
}
@Test
public void givenAuthProviders_whenGetPingWithNoCred_then401() {
ResponseEntity<String> result = makeRestCallToGetPing();
assertThat(result.getStatusCodeValue()).isEqualTo(401);
}
@Test
public void givenAuthProviders_whenGetPingWithBadCred_then401() {
ResponseEntity<String> result
= makeRestCallToGetPing("user", "bad_password");
assertThat(result.getStatusCodeValue()).isEqualTo(401);
}
private ResponseEntity<String>
makeRestCallToGetPing(String username, String password) {
return restTemplate.withBasicAuth(username, password)
.getForEntity("/api/ping", String.class, Collections.emptyMap());
}
private ResponseEntity<String> makeRestCallToGetPing() {
return restTemplate
.getForEntity("/api/ping", String.class, Collections.emptyMap());
}
8. 結論
このクイックチュートリアルでは、Springセキュリティで複数の認証プロバイダーを構成する方法を説明しました。 カスタム認証プロバイダーとメモリ内認証プロバイダーを使用して、単純なアプリケーションを保護しました。
また、アプリケーションへのアクセスに、少なくとも1つの認証プロバイダーが検証できる資格情報が必要であることを確認するためのテストも作成しました。
いつものように、実装の完全なソースコードはGitHubのにあります。