我们在
SecurityConfig
中配置了两个过滤器链(bean):
oauth2ProtocolEndpointsSecurityFilterChain
订单 1(authServer 配置)userEndpointsSecurityFilterChain
顺序为 2(外部 OIDC IdP 的配置)第二条链配置外部 OIDC 提供商,因此当用户尝试使用我们的身份验证服务器登录应用程序时,它们会被转发到外部 OIDC 提供商进行身份验证)。这非常有效,直到我们在自定义
response_mode
中将 form_post
更改为 AuthorizationRequestResolver
(query
是默认值,但不太安全):
additionalParameters.put(RESPONSE_MODE, "form_post");
这就是现在发生的事情。当外部 OIDC 提供程序使用代码值重定向回我们的身份验证服务器时,我们将收到访问被拒绝的异常。这是我在启用跟踪级别的日志中找到的内容:
{"@timestamp":"2025-01-03T14:16:11.229589993+01:00","@version":"1","message":"Sending AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=10.131.0.2, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]] to authentication entry point since access is denied","logger_name":"org.springframework.security.web.access.ExceptionTranslationFilter","thread_name":"http-nio-8080-exec-4","level":"TRACE","level_value":5000,"stack_trace":"org.springframework.security.authorization.AuthorizationDeniedException: Access Denied\n\tat org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:99)\n\tat
在这个错误下面,我发现了一些我认为是问题根源的东西——csrf要求:
Invalid CSRF token found for https://nettskjema-authorization-dev.uio.no/login/oauth2/code/idporten
我尝试禁用 csrf,只是为了弄清楚会发生什么。当然,这对第二个 bean(过滤器)没有影响,但对第一个 bean 没有影响。因此,我将以下配置替换为另一个配置,并完全禁用 CSRF:
.csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher))
.csrf(csrf -> csrf.disable())
但是无效的 CSRF 令牌错误仍然存在。
我已经使用 DevTools 调试了流量,所以这是从我们的外部 IdP 发回的 post 请求(Curl 以简化)
curl 'https://nettskjema-authorization-dev.uio.no/login/oauth2/code/idporten' --compressed -X POST -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:133.0) Gecko/20100101 Firefox/133.0' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' -H 'Accept-Language: no,en;q=0.7,en-US;q=0.3' -H 'Accept-Encoding: gzip, deflate, br, zstd' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Origin: https://login.test.idporten.no' -H 'DNT: 1' -H 'Sec-GPC: 1' -H 'Connection: keep-alive' -H 'Referer: https://login.test.idporten.no/' -H 'Upgrade-Insecure-Requests: 1' -H 'Sec-Fetch-Dest: document' -H 'Sec-Fetch-Mode: navigate' -H 'Sec-Fetch-Site: cross-site' -H 'Priority: u=0, i' --data-raw 'iss=https%3A%2F%2Ftest.idporten.no&code=******&state=*******'
我觉得这很奇怪。在另一个 Spring 应用程序(不是 Spring Auth Server)中,我们没有遇到任何
response_mode=form_post
问题。但这不适用于在 Spring Auth Server 中注册的 OIDC 客户端。
正如上面的评论所暗示的,Spring Security 目前不支持
response_mode = form_post
,但有一个 功能请求问题 可以投票。
问题是
org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter
不处理 POST 请求,并且 OAuth2AuthenticationException: [authorization_request_not_found]
OP 看到的错误源自此代码,从第 171 行开始
if (authorizationRequest == null) {
OAuth2Error oauth2Error = new OAuth2Error(AUTHORIZATION_REQUEST_NOT_FOUND_ERROR_CODE);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
}