我遇到了类似的问题,并认为我会分享我带来的解决方案。
首先,您需要了解SSL证书身份验证将在Web服务器端处理(参见dur的解释,使用“clientAuth=want”设置)。然后,必须配置 Web 应用,以便处理提供(和允许的)证书,将其映射到用户等。
我和你们的细微区别是,我将我的 Spring Boot 应用程序打包到 WAR 归档中,然后将其部署到现有的 Tomcat 应用程序服务器上。
My Tomcat 的服务器.xml配置文件定义了一个 HTTPS 连接器,如下所示:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
keystoreFile="/opt/tomcat/conf/key-stores/ssl-keystore.jks"
keystorePass=“some-complex-password“
clientAuth="want" sslProtocol="TLS"
truststoreFile="/opt/tomcat/conf/trust-stores/ssl-truststore.jks"
truststorePass=“some-other-complex-password” />
为了避免任何混淆,小注释:keystoreFile 包含用于 SSL 的证书/私钥对(仅),而 truststoreFile 包含允许用于客户端 SSL 身份验证的 CA 证书(请注意,您还可以将客户端证书直接添加到该信任存储中)。
如果将嵌入式 tomcat 容器与 spring boot 应用程序一起使用,则应该能够在应用程序的属性文件中使用以下属性键/值配置这些设置:
server.ssl.key-store=/opt/tomcat/conf/key-stores/ssl-keystore.jks
server.ssl.key-store-password=some-complex-password
server.ssl.trust-store=/opt/tomcat/conf/trust-stores/ssl-truststore.jks
server.ssl.trust-store-password=some-other-complex-password
server.ssl.client-auth=want
然后,在我的 Web 应用上,我声明特定的 SSL 配置,如下所示:
@Configuration
@EnableWebSecurity
//In order to use @PreAuthorise() annotations later on...
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SSLAuthConfiguration extends WebSecurityConfigurerAdapter {
@Value("${allowed.user}")
private String ALLOWED_USER;
@Value("${server.ssl.client.regex}")
private String CN_REGEX;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure (final HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/url-path-to-protect").authenticated() //Specify the URL path(s) requiring authentication...
.and()
.x509() //... and that x509 authentication is enabled
.subjectPrincipalRegex(CN_REGEX)
.userDetailsService(userDetailsService);
}
@Autowired
//Simplified case, where the application has only one user...
public void configureGlobal (final AuthenticationManagerBuilder auth) throws Exception {
//... whose username is defined in the application's properties.
auth
.inMemoryAuthentication()
.withUser(ALLOWED_USER).password("").roles("SSL_USER");
}
}
然后,我需要声明 UserDetailsService bean(例如,在我的应用程序的主类中):
@Value("${allowed.user}")
private String ALLOWED_USER;
@Bean
public UserDetailsService userDetailsService () {
return new UserDetailsService() {
@Override
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
if (username.equals(ALLOWED_USER)) {
final User user = new User(username, "", AuthorityUtils.createAuthorityList("ROLE_SSL_USER"));
return user;
}
return null;
}
};
}
就是这样!然后,我可以将@PreAuthorize(“hasRole('ROLE_SSL_USER')”)注释添加到要保护的方法中。
总而言之,身份验证流程将如下所示:
- 用户提供 SSL 证书 ;
- Tomcat 根据其信任存储进行验证 ;
- 自定义 WebSecurityConfigurerAdapter 从证书的 CN 中检索“用户名” ;
- 应用程序对与检索到的用户名 关联的用户进行身份验证;
- 在方法级别,如果使用@PreAuthorize(“hasRole('SSL_USER'))进行注释,应用程序将检查用户是否具有所需的角色。