web-dev-qa-db-ja.com

Spring Boot Securityは401 Unauthorized Exceptionをスローしませんが、404 Not Foundをスローします

私の認証は spring-boot-security-example に基づいています。無効なトークンを入力すると、401 Unauthorized例外がスローされます。ただし、代わりに見つからない404リソースが常に表示されます。私の構成は例外処理を設定しますが、無視されます-おそらく私の前にAuthenticationFilterが追加されており、リクエストが私の例外ハンドラに到達しないためです。

代わりに401例外をスローするために何を変更する必要がありますか?

認証フィルターがあります:

public class AuthenticationFilter extends GenericFilterBean {

...

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest httpRequest = asHttp(request);
    HttpServletResponse httpResponse = asHttp(response);
    Optional<String> token = Optional.fromNullable(httpRequest.getHeader("X-Auth-Token"));

    try {
        if (token.isPresent()) {
            logger.debug("Trying to authenticate user by X-Auth-Token method. Token: {}", token);
            processTokenAuthentication(token);
            addSessionContextToLogging();
        }

        logger.debug("AuthenticationFilter is passing request down the filter chain");
        chain.doFilter(request, response);
    } catch (InternalAuthenticationServiceException internalAuthenticationServiceException) {
        SecurityContextHolder.clearContext();
        logger.error("Internal authentication service exception", internalAuthenticationServiceException);
        httpResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    } catch (AuthenticationException authenticationException) {
        SecurityContextHolder.clearContext();
        httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, authenticationException.getMessage());
    } finally {
        MDC.remove(TOKEN_SESSION_KEY);
        MDC.remove(USER_SESSION_KEY);
    }
}

private void addSessionContextToLogging() {
    ...
}

...

private void processTokenAuthentication(Optional<String> token) {
    Authentication resultOfAuthentication = tryToAuthenticateWithToken(token);
    SecurityContextHolder.getContext().setAuthentication(resultOfAuthentication);
}

private Authentication tryToAuthenticateWithToken(Optional<String> token) {
    PreAuthenticatedAuthenticationToken requestAuthentication = new PreAuthenticatedAuthenticationToken(token, null);
    return tryToAuthenticate(requestAuthentication);
}

private Authentication tryToAuthenticate(Authentication requestAuthentication) {
    Authentication responseAuthentication = authenticationManager.authenticate(requestAuthentication);
    if (responseAuthentication == null || !responseAuthentication.isAuthenticated()) {
        throw new InternalAuthenticationServiceException("Unable to authenticate Domain User for provided credentials");
    }
    logger.debug("User successfully authenticated");
    return responseAuthentication;
}

authenticationProvider実装:

@Provider
public class TokenAuthenticationProvider implements AuthenticationProvider {

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    Optional<String> token = (Optional) authentication.getPrincipal();
    if (!token.isPresent() || token.get().isEmpty()) {
        throw new BadCredentialsException("No token set.");
    }
    if (!myCheckHere()){
        throw new BadCredentialsException("Invalid token");
    }

    return new PreAuthenticatedAuthenticationToken(myConsumerObject, null, AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_API_USER"));
}

...

}

そして次のように見える設定:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.
            csrf().disable().
            sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).
            and().
            anonymous().disable().
            exceptionHandling().authenticationEntryPoint(unauthorizedEntryPoint());

    http.addFilterBefore(new AuthenticationFilter(authenticationManager()), BasicAuthenticationFilter.class);
}


@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(tokenAuthenticationProvider());
}


@Bean
public AuthenticationProvider tokenAuthenticationProvider() {
    return new TokenAuthenticationProvider();
}

@Bean
public AuthenticationEntryPoint unauthorizedEntryPoint() {
    return (request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
11
Frame91

私はこのスレッドで答えを見つけました: Return HTTP Error 401 Code&Skip Filter Chains

の代わりに

httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, authenticationException.getMessage());

電話する必要があります

httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

呼び出しを続けないと、ステータスを別のコードに設定するとチェーンが停止するようです-例外が正しくスローされます

11
Frame91

トップレベルの@SpringBootApplicationクラスに次のアノテーションを追加することで解決しました:

@EnableAutoConfiguration(exclude = {ErrorMvcAutoConfiguration.class})

Spring Bootはデフォルトのエラーページを見つけるのに問題がありますか?

5
candide

上記の回答に加えて、401を達成するようにコードを変更しました。以前は、無効または不足しているトークンで500を取得しました。

public class JwtAuthenticationTokenFilter extends AbstractAuthenticationProcessingFilter {

    public JwtAuthenticationTokenFilter() {
        super("/secure/**");
    }

    @Autowired
    private JWTService jwtService;

    @Override
    public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {


        String header = httpServletRequest.getHeader("Authorization");


        if (header == null || !header.startsWith("Bearer ")) {

            httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED,
                    "Please pass valid jwt token.");


        }else if(jwtService.validate(header.substring(7))==null){

            httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED,
                    "jwt token is invalid or incorrect");

        }
        else{

            String authenticationToken = header.substring(7);

            JwtAuthenticationToken token = new JwtAuthenticationToken(authenticationToken);
            return getAuthenticationManager().authenticate(token);
        }

        return null;

    }

}

1
Aditya Parmar