2

это моя весна-security.xml:Весна Безопасность для отдыха. POST всегда возвращает 403 код

<security:http pattern="/eklienci/**" 
     authentication-manager-ref="authenticationManager" entry-point-ref="restAuthenticationEntryPoint" 
     create-session="stateless"> 
     <security:intercept-url pattern="/eklienci/**" 
      access="hasAnyAuthority('ADMIN','USER','VIEWER')" /> 
     <form-login 
      authentication-success-handler-ref="mySuccessHandler" 
      authentication-failure-handler-ref="myFailureHandler" 
     /> 
     <security:custom-filter ref="restServicesFilter" 
      before="PRE_AUTH_FILTER" /> 
    </security:http> 
    <!-- other stuff --!> 
    <beans:bean id="restAuthenticationEntryPoint" 
     class="pl.aemon.smom.config.RestAuthenticationEntryPoint" /> 
    <!-- Filter for REST services. --> 
    <beans:bean id="restServicesFilter" 
    class="pl.aemon.smom.config.RestUsernamePasswordAuthenticationFilter"> 
    <beans:property name="postOnly" value="true" /> 
    <beans:property name="authenticationManager" ref="authenticationManager" /> 
    <beans:property name="authenticationSuccessHandler" ref="mySuccessHandler" /> 
</beans:bean> 

Это мой RestUsernamePasswordAuthenticationFilter:

public class RestUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter 
{ 

    @Autowired 
    private CustomAuthenticationProvider authenticationProvider; 


    @Override 
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { 

     Enumeration<String> names = request.getHeaderNames(); 
     while(names.hasMoreElements()) 
     { 
      System.out.println(names.nextElement()); 
     } 
     String username = obtainUsername(request); 
     String password = obtainPassword(request); 
     System.out.println("Username " + username + " password: " + password); 
     if(username!=null) 
     { 
      username = username.trim(); 
     } 

     UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); 

     // Allow subclasses to set the "details" property 
     setDetails(request, authRequest); 
     return authenticationProvider.authenticateRest(authRequest); 

//  System.out.println(auth.toString()); 
//  return auth; 
    } 



    @Override 
    protected String obtainPassword(HttpServletRequest request) { 
     return request.getHeader("password"); 
    } 

    @Override 
    protected String obtainUsername(HttpServletRequest request) { 
     return request.getHeader("username"); 
    } 

    @Override 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, 
      ServletException { 

     HttpServletRequest httpRequest = (HttpServletRequest) request; 
     HttpServletResponse httpResponse = (HttpServletResponse) response; 

     Authentication auth = attemptAuthentication(httpRequest, httpResponse); 
     SecurityContextHolder.getContext().setAuthentication(auth); 

     chain.doFilter(request, response); 

    } 
} 

И это мои методы RestController

@RestController 
@RequestMapping("/eklienci") 
public class EklientRestController 
{ 
    @RequestMapping(value="/get/{eklientid}") 
    public Eklient get(@PathVariable String eklientid) 
    { 
     return userService.findById(eklientid); 
    } 

    @RequestMapping(value = "/add", method = RequestMethod.POST, produces="application/json", consumes="application/json") 
    @ResponseBody 
    public String add(@RequestBody String json) 
    { 
     System.out.println(json); 
     Eklient pj = new Eklient(); 
     ObjectMapper mapper = new ObjectMapper(); 
     try 
     { 
      pj = mapper.readValue(json, Eklient.class); 
      return mapper.writeValueAsString(pj); 
     } catch (JsonParseException e) 
     { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (JsonMappingException e) 
     { 
     // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (IOException e) 
     { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     return "Error"; 
    } 
} 

Когда я попробуйте позвонить/получить/{eklientid}, он всегда работает нормально. Все вызовы GET всегда возвращают, по крайней мере, информацию о UNARTHORIZED access (401), и я вижу журналы из RestUsernamePasswordAuthenticationFilter.

Но когда я попробовать любой POST вызов (например,/eklienci/оных} моего приложение всегда возвращает 403 код и не producde любого журнала. В чем причина? Как это исправить?

+0

Вы упомянули, что запросы GET работают нормально, когда код статуса возврата 401, что это значит? Этот вызов происходит до или после проверки подлинности? – Igor

ответ

3

CSRF активируется по умолчанию для общих не-GET-методов, таких как POST, PUT, DELETE, вызывая 403s, если вы не размещали заголовки CSRF в своих REST-вызовах. Вы можете (временно!) отключить CSRF в вашем security.xml, чтобы убедиться, что это проблема В основном вы должны добавить CSRF headers в свои REST-вызовы и теги JSPs <sec:csrfInput/> для любых клиент-серверных вызовов. FYI, дополнительные классы, которые мне необходимо реализовать в моем проекте с открытым исходным кодом, возможно, вам полезны:

  1. CsrfSecurityRequestMatcher отключить CSRF для определенных POST/PUT и т. Д., Для которых не требуется авторизация. Как настроено here в моем security.xml.
  2. CustomAccessDeniedHandlerImpl для маршрутизации CSRF 403 в результате тайм-аутов сеанса на страницу входа.
-1

Отключить защиту CSRF. Он не нужен, если у вас есть create-session="stateless".

<security:http ...> 
    <security:csrf disabled="true"/> 
    <!-- the rest same as before --> 
</security:http> 
+0

Нет, не верно: http://docs.spring.io/spring-security/site/docs/current/reference/html/csrf.html#csrf-and-stateless-browser-applications –

+0

@GlenMazza Небезопасно в некоторых специальных случаев, но OP, похоже, не использует ни cookie проверки подлинности, ни базовый auth. – holmis83