Spring Security cookie仅在第一次禁止请求后才到达Angular

时间:2017-01-18 13:50:43

标签: angularjs spring-security angular-cookies

我使用Spring Security通过AngularJS保护我的Spring Data REST Web应用程序。

我的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());
}

我通常会按this链接来达到目标​​。

现在,如果我第一次登录自己,$cookies.get("XSRF-TOKEN")的角度请求会返回 undefined ,并且我的数据库的每个请求都不会被阻止。

但是在注销并再次登录后,它会返回cookie并允许每个数据库请求。

这只会在每次登录时发生,所以:

  1. 未定义
  2. 饼干
  3. 未定义
  4. 饼干
  5. 未定义

    ...

  6. 所以现在我希望有人可以帮助我而不深入我的结构,但如果需要,我会这样做。

    提前致谢。

    编辑1:以下是请求: enter image description here

    关于流程:我在我的CokieCsrfTokenRepository()。loadToken()中记录了令牌,并显示了所有令牌..

    编辑2:我的Angular服务,我每次登录时都会调用它:

    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,则只有在注销并刷新浏览器后才会调用this链接中的方法loadToken()(首次登录) 。然后显示令牌并再次登录。但经过每一秒尝试它仍然很好..

    编辑4:所以我没有认识到,在第一个禁止的POST请求之后(在Edit3中它是&logout),令牌到达我的模板。刷新浏览器后,我的所有请求都被允许,因为现在每个请求都会发送cookie。但是如何解决这个问题?

1 个答案:

答案 0 :(得分:-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);
    }
}