OAuth2 多重身份验证中的空客户端
null client in OAuth2 Multi-Factor Authentication
Spring 多重身份验证的 OAuth2 实现的完整代码已上传到 a file sharing site that you can download by clicking on this link。下面的说明解释了如何使用 link 在任何计算机上重现当前问题。 提供 500 点赏金。
当前错误:
当用户尝试在 the Spring Boot OAuth2 app from the link in the preceding paragraph 中使用双因素身份验证进行身份验证时,将触发错误。当应用程序应该提供第二个页面,要求用户输入个人识别码以确认用户身份时,会在流程中抛出错误。
鉴于空客户端触发此错误,问题似乎是如何在 Spring Boot OAuth2 中将 ClientDetailsService
连接到 Custom OAuth2RequestFactory
。
entire debug log can be read at a file sharing site by clicking on this link。日志中的完整堆栈跟踪仅包含一个对应用程序中实际代码的引用,那一行代码是:
AuthorizationRequest authorizationRequest =
oAuth2RequestFactory.createAuthorizationRequest(paramsFromRequest(request));
调试日志中抛出的错误是:
org.springframework.security.oauth2.provider.NoSuchClientException:
No client with requested id: null
抛出错误时的控制流程:
我创建了以下流程图来说明 中多重身份验证请求的预期流程:
在前面的流程图中,当前错误在 用户名和密码视图 和 GET /secure/two_factor_authenticated[= 之间的某个点被抛出150=] 步骤。
此 OP 的解决方案仅限于 1.) 通过 /oauth/authorize
端点然后 2.) returns 返回 /oauth/authorize
端点通过 TwoFactorAuthenticationController
.
所以我们只想解决NoSuchClientException
,同时也证明客户端已在POST /secure/two_factor_authenticated
中成功授予ROLE_TWO_FACTOR_AUTHENTICATED
。鉴于后续步骤是样板式的,只要用户输入 [=],流程在 SECOND PASS 进入 CustomOAuth2RequestFactory
时明显中断是可以接受的119=]SECOND PASS 以及成功完成 FIRST PASS 的所有工件。 SECOND PASS可以是一个单独的问题,只要我们在这里成功解决FIRST PASS即可。
相关代码摘录:
这是 AuthorizationServerConfigurerAdapter
的代码,我在其中尝试建立连接:
@Configuration
@EnableAuthorizationServer
protected static class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired//ADDED AS A TEST TO TRY TO HOOK UP THE CUSTOM REQUEST FACTORY
private ClientDetailsService clientDetailsService;
@Autowired//Added per:
private CustomOAuth2RequestFactory customOAuth2RequestFactory;
//THIS NEXT BEAN IS A TEST
@Bean CustomOAuth2RequestFactory customOAuth2RequestFactory(){
return new CustomOAuth2RequestFactory(clientDetailsService);
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
KeyPair keyPair = new KeyStoreKeyFactory(
new ClassPathResource("keystore.jks"), "foobar".toCharArray()
)
.getKeyPair("test");
converter.setKeyPair(keyPair);
return converter;
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("acme")//API: http://docs.spring.io/spring-security/oauth/apidocs/org/springframework/security/oauth2/config/annotation/builders/ClientDetailsServiceBuilder.ClientBuilder.html
.secret("acmesecret")
.authorizedGrantTypes("authorization_code", "refresh_token", "password")
.scopes("openid");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints//API: http://docs.spring.io/spring-security/oauth/apidocs/org/springframework/security/oauth2/config/annotation/web/configurers/AuthorizationServerEndpointsConfigurer.html
.authenticationManager(authenticationManager)
.accessTokenConverter(jwtAccessTokenConverter())
.requestFactory(customOAuth2RequestFactory);//Added per:
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer//API: http://docs.spring.io/spring-security/oauth/apidocs/org/springframework/security/oauth2/config/annotation/web/configurers/AuthorizationServerSecurityConfigurer.html
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
}
这是 TwoFactorAuthenticationFilter
的代码,其中包含上面触发错误的代码:
package demo;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
//This class is added per:
/**
* Stores the oauth authorizationRequest in the session so that it can
* later be picked by the {@link com.example.CustomOAuth2RequestFactory}
* to continue with the authoriztion flow.
*/
public class TwoFactorAuthenticationFilter extends OncePerRequestFilter {
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
private OAuth2RequestFactory oAuth2RequestFactory;
//These next two are added as a test to avoid the compilation errors that happened when they were not defined.
public static final String ROLE_TWO_FACTOR_AUTHENTICATED = "ROLE_TWO_FACTOR_AUTHENTICATED";
public static final String ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED = "ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED";
@Autowired
public void setClientDetailsService(ClientDetailsService clientDetailsService) {
oAuth2RequestFactory = new DefaultOAuth2RequestFactory(clientDetailsService);
}
private boolean twoFactorAuthenticationEnabled(Collection<? extends GrantedAuthority> authorities) {
return authorities.stream().anyMatch(
authority -> ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED.equals(authority.getAuthority())
);
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// Check if the user hasn't done the two factor authentication.
if (AuthenticationUtil.isAuthenticated() && !AuthenticationUtil.hasAuthority(ROLE_TWO_FACTOR_AUTHENTICATED)) {
AuthorizationRequest authorizationRequest = oAuth2RequestFactory.createAuthorizationRequest(paramsFromRequest(request));
/* Check if the client's authorities (authorizationRequest.getAuthorities()) or the user's ones
require two factor authenticatoin. */
if (twoFactorAuthenticationEnabled(authorizationRequest.getAuthorities()) ||
twoFactorAuthenticationEnabled(SecurityContextHolder.getContext().getAuthentication().getAuthorities())) {
// Save the authorizationRequest in the session. This allows the CustomOAuth2RequestFactory
// to return this saved request to the AuthenticationEndpoint after the user successfully
// did the two factor authentication.
request.getSession().setAttribute(CustomOAuth2RequestFactory.SAVED_AUTHORIZATION_REQUEST_SESSION_ATTRIBUTE_NAME, authorizationRequest);
// redirect the the page where the user needs to enter the two factor authentiation code
redirectStrategy.sendRedirect(request, response,
ServletUriComponentsBuilder.fromCurrentContextPath()
.path(TwoFactorAuthenticationController.PATH)
.toUriString());
return;
}
}
filterChain.doFilter(request, response);
}
private Map<String, String> paramsFromRequest(HttpServletRequest request) {
Map<String, String> params = new HashMap<>();
for (Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
params.put(entry.getKey(), entry.getValue()[0]);
}
return params;
}
}
在您的计算机上重新创建问题:
按照以下简单步骤,您可以在几分钟内在任何计算机上重现该问题:
1.) 下载 zipped version of the app from a file sharing site by clicking on this link。
2.) 通过键入解压缩应用程序:tar -zxvf oauth2.tar(1).gz
3.) 通过导航到 oauth2/authserver
然后键入 mvn spring-boot:run
来启动 authserver
应用程序。
4.) 通过导航到 oauth2/resource
然后键入 mvn spring-boot:run
来启动 resource
应用程序
5.) 通过导航到 oauth2/ui
然后键入 mvn spring-boot:run
来启动 ui
应用程序
6.) 打开网络浏览器并导航至 http : // localhost : 8080
7.) 点击Login
然后输入Frodo
作为用户和MyRing
作为密码,点击提交。 这将触发上面显示的错误。
您可以通过以下方式查看完整的源代码:
a.) 将 Maven 项目导入您的 IDE,或通过
b.) 在解压缩的目录中导航并使用文本编辑器打开。
注:上面文件分享link中的代码是the Spring Boot OAuth2 GitHub sample at this link, and the . The only changes to the Spring Boot GitHub sample have been in the authserver
app, specifically in authserver/src/main/java
and in authserver/src/main/resources/templates
的组合。
缩小问题范围:
根据@AbrahamGrief 的建议,我添加了一个 FilterConfigurationBean
,它解决了 NoSuchClientException
。但是OP询问如何通过图中的控制流程完成FIRST PASS以获得500点赏金。
然后我通过在 Users.loadUserByUername()
中设置 ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED
来缩小问题范围,如下所示:
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
String password;
List<GrantedAuthority> auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER");
if (username.equals("Samwise")) {//ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED will need to come from the resource, NOT the user
auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_HOBBIT, ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED");
password = "TheShire";
}
else if (username.equals("Frodo")){//ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED will need to come from the resource, NOT the user
auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_HOBBIT, ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED");
password = "MyRing";
}
else{throw new UsernameNotFoundException("Username was not found. ");}
return new org.springframework.security.core.userdetails.User(username, password, auth);
}
这消除了配置客户端和资源的需要,从而使当前问题仍然缩小。但是,下一个障碍是 Spring 安全部门拒绝了用户对 /security/two_factor_authentication
的请求。 为了通过控制流完成 FIRST PASS 需要做哪些进一步的更改,以便 POST /secure/two_factor_authentication
可以 SYSO ROLE_TWO_FACTOR_AUTHENTICATED
?
该项目需要进行 很多 的修改才能实现所描述的流程,这超出了单个问题的范围。这个答案将只关注如何解决:
org.springframework.security.oauth2.provider.NoSuchClientException: No
client with requested id: null
在 Spring 引导授权服务器中 运行 时尝试使用 SecurityWebApplicationInitializer
和 Filter
bean。
发生此异常的原因是 WebApplicationInitializer
instances are not run by Spring Boot。这包括可以在部署到独立 Servlet 容器的 WAR 中工作的任何 AbstractSecurityWebApplicationInitializer
子类。所以发生的事情是 Spring Boot 由于 @Bean
注释创建了您的过滤器,忽略了您的 AbstractSecurityWebApplicationInitializer
,并将您的过滤器应用于所有 URL。同时,您只希望将过滤器应用于您尝试传递给 addMappingForUrlPatterns
.
的那些 URL
相反,要将 servlet 过滤器应用于 Spring 引导中的特定 URL,您应该 define a FilterConfigurationBean
。对于问题中描述的流程,它试图将自定义 TwoFactorAuthenticationFilter
应用于 /oauth/authorize
,如下所示:
@Bean
public FilterRegistrationBean twoFactorAuthenticationFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(twoFactorAuthenticationFilter());
registration.addUrlPatterns("/oauth/authorize");
registration.setName("twoFactorAuthenticationFilter");
return registration;
}
@Bean
public TwoFactorAuthenticationFilter twoFactorAuthenticationFilter() {
return new TwoFactorAuthenticationFilter();
}
Spring 多重身份验证的 OAuth2 实现的完整代码已上传到 a file sharing site that you can download by clicking on this link。下面的说明解释了如何使用 link 在任何计算机上重现当前问题。 提供 500 点赏金。
当前错误:
当用户尝试在 the Spring Boot OAuth2 app from the link in the preceding paragraph 中使用双因素身份验证进行身份验证时,将触发错误。当应用程序应该提供第二个页面,要求用户输入个人识别码以确认用户身份时,会在流程中抛出错误。
鉴于空客户端触发此错误,问题似乎是如何在 Spring Boot OAuth2 中将 ClientDetailsService
连接到 Custom OAuth2RequestFactory
。
entire debug log can be read at a file sharing site by clicking on this link。日志中的完整堆栈跟踪仅包含一个对应用程序中实际代码的引用,那一行代码是:
AuthorizationRequest authorizationRequest =
oAuth2RequestFactory.createAuthorizationRequest(paramsFromRequest(request));
调试日志中抛出的错误是:
org.springframework.security.oauth2.provider.NoSuchClientException:
No client with requested id: null
抛出错误时的控制流程:
我创建了以下流程图来说明
在前面的流程图中,当前错误在 用户名和密码视图 和 GET /secure/two_factor_authenticated[= 之间的某个点被抛出150=] 步骤。
此 OP 的解决方案仅限于 1.) 通过 /oauth/authorize
端点然后 2.) returns 返回 /oauth/authorize
端点通过 TwoFactorAuthenticationController
.
所以我们只想解决NoSuchClientException
,同时也证明客户端已在POST /secure/two_factor_authenticated
中成功授予ROLE_TWO_FACTOR_AUTHENTICATED
。鉴于后续步骤是样板式的,只要用户输入 [=],流程在 SECOND PASS 进入 CustomOAuth2RequestFactory
时明显中断是可以接受的119=]SECOND PASS 以及成功完成 FIRST PASS 的所有工件。 SECOND PASS可以是一个单独的问题,只要我们在这里成功解决FIRST PASS即可。
相关代码摘录:
这是 AuthorizationServerConfigurerAdapter
的代码,我在其中尝试建立连接:
@Configuration
@EnableAuthorizationServer
protected static class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired//ADDED AS A TEST TO TRY TO HOOK UP THE CUSTOM REQUEST FACTORY
private ClientDetailsService clientDetailsService;
@Autowired//Added per:
private CustomOAuth2RequestFactory customOAuth2RequestFactory;
//THIS NEXT BEAN IS A TEST
@Bean CustomOAuth2RequestFactory customOAuth2RequestFactory(){
return new CustomOAuth2RequestFactory(clientDetailsService);
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
KeyPair keyPair = new KeyStoreKeyFactory(
new ClassPathResource("keystore.jks"), "foobar".toCharArray()
)
.getKeyPair("test");
converter.setKeyPair(keyPair);
return converter;
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("acme")//API: http://docs.spring.io/spring-security/oauth/apidocs/org/springframework/security/oauth2/config/annotation/builders/ClientDetailsServiceBuilder.ClientBuilder.html
.secret("acmesecret")
.authorizedGrantTypes("authorization_code", "refresh_token", "password")
.scopes("openid");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints//API: http://docs.spring.io/spring-security/oauth/apidocs/org/springframework/security/oauth2/config/annotation/web/configurers/AuthorizationServerEndpointsConfigurer.html
.authenticationManager(authenticationManager)
.accessTokenConverter(jwtAccessTokenConverter())
.requestFactory(customOAuth2RequestFactory);//Added per:
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer//API: http://docs.spring.io/spring-security/oauth/apidocs/org/springframework/security/oauth2/config/annotation/web/configurers/AuthorizationServerSecurityConfigurer.html
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
}
这是 TwoFactorAuthenticationFilter
的代码,其中包含上面触发错误的代码:
package demo;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
//This class is added per:
/**
* Stores the oauth authorizationRequest in the session so that it can
* later be picked by the {@link com.example.CustomOAuth2RequestFactory}
* to continue with the authoriztion flow.
*/
public class TwoFactorAuthenticationFilter extends OncePerRequestFilter {
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
private OAuth2RequestFactory oAuth2RequestFactory;
//These next two are added as a test to avoid the compilation errors that happened when they were not defined.
public static final String ROLE_TWO_FACTOR_AUTHENTICATED = "ROLE_TWO_FACTOR_AUTHENTICATED";
public static final String ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED = "ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED";
@Autowired
public void setClientDetailsService(ClientDetailsService clientDetailsService) {
oAuth2RequestFactory = new DefaultOAuth2RequestFactory(clientDetailsService);
}
private boolean twoFactorAuthenticationEnabled(Collection<? extends GrantedAuthority> authorities) {
return authorities.stream().anyMatch(
authority -> ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED.equals(authority.getAuthority())
);
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// Check if the user hasn't done the two factor authentication.
if (AuthenticationUtil.isAuthenticated() && !AuthenticationUtil.hasAuthority(ROLE_TWO_FACTOR_AUTHENTICATED)) {
AuthorizationRequest authorizationRequest = oAuth2RequestFactory.createAuthorizationRequest(paramsFromRequest(request));
/* Check if the client's authorities (authorizationRequest.getAuthorities()) or the user's ones
require two factor authenticatoin. */
if (twoFactorAuthenticationEnabled(authorizationRequest.getAuthorities()) ||
twoFactorAuthenticationEnabled(SecurityContextHolder.getContext().getAuthentication().getAuthorities())) {
// Save the authorizationRequest in the session. This allows the CustomOAuth2RequestFactory
// to return this saved request to the AuthenticationEndpoint after the user successfully
// did the two factor authentication.
request.getSession().setAttribute(CustomOAuth2RequestFactory.SAVED_AUTHORIZATION_REQUEST_SESSION_ATTRIBUTE_NAME, authorizationRequest);
// redirect the the page where the user needs to enter the two factor authentiation code
redirectStrategy.sendRedirect(request, response,
ServletUriComponentsBuilder.fromCurrentContextPath()
.path(TwoFactorAuthenticationController.PATH)
.toUriString());
return;
}
}
filterChain.doFilter(request, response);
}
private Map<String, String> paramsFromRequest(HttpServletRequest request) {
Map<String, String> params = new HashMap<>();
for (Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
params.put(entry.getKey(), entry.getValue()[0]);
}
return params;
}
}
在您的计算机上重新创建问题:
按照以下简单步骤,您可以在几分钟内在任何计算机上重现该问题:
1.) 下载 zipped version of the app from a file sharing site by clicking on this link。
2.) 通过键入解压缩应用程序:tar -zxvf oauth2.tar(1).gz
3.) 通过导航到 oauth2/authserver
然后键入 mvn spring-boot:run
来启动 authserver
应用程序。
4.) 通过导航到 oauth2/resource
然后键入 mvn spring-boot:run
resource
应用程序
5.) 通过导航到 oauth2/ui
然后键入 mvn spring-boot:run
ui
应用程序
6.) 打开网络浏览器并导航至 http : // localhost : 8080
7.) 点击Login
然后输入Frodo
作为用户和MyRing
作为密码,点击提交。 这将触发上面显示的错误。
您可以通过以下方式查看完整的源代码:
a.) 将 Maven 项目导入您的 IDE,或通过
b.) 在解压缩的目录中导航并使用文本编辑器打开。
注:上面文件分享link中的代码是the Spring Boot OAuth2 GitHub sample at this link, and the authserver
app, specifically in authserver/src/main/java
and in authserver/src/main/resources/templates
的组合。
缩小问题范围:
根据@AbrahamGrief 的建议,我添加了一个
FilterConfigurationBean
,它解决了 NoSuchClientException
。但是OP询问如何通过图中的控制流程完成FIRST PASS以获得500点赏金。
然后我通过在 Users.loadUserByUername()
中设置 ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED
来缩小问题范围,如下所示:
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
String password;
List<GrantedAuthority> auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER");
if (username.equals("Samwise")) {//ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED will need to come from the resource, NOT the user
auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_HOBBIT, ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED");
password = "TheShire";
}
else if (username.equals("Frodo")){//ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED will need to come from the resource, NOT the user
auth = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_HOBBIT, ROLE_TWO_FACTOR_AUTHENTICATION_ENABLED");
password = "MyRing";
}
else{throw new UsernameNotFoundException("Username was not found. ");}
return new org.springframework.security.core.userdetails.User(username, password, auth);
}
这消除了配置客户端和资源的需要,从而使当前问题仍然缩小。但是,下一个障碍是 Spring 安全部门拒绝了用户对 /security/two_factor_authentication
的请求。 为了通过控制流完成 FIRST PASS 需要做哪些进一步的更改,以便 POST /secure/two_factor_authentication
可以 SYSO ROLE_TWO_FACTOR_AUTHENTICATED
?
该项目需要进行 很多 的修改才能实现所描述的流程,这超出了单个问题的范围。这个答案将只关注如何解决:
org.springframework.security.oauth2.provider.NoSuchClientException: No client with requested id: null
在 Spring 引导授权服务器中 运行 时尝试使用 SecurityWebApplicationInitializer
和 Filter
bean。
发生此异常的原因是 WebApplicationInitializer
instances are not run by Spring Boot。这包括可以在部署到独立 Servlet 容器的 WAR 中工作的任何 AbstractSecurityWebApplicationInitializer
子类。所以发生的事情是 Spring Boot 由于 @Bean
注释创建了您的过滤器,忽略了您的 AbstractSecurityWebApplicationInitializer
,并将您的过滤器应用于所有 URL。同时,您只希望将过滤器应用于您尝试传递给 addMappingForUrlPatterns
.
相反,要将 servlet 过滤器应用于 Spring 引导中的特定 URL,您应该 define a FilterConfigurationBean
。对于问题中描述的流程,它试图将自定义 TwoFactorAuthenticationFilter
应用于 /oauth/authorize
,如下所示:
@Bean
public FilterRegistrationBean twoFactorAuthenticationFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(twoFactorAuthenticationFilter());
registration.addUrlPatterns("/oauth/authorize");
registration.setName("twoFactorAuthenticationFilter");
return registration;
}
@Bean
public TwoFactorAuthenticationFilter twoFactorAuthenticationFilter() {
return new TwoFactorAuthenticationFilter();
}