AuthenticationEntryPoint有时仅称为

时间:2016-05-09 19:22:47

标签: java spring authentication spring-security spring-security-oauth2

我有一个简单的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")。如何确保调用此方法?

2 个答案:

答案 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;
}