2015-07-13 4 views
3

Я уже пробовал многие из форумов по этой теме, никто не работает для меня.Весна CSRF + AngularJs

У меня есть базовый CRUD с Spring MVC 4.1.7, Spring Security 3.2.3, работающий на MySQL + Tomcat7.

Проблема в том, что когда я пытаюсь получить форму POST с помощью AngularJS, я заблокирован по ошибке 403 (доступ запрещен).

Я понял, что мне нужно отправить CSRF_TOKEN с запросом POST, но я не могу понять, КАК!

Я пробовал так много разных способов, и никто не работает.

Мои файлы

Controller.js

$scope.novo = function novo() { 
    if($scope.id){ 
    alert("Update - " + $scope.id); 
    } 
    else{ 
     var Obj = { 
       descricao : 'Test', 
       saldo_inicial : 0.00, 
       saldo : 33.45, 
       aberto : false, 
       usuario_id : null, 
       ativo : true 
     }; 
     $http.post(urlBase + 'caixas/adicionar', Obj).success(function(data) { 
      $scope.caixas = data;  
     }).error(function(data) {alert(data)}); 
    } 
}; 

весна-security.xml

<beans:beans xmlns="http://www.springframework.org/schema/security" 
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd 
http://www.springframework.org/schema/security 
http://www.springframework.org/schema/security/spring-security.xsd"> 

<!-- enable use-expressions --> 
<http auto-config="true" use-expressions="true"> 
    <intercept-url pattern="/seguro**" 
     access="hasAnyRole('ROLE_USER','ROLE_ADMIN')" /> 
    <intercept-url pattern="/seguro/financeiro**" 
     access="hasAnyRole('ROLE_FINANCEIRO','ROLE_ADMIN')" /> 

    <!-- access denied page --> 
    <access-denied-handler error-page="/negado" /> 
    <form-login login-page="/home/" default-target-url="/seguro/" 
     authentication-failure-url="/home?error" username-parameter="inputEmail" 
     password-parameter="inputPassword" /> 
    <logout logout-success-url="/home?logout" /> 
    <!-- enable csrf protection --> 
    <csrf /> 
</http> 

<!-- Select users and user_roles from database --> 
<authentication-manager> 
    <authentication-provider> 
     <password-encoder hash="md5" /> 
     <jdbc-user-service data-source-ref="dataSource" 
      users-by-username-query="SELECT login, senha, ativo 
       FROM usuarios 
       WHERE login = ?" 
      authorities-by-username-query="SELECT u.login, r.role 
       FROM usuarios_roles r, usuarios u 
       WHERE u.id = r.usuario_id 
       AND u.login = ?" /> 
    </authentication-provider> 
</authentication-manager> 

web.xml

<?xml version="1.0" encoding="UTF-8"?> 
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 

<display-name>Barattie ~ Soluções Integradas</display-name> 

<!-- The definition of the Root Spring Container shared by all Servlets 
    and Filters --> 
<context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value> 
     /WEB-INF/spring/spring-security.xml 
     /WEB-INF/spring/spring-database.xml 
     /WEB-INF/spring/spring-hibernate.xml 
    </param-value> 
</context-param> 
<context-param> 
    <param-name>com.sun.faces.writeStateAtFormEnd</param-name> 
    <param-value>false</param-value> 
</context-param> 

<!-- Creates the Spring Container shared by all Servlets and Filters --> 
<listener> 
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
</listener> 

<!-- Processes application requests --> 
<servlet> 
    <servlet-name>appServlet</servlet-name> 
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
    <init-param> 
     <param-name>contextConfigLocation</param-name> 
     <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value> 
    </init-param> 
    <load-on-startup>1</load-on-startup> 
</servlet> 

<servlet-mapping> 
    <servlet-name>appServlet</servlet-name> 
    <url-pattern>/home</url-pattern> 
    <url-pattern>/</url-pattern> 
</servlet-mapping> 

<!-- Spring Security --> 
<filter> 
    <filter-name>springSecurityFilterChain</filter-name> 
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 
</filter> 

<filter-mapping> 
    <filter-name>springSecurityFilterChain</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

<error-page> 
    <exception-type>java.lang.Throwable</exception-type> 
    <location>/erro</location> 
</error-page> 

UPDATE

Я пытался добавить переименовать в клиентской стороне XSRF, но я получаю доступ запрещен.

var app = angular.module('myApp', []).config(function($httpProvider) { 
$httpProvider.defaults.xsrfCookieName = '_csrf'; 
$httpProvider.defaults.xsrfHeaderName = 'X-CSRF-Token'; 
}); 

** UPDATE 2 **

Я пытался реализовать фильтр, как это.

package sys.barattie.util; 

import java.io.IOException; 

import javax.servlet.FilterChain; 
import javax.servlet.ServletException; 
import javax.servlet.http.Cookie; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

import org.springframework.security.web.csrf.CsrfToken; 
import org.springframework.web.filter.OncePerRequestFilter; 

public class CsrfFilter 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 = new Cookie("XSRF-TOKEN", csrf.getToken()); 
     cookie.setPath("/"); 
     response.addCookie(cookie); 
    } 
    filterChain.doFilter(request, response); 
} 
} 

И изменил мою весеннюю безопасность.

 <csrf token-repository-ref="csrfTokenRepository" /> 
<beans:bean id="csrfTokenRepository" class="org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository"> 
    <beans:property name="headerName" value="X-XSRF-TOKEN" /> 
</beans:bean> 

web.xml

<filter> 
    <filter-name>csrfFilter</filter-name> 
    <filter-class>sys.barattie.util.CsrfFilter</filter-class> 
</filter> 

Но это похоже, что сервер не работает фильтр, я добавил System.out.println к нему, но не может видеть сообщения в отладочном файле

ответ

3

Я сделал несколько тестов, и в конечном итоге с этим.

В моем контроллере входа в систему, если моя аутентификация пользователя прошла успешно, я создаю токен с именем токена AngularJS, точно так же.

CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName()); 
if (csrf != null) { 
    Cookie cookie = new Cookie("XSRF-TOKEN", csrf.getToken()); 
    cookie.setPath("/"); 
    response.addCookie(cookie); 
} 

После этого я могу успешно управлять своим http.post.

Я не знаю, если это лучший способ, но это способ, который сработал для меня!

Спасибо за помощь @Joao Евангелиста

0

Основная проблема - интеграция. Угловой всегда ищет имя файла cookie XSRF-TOKEN, а Spring отправляет CSRF_TOKEN, вам необходимо предоставить фильтр, чтобы изменить это.Что-то вроде этого:

private static 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) 
      } 
     } 
    } 

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

УВЕДОМЛЕНИЕ Единственный пример у меня есть это, написано в Groovy, но просто не хватает некоторых ;

Затем вам нужно добавить фильтр и хранилище для <csrf/> свойств , вы можете установить в явном классе реализации фильтра в качестве <bean>, используя @Component или объявить эти методы, как @Bean по классу конфигурации

в противном случае вы можете изменить $http конфигурации на Угловое, согласно документации, устанавливающих эти параметры в соответствии с Spring лексем имя куки и имя заголовка

xsrfHeaderName – {string} – Name of HTTP header to populate with the XSRF token. 
xsrfCookieName – {string} – Name of cookie containing the XSRF token. 

Больше информации об этом вы можете проверить документы на Usage разделе

+0

Я пытался реализовать $ http config на стороне клиента, установка 'var app = angular.module ('myApp', []). config (function ($ httpProvider) { \t $ httpProvider.defaults.xsrfCookieName = 'csrftoken'; \t $ httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken'; }); '};' Но я все время получаю доступ запрещенным ... Я попытаюсь на стороне сервера –

+0

. Имя заголовка по умолчанию - 'X-CSRF-TOKEN' –

+0

Изменено, но пока не работает. –

0

я столкнулся с этой проблемой также, и это решение, которое работает для меня (из документации Spring), обратите внимание, что им не с помощью $ HTTP. Вместо этого я использую $ resource. ' Вы можете попросить Spring сохранить печенье с дефолтов ANGULAR по:

<csrf token-repository-ref="tokenRepository"/> 

... </http>

<b:bean id="tokenRepository" 
    class="org.springframework.security.web.csrf.CookieCsrfTokenRepository" 
    p:cookieHttpOnly="false"/> 

Пожалуйста, обратите внимание, что если вы используете $ HTTP, есть поле в конфигурации объект называется xsrfCookieName, где вы можете явно указать имя файла cookie. Но этот вариант я havent пробовал, поэтому я не знаю, насколько он полезен.

С наилучшими пожеланиями.

0

Это должно работать:

класс, который расширяет WebSecurityConfigurerAdapter:

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

    http 
      .csrf() 
      .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) 
.. 

И тогда в ваших AngularJS вы можете использовать любой модуль для CSRF, и т.д .: spring-security-csrf-token-interceptor

Смежные вопросы