【问题标题】:Spring security - Custom ExceptionTranslationFilterSpring security - 自定义 ExceptionTranslationFilter
【发布时间】:2016-09-04 21:43:44
【问题描述】:

这个问题其实和这个问题problem有关。

根据@harsh-poddar 的建议,我相应地添加了过滤器。

但是,在添加之后,即使使用有效的凭据,我似乎也无法登录。

以下是相关代码:

安全配置

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

//  @Bean
//  public CustomAuthenticationEntryPoint customAuthenticationEntryPoint() {
//      return new CustomAuthenticationEntryPoint();
//  }

@Bean
public CustomExceptionTranslationFilter customExceptionTranslationFilter() {
    return new CustomExceptionTranslationFilter(new CustomAuthenticationEntryPoint());
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        //Note : Able to login without this filter, but after adding this, valid credential also fails
        .addFilterAfter(customExceptionTranslationFilter(), ExceptionTranslationFilter.class)
//      .exceptionHandling()
//          .authenticationEntryPoint(new customAuthenticationEntryPoint())
//          .and()
        .authorizeRequests()
            .anyRequest().authenticated()
            .and()
        .requestCache()
            .requestCache(new NullRequestCache())
            .and()
        .httpBasic()
            .and()
        .csrf().disable();
}

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(new CustomAuthenticationProvider());
    }
}

CustomAuthenticationProvider

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

public CustomAuthenticationProvider() {
    super();
}

@Override
public Authentication authenticate(final Authentication authentication) throws AuthenticationException  {
    final String name = authentication.getName();
    final String password = authentication.getCredentials().toString();
    if (name.equals("admin") && password.equals("password")) {
        final List<GrantedAuthority> grantedAuths = new ArrayList<>();
        grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
        final UserDetails principal = new User(name, password, grantedAuths);
        final Authentication auth = new UsernamePasswordAuthenticationToken(principal, password, grantedAuths);
        return auth;
    } else {
        throw new BadCredentialsException("NOT_AUTHORIZED");
    }
}

    @Override
    public boolean supports(final Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }

}

CustomExceptionTranslationFilter

@Component
public class CustomExceptionTranslationFilter extends ExceptionTranslationFilter {

    public CustomExceptionTranslationFilter(AuthenticationEntryPoint authenticationEntryPoint) {
        super(authenticationEntryPoint);
    }
}

CustomAuthenticationEntryPoint

public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
            AuthenticationException authException) throws IOException, ServletException {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized.");
    }
}

p/s:对于这个基本问题,我很抱歉,我是 spring 和 spring 安全方面的新手。

【问题讨论】:

  • 在前面的问题stackoverflow.com/questions/37063342/…中查看我的答案
  • @D0dger :感谢您的回答。但仍然存在相同的错误。使用有效凭据登录也会触发“AuthExceptionEntryPoint”。有什么提示我可以在哪里检查以进行调试?
  • 打开org.springframework.security 包的日志记录并将其附加到问题(当有效凭据不起作用时)

标签: java spring spring-mvc spring-security


【解决方案1】:

AuthenticationEntryPoint 的预期设计是启动/启动身份验证。但是,您的实现 CustomAuthenticationEntryPoint 不会这样做。相反,它只是发回未经授权的响应。请参阅 AuthenticationEntryPoint 的 javadoc,了解有关实现细节的更多详细信息。

根据您的配置,您正在使用 HTTP Basic 进行身份验证:

protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .anyRequest().authenticated()
            .and()
        .httpBasic();
}

这个具体配置会自动配置BasicAuthenticationEntryPoint,这是AuthenticationEntryPoint的一个实现。根据server protocolBasicAuthenticationEntryPoint 将使用WWW-Authenticate: Basic realm="User Realm" 的http 响应标头挑战用户进行身份验证。

但是,您正在配置自己的CustomAuthenticationEntryPoint,它最终会覆盖BasicAuthenticationEntryPoint,这不是您想要做的。

other post 推荐了这个配置,这又不是你想做的。

protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .anyRequest().authenticated()
            .and()
        .httpBasic()
            .and()
        .exceptionHandling().authenticationEntryPoint(new CustomAuthenticationEntryPoint());
}

如果您的主要目标是在身份验证失败时向用户提供自定义响应,那么我会建议使用配置的AuthenticationFailureHandler 进行表单登录配置。这是配置:

http
    .authorizeRequests()
        .anyRequest().authenticated()
        .and()
    .formLogin().failureHandler(new DefaultAuthenticationFailureHandler())
        .and()
    .csrf().disable();   // NOTE: I would recommend enabling CSRF

您对DefaultAuthenticationFailureHandler 的实现将是:

public class DefaultAuthenticationFailureHandler implements AuthenticationFailureHandler {

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        // Set status only OR do whatever you want to the response
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
    }
}

AuthenticationFailureHandler 专门用于处理失败的身份验证尝试。

【讨论】:

  • 感谢您的建议。我已经尝试过了,发现每个请求都被重定向(302)到“/login”。供您参考,这是一个通过 @RestController 进行通信的 Web 服务。
猜你喜欢
  • 2015-01-27
  • 2020-09-24
  • 1970-01-01
  • 1970-01-01
  • 2018-01-13
  • 2015-12-15
  • 2016-04-23
  • 2013-05-22
  • 1970-01-01
相关资源
最近更新 更多