预检的响应具有无效的HTTP状态代码403

时间:2016-01-09 14:40:26

标签: angularjs http spring-boot ionic-framework

我用作服务器端Spring-boot并为测试提供虚拟服务

我的 ServiceCaller.java =

package com.user.server.mfw;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.handler.MappedInterceptor;


@RestController
public class ServiceCaller {
    @CrossOrigin(allowedHeaders="*",allowCredentials="true")
    @RequestMapping(value="/serviceCaller",method=RequestMethod.POST, headers="content-type=text/*")
    @ResponseBody
    String serviceListener(@RequestParam("serviceName") String serviceName,HttpSession session,HttpServletRequest theHttpServletReq ) throws IOException 
    {


        if(!serviceName.isEmpty())
        {
           byte[] encoded = Files.readAllBytes(Paths.get("C://Users//something//Desktop//asd.json"));
           return new String(encoded, "UTF-8");
        }
        return "gelemedi";
    }


    private void checkActiveSessionControl(HttpSession session)
    {   
        System.out.println("Session Id:" +  session.getId() +" // " + session.getCreationTime());
        if(session == null)
            System.out.println("Null");
        else if(session.isNew())
            System.out.println("New");
        else
            System.out.println("Old");
    }



}

我的客户端是离子框架,基于angular.js ......

Controller.js

   $scope.getInfo = function() {
    $http({
        url: SERVER_ENDPOINT.url + '/serviceCaller',
        method: 'POST',
        params: {serviceName: 'deneme'},
        withCredentials: true
    }).then(function(result) {
      var alertPopup = $ionicPopup.alert({
        title: 'ALOHA!',
        template: 'dksjd ' + result
      });
      $scope.memberInfo = result.data.accountNumber;
    }, function() {
        var alertPopup = $ionicPopup.alert({
          title: ' failed!',
          template: 'da'
        });
      }

    );
  };

基本上,当我使用POST方法而不是GET时,我得到“无效的HTTP状态代码403”。但是,我想使用 POST 来代替 GET 进行调用。 但是我无法弄清楚我在哪里弄错了......

任何解决方案将不胜感激!

4 个答案:

答案 0 :(得分:7)

如果您的浏览器正在发送飞行前OPTIONS请求,您只需通过允许http OPTIONS在WebSecurity配置中允许该操作。

.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()

答案 1 :(得分:1)

我认为您没有使用此anotation传递任何参数:

@CrossOrigin(allowedHeaders="*",allowCredentials="true")
@RequestMapping(value="/serviceCaller",method=RequestMethod.POST, headers="content-type=text/*")
@ResponseBody
String serviceListener(@RequestParam("serviceName") String serviceName,HttpSession session,HttpServletRequest theHttpServletReq ) throws IOException 
{

您应该value="/serviceCaller"替换value="/{serviceCaller}"

编辑

请将此课程添加到您的项目中以解决CORS问题

@Component
public class SimpleCORSFilter implements Filter {

@Override
public void init(FilterConfig fc) throws ServletException {}

@Override
public void doFilter(ServletRequest req, ServletResponse resp,
        FilterChain chain) throws IOException, ServletException {
    // TODO Auto-generated method stub
    HttpServletResponse response = (HttpServletResponse) resp;

    response.setHeader("Access-Control-Allow-Origin", "*");
    response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
    response.setHeader("Access-Control-Max-Age", "3600");
    response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
    chain.doFilter(req, resp);
}

@Override
public void destroy() {}

}

答案 2 :(得分:1)

AngularJS docs

所示
  

XSRF是一种未经授权的网站可以获取用户私人数据的技术。 Angular提供了一种对抗XSRF的机制。执行XHR请求时,$ http服务从cookie(默认情况下为XSRF-TOKEN)读取令牌并将其设置为HTTP头(X-XSRF-TOKEN)。由于只有在您的域上运行的JavaScript才能读取Cookie,因此您的服务器可以确保XHR来自您域上运行的JavaScript。不会为跨域请求设置标头。

所以默认标头是x-xsrf-token。

在CsrfFilter

之后的websecurity配置中添加此过滤器
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);
  }
}

添加过滤器,如下所示:

protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .httpBasic()...
      .and()
      .addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class);
  }
}

答案 3 :(得分:0)

我在回答问题Angularjs Post not sending headers to Spring JWT时非常清楚地发现了预检请求的解释。

由于您使用的是Spring Security,因此必须在Spring Security级别启用CORS,以允许它利用Spring MVC级别定义的配置:

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and()...
    }
}

Here是非常优秀的教程,解释了Spring MVC框架中的CORS支持。

这使HttpMethod.Options请求能够在预检请求中包含标题。