【问题标题】:Spring Custom Authentication Provider- how to return custom REST Http Status when authentication failsSpring Custom Authentication Provider - 身份验证失败时如何返回自定义 REST Http 状态
【发布时间】:2022-08-16 14:24:14
【问题描述】:

我有自定义身份验证提供程序可以正常工作:

@Component
public class ApiAuthenticationProvider implements AuthenticationProvider {

    @Override
    public Authentication authenticate(final Authentication authentication) throws AuthenticationException {
        final String name = authentication.getName();
        final String password = authentication.getCredentials().toString();

        if (isAuthorizedDevice(name, password)) {
            final List<GrantedAuthority> grantedAuths = new ArrayList<>();
            grantedAuths.add(new SimpleGrantedAuthority(ApiInfo.Role.User));

            final UserDetails principal = new User(name, password, grantedAuths);
            return new UsernamePasswordAuthenticationToken(principal, password, grantedAuths);
        } else {
            return null;
        }
}

但它总是返回 401。我想在某些情况下将其更改为 429 以实现蛮力机制。我不想返回 null 我想返回错误:f.e.: 429。我认为不应该在这里完成。应该在配置中完成:WebSecurityConfig 但我不知道如何实现这一点。

我已经尝试抛出异常,例如:

throw new LockedException(\"InvalidCredentialsFilter\");
throw new AuthenticationCredentialsNotFoundException(\"Invalid Credentials!\");

或注入响应对象并设置其状态:

 response.setStatus(429);

但没有一个奏效。它总是返回 401。

即:

  curl http://localhost:8080/api/v1.0/time   --header \"Authorization: Basic poaueiccrmpoawklerpo0i\"
{\"timestamp\":\"2022-08-12T20:58:42.236+00:00\",\"status\":401,\"error\":\"Unauthorized\",\"path\":\"/api/v1.0/time\"}%      

与身体:

白标错误页面

此应用程序没有显式映射 /error,因此您将其视为后备。 2022 年 8 月 12 日星期五 22:58:17 CEST 出现意外错误(类型=未授权,状态=401)。

也找不到任何文档或 Baeldung 教程。

你能帮助我吗?

PS我的WebSecurityConfig:


@Configuration
@EnableWebSecurity
class WebSecurityConfig {

    AuthenticationProvider apiAuthenticationProvider;


    @Bean
    public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
        return http
                .csrf().disable()
                .formLogin().disable()
                .httpBasic().and()
                .authenticationProvider(apiAuthenticationProvider)
                .authorizeRequests()
                .antMatchers(ApiInfo.BASE_URL + \"/**\")
                .fullyAuthenticated()
                .and()
                .build();
    }
  • But non of it worked 没用怎么办?预期什么,结果如何返回等?还。 spring security 的文档在他们的网页上。仅仅因为它没有 Baldung 页面,并不意味着没有信息。 Baeldung 不是官方文档。
  • F.E. 这里是与抛出错误相同的示例:marcobehler.com/guides/spring-security
  • 我在回答问题,因为我每天都会有空闲时间回答问题。我不会花几个小时来解决你的问题,因为我没有得到报酬来解决你的问题。我投了反对票,因为如果您阅读了 architecture 上的章节,那么如何处理异常在 spring security 官方文档中,这是您在 spring security 中编写代码之前应该阅读的章节,或者发布有关堆栈溢出的问题。但我要给你一个提示,他抛出什么异常,你抛出什么异常......并非所有异常都是相同的。

标签: spring spring-boot spring-security


【解决方案1】:

由于我没有有用的答案,我将发布我的解决方案。

一般来说,我添加了 AuthenticationEntryPoint 的自定义实现,它处理所有未经授权的请求,并在 AuthenticationProvider 之后进行:

@Component
public class BruteForceEntryPoint implements AuthenticationEntryPoint {
    final BruteForce bruteForce;
    static final String WWW_AUTHENTICATE_HEADER_VALUE = "Basic realm=\"Access to API\", charset=\"UTF-8\"";

    public BruteForceEntryPoint(BruteForce bruteForce) {
        this.bruteForce = bruteForce;
    }

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        addWwwAuthenticateHeader(request, response);
        bruteForce.incrementFailures(request.getRemoteAddr());
        if (bruteForce.IsBlocked(request.getRemoteAddr())) {
            response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
            OutputStream responseStream = response.getOutputStream();
            ObjectMapper mapper = new ObjectMapper();
            mapper.writeValue(responseStream, HttpStatus.TOO_MANY_REQUESTS);
            responseStream.flush();
        } else {
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            OutputStream responseStream = response.getOutputStream();
            ObjectMapper mapper = new ObjectMapper();
            mapper.writeValue(responseStream, HttpStatus.UNAUTHORIZED);
            responseStream.flush();
        }
    }

    void addWwwAuthenticateHeader(HttpServletRequest request, HttpServletResponse response) {
        if (isWwwAuthenticateSupported(request)) {
            response.addHeader(WWW_AUTHENTICATE, WWW_AUTHENTICATE_HEADER_VALUE);
        }
    }
}

配置:

@Configuration
class WebSecurityConfig {

    AuthenticationProvider apiAuthenticationProvider;
    AuthenticationEntryPoint customAuthenticationEntryPoint;

    public WebSecurityConfig(AuthenticationProvider apiAuthenticationProvider, AuthenticationEntryPoint customAuthenticationEntryPoint) {
        this.apiAuthenticationProvider = apiAuthenticationProvider;
        this.customAuthenticationEntryPoint = customAuthenticationEntryPoint;
    }

    @Bean
    public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
        return
                http
                        .httpBasic()
                        .authenticationEntryPoint(customAuthenticationEntryPoint)
                        .and()
                        .authorizeRequests()
                        .antMatchers(AapiInfo.BASE_URL + "/**").authenticated()
                        .and()
                        .authenticationProvider(apiAuthenticationProvider)
                        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                        .and()
                        .csrf().disable()
                        .formLogin().disable()
                        .logout().disable()
                        .build();
    }

【讨论】:

    猜你喜欢
    • 2017-04-09
    • 2021-09-27
    • 1970-01-01
    • 1970-01-01
    • 2020-03-16
    • 2023-03-19
    • 2020-02-17
    • 2017-10-03
    • 2019-02-02
    相关资源
    最近更新 更多