2

这是我的弹簧security.xml文件:Spring Security for rest application。 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"; 
    } 
} 

当我尝试调用/ get/{eklientid},它总是可以正常工作。所有GET调用总是返回至少关于UNARTHORIZED访问的信息(401),并且我从RestUsernamePasswordAuthenticationFilter中看到日志。

但是当我尝试任何POST调用(例如/ eklienci /加}我的应用总是返回403码,并且不producde任何日志,这是什么原因?如何解决?

+0

你提到的GET请求在返回状态码401时工作正常,这是什么意思?此通话是在身份验证之前还是之后发生的 – Igor

回答

3

CSRF被激活默认情况下,如果你没有在你的REST调用中放置CSRF头文件,你可以(临时!)在你的security.xml中关闭CSRF,以确认这是问题主要需要将CSRF headers添加到您的REST调用中,并将<sec:csrfInput/> JSPs标记添加到任何客户端服务器调用中。FYI,我需要在我的开源项目中实现的其他类,可能对您有用:

  1. CsrfSecurityRequestMatcher关闭某些POST/PUT等的CSRF,不需要授权。在我的security.xml中配置为here
  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或基本认证。 – holmis83