Сервер не отвечает на запрос входа в систему с помощью Spring Security - PullRequest
0 голосов
/ 05 апреля 2020

Я защищаю REST API с помощью Spring Security и JWT (я не использую Spring Boot).

Когда я пытаюсь отправить запрос аутентификации (/login) на мой REST API у меня Could not get any response на Почтальоне

enter image description here

Вот мой фильтр JWT

public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    ...

    public AuthenticationFilter(AuthenticationManager authenticationManager) {
        super.setAuthenticationManager(authenticationManager);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try {
            ... // getting the credentials from the request
            return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(credentials.login, credentials.password));
        } 
        catch (IOException e) { throw new RuntimeException(e); }
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
            Authentication authResult) throws IOException, ServletException {

        ... // generating the jwtToken;

        response.setHeader("Authorization", jwtToken);
    }
}

Когда я отлаживаю все свое приложение работает нормально, и метод successfulAuthentication выполняется, и я получаю правильный токен, вставленный в запрос заголовка response.setHeader("Authorization", jwtToken);.

Но после этого мой REST API (или Spring Security или Tomcat) не отправляются любой ответ назад!

Вот конфигурация безопасности:

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    ...

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
                .anyRequest().authenticated()
            .and()
                .addFilter(new JwtAuthenticationFilter(authenticationManager()));
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

    }

    ...
}

Для других запросов HTTP, отличных от /login, я получил (403) HTML ответ в Postman и НЕ a JSON ответ.

<!doctype html>
<html lang="en">

<head>
    <title>HTTP Status 403 – Forbidden</title>
    ...

Итак, почему мой сервер не отвечает на запрос /login? и почему Spring security не отправляет JSON ответ на все запросы http?

Журналы после /login запроса:

DEBUG o.s.security.web.FilterChainProxy - /login at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
DEBUG o.s.security.web.FilterChainProxy - /login at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG o.s.security.web.FilterChainProxy - /login at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
DEBUG o.s.security.web.FilterChainProxy - /login at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
DEBUG o.s.security.web.util.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/logout', GET]
DEBUG o.s.security.web.util.matcher.AntPathRequestMatcher - Request 'POST /login' doesn't match 'GET /logout'
DEBUG o.s.security.web.util.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/logout', POST]
DEBUG o.s.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/login'; against '/logout'
DEBUG o.s.security.web.util.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/logout', PUT]
DEBUG o.s.security.web.util.matcher.AntPathRequestMatcher - Request 'POST /login' doesn't match 'PUT /logout'
DEBUG o.s.security.web.util.matcher.OrRequestMatcher - Trying to match using Ant [pattern='/logout', DELETE]
DEBUG o.s.security.web.util.matcher.AntPathRequestMatcher - Request 'POST /login' doesn't match 'DELETE /logout'
DEBUG o.s.security.web.util.matcher.OrRequestMatcher - No matches found
DEBUG o.s.security.web.FilterChainProxy - /login at position 5 of 11 in additional filter chain; firing Filter: 'JwtAuthenticationFilter'
DEBUG o.s.security.web.util.matcher.AntPathRequestMatcher - Checking match of request : '/login'; against '/login'
DEBUG security.JwtAuthenticationFilter - Request is to process authentication
DEBUG o.s.security.authentication.ProviderManager - Authentication attempt using o.s.security.authentication.dao.DaoAuthenticationProvider
DEBUG o.s.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler - Creating new EntityManager for shared EntityManager invocation
Hibernate: select ... 
DEBUG o.s.security.web.header.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match the requestMatcher o.s.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@5b319bff
DEBUG o.s.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed

Ответы [ 2 ]

0 голосов
/ 06 апреля 2020

Для проблемы с сервером, который не отвечает, это была глупая ошибка. В моем файле свойств я поставил имя заголовка авторизации с двойной кавычкой

security.token.header-string="Authorization"

вместо

security.token.header-string=Authorization

Для части, которую сервер не отвечает в формате JSON, я следую этому ответу

Так что мне пришлось реализовать пользовательские authenticationEntryPoint, accessDeniedHandler, authenticationSuccessHandler и authenticationFailureHandler как показано ниже:

@Override
protected void configure(HttpSecurity http) throws Exception {

    http.csrf().disable();
    http.
        authorizeRequests()
            .anyRequest().authenticated()
        .and()
        .addFilter(getJwtAuthenticationFilter())
        .exceptionHandling()
            .authenticationEntryPoint((request, response, exception) -> {
                response.setStatus(401);
            })  
            .accessDeniedHandler((request, response, exception) -> {
                response.setStatus(403);
            })
        ;

    http.
        sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

}

С JwtAuthenticationFilter

@Bean
private JwtAuthenticationFilter getJwtAuthenticationFilter() throws Exception {

    JwtAuthenticationFilter filter = new JwtAuthenticationFilter(authenticationManager());

    filter.setFilterProcessesUrl("/api/login");

    //filter.setAuthenticationSuccessHandler((request, response, authentication) -> {
    //    response.setStatus(200);
    //});

    filter.setAuthenticationFailureHandler((request, response, exception) -> {
        response.setStatus(401);
    });

    return filter;
}

Я прокомментировал строку filter.setAuthenticationSuccessHandler(...), потому что она не будет вызвана, так как я уже переопределил метод successfulAuthentication в моем JwtAuthenticationFilter класс.

0 голосов
/ 05 апреля 2020

Самое первое, я расскажу об ответе, который вы получите не в Json (для всех остальных запросов). Видите, сначала должен быть назначен метод в конечной точке URL для создания запрашиваемого контента. И содержимое, которое вы хотите, вы можете упомянуть в заголовках почтальона для json, оно должно быть Принято: Application/json

Другое дело, почему сервер не отвечает на ваш запрос на вход в систему, это то, что лучшая конфигурация должна быть в вашем случае.

http.csrf().disable()
             //You can give the request that you want to allow
         .anyRequest().authenticated()
            .and()
                .addFilter(new JwtAuthenticationFilter(authenticationManager()));
...