2015-08-13 3 views
5

Мне нужно отправить HTTP.Post (приложение для Android) в мою службу, чтобы зарегистрировать нового пользователя!Статус HTTP 403 - Недействительный токен CSRF «null» был найден по параметру запроса

Проблема заключается в том, что когда я пытаюсь отправить запрос в конечную точку реестра (без безопасности), Spring блокирует меня!

Мой проект Зависимости

<properties> 
    <java-version>1.6</java-version> 
    <org.springframework-version>4.1.7.RELEASE</org.springframework-version> 
    <org.aspectj-version>1.6.10</org.aspectj-version> 
    <org.slf4j-version>1.6.6</org.slf4j-version> 
    <jackson.version>1.9.10</jackson.version> 
    <spring.security.version>4.0.2.RELEASE</spring.security.version> 
    <hibernate.version>4.2.11.Final</hibernate.version> 
    <jstl.version>1.2</jstl.version> 
    <mysql.connector.version>5.1.30</mysql.connector.version> 
</properties> 

Spring Security

<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"> 

<!--this is the register endpoint--> 
<http security="none" pattern="/webapi/cadastro**"/> 


    <http auto-config="true" use-expressions="true"> 
       <intercept-url pattern="/webapi/dados**" 
      access="hasAnyRole('ROLE_USER','ROLE_SYS')" /> 
     <intercept-url pattern="/webapi/system**" 
      access="hasRole('ROLE_SYS')" /> 

<!--  <access-denied-handler error-page="/negado" /> --> 
     <form-login login-page="/home/" default-target-url="/webapi/" 
      authentication-failure-url="/home?error" username-parameter="username" 
      password-parameter="password" /> 
     <logout logout-success-url="/home?logout" />   
     <csrf token-repository-ref="csrfTokenRepository" /> 
    </http> 

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

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

</beans:beans> 

Контроллер

@RestController 
@RequestMapping(value="/webapi/cadastro", produces="application/json") 
public class CadastroController { 
    @Autowired 
    UsuarioService usuarioService; 

    Usuario u = new Usuario(); 

    @RequestMapping(value="/novo",method=RequestMethod.POST) 
    public String register() { 
     // this.usuarioService.insert(usuario); 
     // usuario.setPassword(HashMD5.criptar(usuario.getPassword())); 
     return "teste"; 
    } 
} 

JS Post (Угловое)

$http.post('/webapi/cadastro/novo').success(function(data) { 
      alert('ok'); 
     }).error(function(data) { 
      alert(data); 
     }); 

И ошибка

HTTP Status 403 - Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-XSRF-TOKEN'.</h1><HR size="1" noshade="noshade"><p><b>type</b> Status report</p><p><b>message</b> <u>Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-XSRF-TOKEN' 

--- Решение ---

Реализован фильтр, чтобы присоединить мой X-XSRF-токен к каждому запросу заголовка

public class CsrfHeaderFilter 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); 
    } 
} 

Добавлено отображение к этому фильтру к web.xml и сделать!

ответ

11

В вашем коде выше я не вижу ничего, что передало бы токен CSRF клиенту (который является автоматическим, если вы используете JSP и т. Д.).

Общепринятой практикой является кодирование фильтра для присоединения маркера CSRF в качестве файла cookie. Затем ваш клиент отправляет запрос GET для получения этого файла cookie. Для последующих запросов этот файл cookie затем отправляется обратно в виде заголовка.

Принимая во внимание, что официальный Spring Angular guide подробно объясняет это, вы можете обратиться к Spring Lemon за полным рабочим примером.

Для отправки файла cookie в виде заголовка вам может потребоваться написать код. AngularJS по умолчанию делает это (если вы не отправляете междоменные запросы), но вот пример, если это поможет, если ваш клиент не делает:

angular.module('appBoot') 
    .factory('XSRFInterceptor', function ($cookies, $log) { 

    var XSRFInterceptor = { 

     request: function(config) { 

     var token = $cookies.get('XSRF-TOKEN'); 

     if (token) { 
      config.headers['X-XSRF-TOKEN'] = token; 
      $log.info("X-XSRF-TOKEN: " + token); 
     } 

     return config; 
     } 
    }; 
    return XSRFInterceptor; 
    }); 

angular.module('appBoot', ['ngCookies', 'ngMessages', 'ui.bootstrap', 'vcRecaptcha']) 
    .config(['$httpProvider', function ($httpProvider) { 

     $httpProvider.defaults.withCredentials = true; 
     $httpProvider.interceptors.push('XSRFInterceptor'); 

    }]); 
Смежные вопросы