【问题标题】:Using JSON RPC in Struts2 along with Spring Security causes the request to be forbidden(403)在 Struts2 中使用 JSON RPC 和 Spring Security 会导致请求被禁止 (403)
【发布时间】:2014-02-20 12:05:27
【问题描述】:

我使用以下 JavaScript/jQuery 函数通过 JSON 进行远程过程调用。

<s:url var="testJsonUrl" action="testJsonAction"/>
<script src="../js/jquery-1.8.0.min.js" type="text/javascript"></script>

var timeout;
var request;

$(document).ready(function(){
    $("#countryComboBox").change(function(){
        if(!request)
        {
            request = $.ajax({
                datatype:"json",
                type: "POST",
                data: JSON.stringify({jsonrpc:'2.0', method:'getStateTables', id:'jsonrpc', params:[$("#countryComboBox").val()]}),
                contentType: "application/json-rpc; charset=utf-8",
                url: "<s:property value='#testJsonUrl'/>",
                success: function(response)
                {
                    alert(JSON.stringify(response.result));
                },
                complete: function()
                {
                    timeout = request = null;
                },
                error: function(request, status, error)
                {
                    if(status!=="timeout"&&status!=="abort")
                    {
                        alert(status+" : "+error);
                    }
                }
            });
            timeout = setTimeout(function() {
                if(request)
                {
                    request.abort();
                    alert("The request has been timed out.");
                }
            }, 30000);
        }
    });
});

此函数调用动作类中的方法getStateTables(),如下所示。

@Namespace("/admin_side")
@ResultPath("/WEB-INF/content")
@ParentPackage(value = "json-default")
public final class TestAction extends ActionSupport
{
    @Autowired
    private final transient SharableService sharableService = null;
    private static final long serialVersionUID = 1L;
    List<StateTable> stateTables;

    public TestAction() {}

    @SMDMethod
    public List<StateTable> getStateTables(@SMDMethodParameter(name="countryId")Long countryId) {
        stateTables = sharableService.findStatesByCountryId(countryId);
        return stateTables;
    }

    @Action(value = "testJsonAction",
    results = {
        @Result(name = ActionSupport.SUCCESS, type = "json", params = {"enableSMD", "true"})},
    interceptorRefs = {
        @InterceptorRef(value = "json", params = {"enableSMD", "true", "includeProperties", "result\\[\\d+\\]\\.stateId, result\\[\\d+\\]\\.stateName", "excludeNullProperties", "true"})})
    public String executeAction() throws Exception {
        return SUCCESS;
    }

    @Action(value = "Test",
    results = {
        @Result(name = ActionSupport.SUCCESS, location = "Test.jsp"),
        @Result(name = ActionSupport.INPUT, location = "Test.jsp")},
    interceptorRefs = {
        @InterceptorRef(value = "defaultStack", params = {"params.acceptParamNames", "", "params.excludeMethods", "load", "validation.validateAnnotatedMethodOnly", "true"})})
    public String load() throws Exception {
        //This method is just used to return an initial view on page load.
        return ActionSupport.SUCCESS;
    }
}

此方法会导致返回与 jQuery 函数作为参数提供给此方法的 countryId 对应的状态列表,该列表作为 JSON 响应委托给 jQuery 函数。

这很好用,除非 Spring Security 出现。使用 Spring Security 时,请求被禁止。

头信息可以查看如下。

Request URL:http://localhost:8080/TestStruts/admin_side/testJsonAction.action
Request Method:POST
Status Code:403 Forbidden
Request Headers
    Accept:*/*
    Accept-Encoding:gzip,deflate,sdch
    Accept-Language:en-US,en;q=0.8
    Cache-Control:max-age=0
    Connection:keep-alive
    Content-Length:73
    Content-Type:application/json-rpc; charset=UTF-8
    Cookie:JSESSIONID=0C4D7DFD269F1D5F7315A39971A75961; sbOverlayID=42887237
    Host:localhost:8080
    Origin:http://localhost:8080
    Referer:http://localhost:8080/TestStruts/admin_side/Test.action
    User-Agent:Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.76 Safari/537.36
    X-Requested-With:XMLHttpRequest
Request Payload
    {jsonrpc:2.0, method:getStateTables, id:jsonrpc, params:[2]}
    id: "jsonrpc"
    jsonrpc: "2.0"
    method: "getStateTables"
    params: [2]
Response Headers
    Content-Length:1149
    Content-Type:text/html;charset=utf-8
    Date:Tue, 28 Jan 2014 22:12:55 GMT
    Server:Apache-Coyote/1.1
    X-Content-Type-Options:nosniff
    X-Frame-Options:DENY
    X-XSS-Protection:1; mode=block

我的 Spring Security 配置与this 问题中提到的完全相同。

在哪里查看 Spring Security?

【问题讨论】:

    标签: json spring struts2 spring-security json-rpc


    【解决方案1】:

    发现了一些东西。这是因为我使用了一个 CSRF 令牌(在 spring-security.xml 文件中配置为 &lt;csrf/&gt;),它需要与 AJAX 请求一起发送。当我使用jQuery函数和&lt;meta&gt;标签时,它起作用了,正如here所提到的。

    如果您使用 JSON,则无法提交 CSRF 令牌 在 HTTP 参数中。相反,您可以在 HTTP 标头。一个典型的模式是包含 CSRF 令牌 在您的元标记中。一个带有 JSP 的示例如下所示:

    <html>
      <head>
        <meta name="_csrf" content="${_csrf.token}"/>
        <!-- default header name is X-CSRF-TOKEN -->
        <meta name="_csrf_header" content="${_csrf.headerName}"/>
        <!-- ... -->
      </head>
      <!-- ... -->
    

    然后,您可以在所有 Ajax 请求中包含该令牌。如果你 正在使用 jQuery,这可以通过以下方式完成:

    $(function () {
      var token = $("meta[name='_csrf']").attr("content");
      var header = $("meta[name='_csrf_header']").attr("content");
      $(document).ajaxSend(function(e, xhr, options) {
        xhr.setRequestHeader(header, token);
      });
    });
    

    【讨论】:

      猜你喜欢
      • 2020-04-20
      • 2020-12-18
      • 2023-02-08
      • 2018-12-24
      • 2017-11-28
      • 2015-08-16
      • 2015-04-15
      • 2012-12-24
      • 2021-06-17
      相关资源
      最近更新 更多