我有一个简单的AuthenticationEntryPoint
,应该为未经授权的请求设置WWW-Authenticate标头。
@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {
response.setHeader("WWW-Authenticate", "FormBased");
response.sendError(401, authException.getMessage());
}
}
我在AuthorizationServerConfigurer
@Override
public void configure(AuthorizationServerSecurityConfigurer authorizationServerSecurityConfigurer) throws Exception {
authorizationServerSecurityConfigurer.authenticationEntryPoint(authenticationEntryPoint);
}
但是,这种开始方法并不总是被称为。如果请求中没有Authorize标头,或者Authorize标头值不以' Basic'开头,则会调用它。但是,如果Authorize标头以' Basic'开头,则不会调用begin方法(并且响应的值为Basic realm="oauth2/client"
)。如何确保调用此方法?
答案 0 :(得分:4)
正如AliDehghani指出的那样,这是因为BasicAuthenticationFilter
使用BasicApplicationEntryPoint
而不管ApplicationEntryPoint
中声明的AuthorizationServerSecurityConfigurer
。为了让BasicAuthenticationFilter
使用我的CustomApplicationEntryPoint
,我需要创建一个新的CustomBasicAuthenticationFilter
并将@Autowire
注释添加到构造函数中:
@Component
public class CustomBasicAuthenticationFilter extends BasicAuthenticationFilter {
@Autowired
public CustomBasicAuthenticationFilter(AuthenticationManager authenticationManager,
AuthenticationEntryPoint authenticationEntryPoint) {
super(authenticationManager, authenticationEntryPoint);
}
}
然后将其添加到AuthorizationServerConfigurer
@Override
public void configure(AuthorizationServerSecurityConfigurer authorizationServerSecurityConfigurer) throws Exception {
authorizationServerSecurityConfigurer
.authenticationEntryPoint(authenticationEntryPoint)
.addTokenEndpointAuthenticationFilter(customBasicAuthenticationFilter);
}
现在应用程序使用我的CustomBasicAuthenticationFilter
- 这在功能上等同于BasicAuthenticationFilter
。但是,它现在包括在构造期间声明的AuthenticationEntryPoint
bean - 这是我的CustomAuthenticationEntryPoint
。
答案 1 :(得分:2)
要获取访问令牌,您应该通过 HTTP Basic 验证您的客户端:
Authorization: Basic Base64(client_id:client_secret)
但是,这种开始方法并不总是被称为。它会被调用 请求中或授权时没有Authorize标头 标题值不以' Basic'开头。但是,如果授权 标题以' Basic'开头,不称为开始方法
Spring Security在内部维护一个过滤器链,其中每个过滤器都有特定的责任,其中一个是BasicAuthenticationFilter
,它将处理基本身份验证。如果你看一下doFilterInteral
方法,you would see:
if (header == null || !header.startsWith("Basic ")) {
chain.doFilter(request, response);
return;
}
如果您未传递Authorization
标头或Authorization
标头未以Basic
开头,则会跳过安全过滤器链中其他过滤器的当前过滤器。最终会抛出一个AuthenticationException
的实例,ExceptionTranslationFilter
会抓住该实例,ExceptionTranslationFilter
会调用您已注册的AuthenticationEntryPoint
。
但是当您传递基本授权标头时,BasicAuthenticationFilter
本身将处理身份验证令牌。如果传递的凭据无效,请BasicAuthenticationFilter
would catch the exception itself并致电BasicAuthenticationEntryPoint
,而不是AuthenticationEntryPoint
:
catch (AuthenticationException failed) {
SecurityContextHolder.clearContext();
if (debug) {
this.logger.debug("Authentication request for failed: " + failed);
}
this.rememberMeServices.loginFail(request, response);
onUnsuccessfulAuthentication(request, response, failed);
if (this.ignoreFailure) {
chain.doFilter(request, response);
}
else {
this.authenticationEntryPoint.commence(request, response, failed);
}
return;
}