Файл cookie Spring Security поступает в Angular только после первого запрещенного запроса

Я использую Spring Security для защиты своего веб-приложения Spring Data REST с AngularJS.

Мой SecurityConfig объявлен так:

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

  http
    .httpBasic().and()
    .authorizeRequests()

    // public ressources
    .antMatchers("/index.html", "/templates/public/**", "/js/**", "/").permitAll()
    .antMatchers(HttpMethod.GET, "/api/security/user").permitAll()
    .antMatchers("/api/**").hasAnyRole("ADMIN", "NORMALUSER")

    .anyRequest().authenticated()
    .and().exceptionHandling().authenticationEntryPoint(basicAuthenticationEntryPointHandler)

    .and().logout().logoutUrl("/logout").logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler()).deleteCookies("JSESSIONID").permitAll().and()
    .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}

Я обычно следовал по этой ссылке для достижения своей цели.

Теперь, если я войду в свой аккаунт впервые, angular-запрос для $cookies.get("XSRF-TOKEN") возвращает неопределенное значение, и каждый запрос к моей базе данных не блокируется.

Но после выхода и повторного входа мне возвращается cookie, и каждый запрос к базе данных разрешен.

И это происходит только при каждом втором входе в систему, поэтому:

  1. не определено
  2. печенье
  3. не определено
  4. печенье
  5. не определено

    ...

Так что теперь я надеюсь, что найдется кто-нибудь, кто сможет помочь мне, не углубляясь в мою структуру, но если это потребуется, я сделаю это.

Заранее спасибо.

Редактировать 1: Вот запросы:

Относительно процесса: я регистрирую токены в моем CokieCsrfTokenRepository(). LoadToken(), и там отображаются все токены..

Редактировать 2: Мой Angular Service, который я вызываю при каждом входе в систему:

function authenticationService($rootScope, $http, $location, $filter, $cookies){    
    function authenticate(credentials, callback) {

        var headers = credentials ? {authorization : "Basic "
            + btoa(credentials.username + ":" + credentials.password)
        } : {};

        $http.get('api/security/user', {headers : headers}).success(function(data, status, get, header) {
            if (data.name) {
                $rootScope.authenticated = true;
                $rootScope.session = data;
                console.log($cookies.get("XSRF-TOKEN")) // -> returns every second login cookie

            } else {
                $rootScope.authenticated = false;
                $rootScope.session = null;
            }

            console.log($rootScope.session)

            callback && callback();
        }).error(function() {
            $rootScope.authenticated = false;

            callback && callback();
        });

    }

    return {
        authenticate: function(credentials){
            authenticate(credentials, function() {
                if ($rootScope.authenticated == true) {
                    $rootScope.authenticationError = false;

                    if ($rootScope.session.principal.admin == true){
                        $location.path("/admin/manage");
                    } else{
                        $location.path("/user");
                    }
                } else {
                    $rootScope.authenticationError = true;

                    $location.path("/login");
                }
            });
        },
        // called by refreshing browser
        checkLoggedIn: function(){
            authenticate();
        },

        logout: function(){
            $http.post('/logout', {})["finally"](function() {
                $rootScope.authenticated = false;
                $rootScope.session = null;
                $location.path("/login");
            });
        }
    };
}

Редактировать 3: Я уже упоминал, что если cookie не определен, метод loadToken() по этой ссылке вызывается только после выхода из системы и обновления браузера (первый вход в систему). Затем отображается токен, и я снова вхожу в систему. Но после каждой второй попытки это все еще прекрасно работает..

Edit 4: Так что я не узнал, что после первого запрещенного POST-запроса (в Edit 3 это /logout) токен приходит в мой шаблон. После обновления браузера все мои запросы разрешены, потому что теперь cookie будет отправляться для каждого запроса. Но как это исправить?

1 ответ

Решение

Мое решение:

//WebSecurityConfigurerAdapter:
@Override
protected void configure(HttpSecurity http) throws Exception {
    http
    ....
    .addFilterAfter(new CsrfCustomFilter(), CsrfFilter.class).and()
    .csrf().csrfTokenRepository(csrfTokenRepository());
}

private CsrfTokenRepository csrfTokenRepository() {
    HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
    repository.setHeaderName("X-XSRF-TOKEN");
    return repository;
}

public class CsrfCustomFilter extends OncePerRequestFilter{

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());

        if (csrf != null) {
            Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
            String token = csrf.getToken();

            if (cookie==null || token!=null && !token.equals(cookie.getValue())) {
                cookie = new Cookie("XSRF-TOKEN", token);
                cookie.setPath("/");
                response.addCookie(cookie);
            }
        }

        filterChain.doFilter(request, response);
    }
}
Другие вопросы по тегам