leftso 2040 0 2018-06-21 10:04:50

文章位置:左搜> 编程技术> 正文
Spring Security 配置多个Authentication Providers认证器

1.概述

在这篇快速文章中,我们将重点介绍如何使用多种机制在Spring Security中对用户进行身份验证。
我们将通过配置多个身份验证提供程序来完成此操作
 

2. Authentication Providers

AuthenticationProvider是从特定存储库(如数据库,LDAP,自定义第三方来源等)获取用户信息的抽象概念。 它使用获取的用户信息来验证提供的凭证。

简而言之,当定义多个身份验证提供程序时,提供程序将按其声明的顺序进行查询。

为了快速演示,我们将配置两个身份验证提供程序 - 一个定制身份验证提供程序和一个内存身份验证提供程序

3. Maven 依赖

我们首先在我们的Web应用程序中添加必要的Spring Security依赖项:
<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.0.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-core</artifactId>
    <version>5.0.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>5.0.4.RELEASE</version>
</dependency>

4. 自定义 Authentication Provider

现在让我们通过实现AuthneticationProvider接口来创建一个自定义身份验证提供程序。

我们将实施验证方法 - 它将尝试验证。 输入的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. 配置Multiple Authentication Providers

现在让我们将CustomAuthenticationProvider和一个内存中验证提供程序添加到我们的Spring Security配置中。

5.1. Java Configuration

在我们的配置类中,现在让我们使用AuthenticationManagerBuilder创建和添加身份验证提供程序。

首先,通过使用inMemoryAuthentication(),使用CustomAuthenticationProvider,然后使用内存认证提供程序。

我们还确保访问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 Configuration

或者,如果我们想使用XML配置而不是Java配置:
<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. 应用Application

接下来,让我们创建一个由我们的两个身份验证提供程序保护的简单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 Security中配置多个身份验证提供程序。 我们使用自定义身份验证提供程序和内存身份验证提供程序确保了一个简单应用程序。

我们还编写了测试,以验证对我们应用程序的访问需要至少有一个身份验证提供程序可以验证的凭据。