我遇到了类似的问题,想分享我找到的解决方法。
首先,您需要知道SSL证书认证将在您的Web服务器端处理(请参见dur的解释,“clientAuth = want”设置)。
然后,您的Web应用程序必须配置为处理提供的(和允许的)证书,将其映射到用户等。
我与您略有不同的地方是,我将我的Spring Boot应用程序打包成WAR存档文件,然后部署在现有的Tomcat应用服务器上。
我的Tomcat的server.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 证书(请注意,您也可以直接将客户端证书添加到该 TrustStore 中)。
如果您正在使用嵌入式 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
@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()
.and()
.x509()
.subjectPrincipalRegex(CN_REGEX)
.userDetailsService(userDetailsService);
}
@Autowired
public void configureGlobal (final AuthenticationManagerBuilder auth) throws Exception {
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')")注释的方法,应用程序会在方法级别检查用户是否具有所需的角色。