Spring 安全 & Angular

Spring security & Angular

我在前端使用 Angular,在后端使用 spring 安全处理安全。

但是,Spring 秒不会对用户进行身份验证。对于有效和无效凭证,其行为是相同的。我想捕获 "bad credential" 无效的用户或密码以及有效凭据的用户数据。 我的问题是什么,我该如何处理?谢谢

spring 安全配置

    @Bean
public BCryptPasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

@Bean
public JdbcUserDetailsManager userDetailsManager(AuthenticationManager authenticationManager, DataSource dataSource) {
    JdbcUserDetailsManager userDetailsService = new JdbcUserDetailsManager();
    userDetailsService.setDataSource(dataSource);
    userDetailsService.setAuthenticationManager(authenticationManager);
    return userDetailsService;
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(passwordEncoder());
}

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/webjars/**", "/resources/**", "/js/**", "/public/**");
}

@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
}

@Override
protected void configure(HttpSecurity http) throws Exception {        
    http
            .authorizeRequests().antMatchers("/login").permitAll().and()
            .authorizeRequests().antMatchers("/index").permitAll().and()

            .authorizeRequests().anyRequest().hasRole("USER").and()
            .exceptionHandling()
            .accessDeniedPage("/index?authorization_error=true")
            .and()

            .csrf()
            .csrfTokenRepository(csrfTokenRepository())
            .requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize")).disable()
            .addFilterAfter(csrfHeaderFilter(), CsrfFilter.class)

            .logout()
            .logoutSuccessUrl("/index")
            .logoutUrl("/logout.do")
            .and()

            .formLogin()
            .usernameParameter("j_username")
            .passwordParameter("j_password")
            .failureUrl("/index?authentication_error=true")
            .loginPage("/index")
            .loginProcessingUrl("/j_security_check")
            .and()

            .sessionManagement().maximumSessions(1);
}

private Filter csrfHeaderFilter() {
    return new 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);
        }
    };
}

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

}

Angular 控制器:

        var loginService = function () {
        var deferred = $q.defer();
        $http.post(contextPath + '/j_security_check', {j_username: $scope.credentials.j_username, j_password: $scope.credentials.j_password}).
            success(function (data) {
                deferred.resolve(data);
            }).
            error(function (data, status, header, config) {
                $log.warn(data, status, header(), config);
                deferred.reject(status);
            });
        return deferred.promise;
    };
    $scope.login = function () {
        loginService().then(function (result) {
            console.log(result);
            $state.go('dashboard');
        }, function (result) {
            switch (result) {
                case 401:
                    $scope.message = "Error " + result + ": username or password is not correct";
                    break;
                case 403:
                    $scope.message = "Error " + result + ": username or password is not correct";
                    break;
                default :
                    $scope.message = "Error " + result + " :unknown error";
            }
        })
    };

谢谢

更新:

检查这个类似的 SO 问题,其中有示例 angularjs http 拦截器直接获取 csrf 参数并在所有请求中添加 headers。

REASON for default angularJS 不能像 link

中提到的那样工作

默认情况下 AngularJS 提供了一种实现跨站点请求伪造的机制,但是该机制仅适用于 cookie。由于 Spring 安全性是通过将令牌设置为 HTTP 参数来实现的,因此 AngularJS 提供的开箱即用解决方案将不起作用。

spring-security-csrf-token-interceptor 项目文档中所述 - "An AngularJS interceptor that sets the Spring Security CSRF token information in all HTTP requests" - 它通过调用 head 来接收 X-CSRF-TOKEN,然后存储此令牌并随每个 http 请求发送出去。

总结:在您的项目中添加上述项目中提到的 angular 拦截器以解决您的问题。检查该 github 项目中提到的示例。