我已经创建了一个基于 Spring WebFlux 的 REST API,它通过 X.509 身份验证受到保护。我遵循了本指南 https://www.baeldung.com/x-509-authentication-in-spring-security创建所有证书。
路由器实现:
@Configuration
class LogRouter {
@Bean
fun functionalRoutes(handler: LogHandler): RouterFunction<ServerResponse> =
route()
.route(RequestPredicates.path("/")) {
ServerResponse.ok().body(Mono.just("I am alive"))
}
.nest(RequestPredicates.path("/api").and(RequestPredicates.accept(MediaType.APPLICATION_JSON))) { builder ->
builder.GET("/fn/mono", handler::monoMessage)
.POST("/fn/mono", handler::monoPostMessage)
}
.build()
}
和应用实现:
@SpringBootApplication
@EnableWebFluxSecurity
class RestplayApplication {
@Bean
fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain? {
val principalExtractor = SubjectDnX509PrincipalExtractor()
principalExtractor.setSubjectDnRegex("OU=(.*?)(?:,|$)")
val authenticationManager = ReactiveAuthenticationManager { authentication: Authentication ->
authentication.isAuthenticated = "Trusted Org Unit" == authentication.name
Mono.just(authentication)
}
http
.x509 { x509 ->
x509
.principalExtractor(principalExtractor)
.authenticationManager(authenticationManager)
}
.authorizeExchange { exchanges ->
exchanges
.anyExchange().authenticated()
}
return http.build()
}
}
fun main(args: Array<String>) {
runApplication<RestplayApplication>( *args)
}
我使用 Firefox 浏览器来测试 x.509 身份验证,并且我已将自签名证书(rootCA.crt) 添加到 Firefox:
包含客户端证书(clientBob.p12)。
在浏览器中调用链接时,它显示基本身份验证表单:
但是,我希望身份验证表单不会出现,因为我在浏览器中提供了有效的客户端证书。
为什么每次都出现基本形式?
代码托管在 https://github.com/softshipper/restplay 上.证书的密码始终是 changeit。
最佳答案
我调试了它,问题似乎是您的客户端证书 clientBob.crt 不包含主题的组织单位字段,并且您的 principalExtractor 设置为提取该字段。结果,您的 principalExtractor 失败,因此它调用 authenticationFailureHandler,默认设置为提示基本身份验证。
可能的解决方案可能是:
使用包含主体组织单位的客户端证书,并将其设置为“受信任的组织单位”。
更改 principalExtractor 正则表达式,使其使用不同的字段。默认使用通用名称 (CN)。如果你确实编辑了它,那么记得同时更新你的 authenticationManager 以检查“Bob”而不是“Trusted Org Unit”
关于spring - 使用 x.509 身份验证时避免基本身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71483390/