【问题标题】:Web service on Play framework not accepting POST messagePlay 框架上的 Web 服务不接受 POST 消息
【发布时间】:2018-07-31 23:29:20
【问题描述】:

我正在将以下消息从 Angular 服务发送到播放应用程序

  public createUser(user:User):any{
    console.log('contacting server at '+this.API_URL +this.ADD_USER_URL +" with user data ",user);
    /*http.post returns an observable. The caller's code should subscribe to this observable */
    return this.http.post(this.API_URL +this.ADD_USER_URL,user)
      .map(response => { //handler if post's Observable is successful. map creates new User and returns Observable<User>.
        console.log('response from backend service',response);
        //return new User(response); //the constructor of User allows passing an object.
        /*when the observable of http.post returns (produces) data (the response), the map function prints a message and returns that response*/
        return response;
      })
      .catch(this.handleError); //error handler if Observable fails
  }

我在 Play 的控制台上收到以下警告并禁止响应。 [warn] p.filters.CSRF - [CSRF] Check failed because application/json for request /ws/users/add

WebToBackendInterfaceService::handleError 
Object { headers: {…}, status: 403, statusText: "Forbidden", url: "http://localhost:9000/ws/users/add", ok: false, name: "HttpErrorResponse", message: "Http failure response for http://localhost:9000/ws/users/add: 403 Forbidden", error: "<!DOCTYPE html>\n<html lang=\"en\">\n    <head>\n        <title>Unauthorized</title>\n        <link rel=\"shortcut icon\" href=\"data:image/png;base64,...">\n        <style>\n            html, body, pre {\n                margin: 0;\n                padding: 0;\n                font-family: Monaco, 'Lucida Console', monospace;\n                background: #ECECEC;\n            }\n            h1 {\n                margin: 0;\n                background: #333;\n                padding: 20px 45px;\n                color: #fff;\n                text-shadow: 1px 1px 1px rgba(0,0,0,.3);\n                border-bottom: 1px solid #111;\n                font-size: 28px;\n            }\n            p#detail {\n                margin: 0;\n                padding: 15px 45px;\n                background: #888;\n                border-top: 4px solid #666;\n                color: #111;\n                text-shadow: 1px 1px 1px rgba(255,255,255,.3);\n                font-size: 14px;\n                border-bottom: 1px solid #333;\n            }\n        </style>\n    </head>\n    <body>\n        <h1>Unauthorized</h1>\n\n        <p id=\"detail\">\n            You must be authenticated to access this page.\n        </p>\n\n    </body>\n</html>\n" }

Play 的 CSRF 似乎不喜欢这条消息。我该如何解决这个问题?我在 Play 中读到,错误发生在

  1. 请求不是 GET、HEAD 或 Option - 在我的情况下是真的,我正在发送 POST 消息
  2. 请求具有 cookie 或授权标头。我没有明确地发送它们。 Angular 会默认发送吗?
  3. CORS 过滤器未配置为信任请求的来源。 - 我正在向 localhost:9000 发送请求。 Play 不应该信任本地主机吗?

如何让 Play 接受我的消息?

【问题讨论】:

    标签: playframework-2.6


    【解决方案1】:

    这是一种解决方法。正确的解释在Angular not sending CSRF token in header。基本上,我的客户应该发送一个带有最初由 play 框架创建的令牌的 CSRF Header

    我不知道这是否正确,但我不得不在 Play 中禁用 CSRF。可以通过以下两种方式完成

    routes文件中,在规则上方添加nocsrf

    +nocsrf
    POST /ws/users/add                  controllers.UserController.addUser
    

    或者在application.conf中完全禁用csrf

    play.filters {
    
    
      # Disabled filters remove elements from the enabled list.
      disabled += play.filters.csrf.CSRFFilter
    }
    

    我完全禁用了csrf

    【讨论】:

    • 禁用 CSRF 对安全来说是个坏主意。您应该按照下面的答案并将正确的令牌添加到请求的标头中。
    【解决方案2】:

    确保使用标头和 cookie 名称 "Csrf-Token" 设置前端 HTTP 客户端。我的 Angular+Play 种子也有同样的问题,原来 Angular 的 CSRF 的 defaults cookie and header names 是 XSRF-TOKEN 和 X-XSRF-TOKEN。所以在我的情况下,我必须导入另一个 Angular 模块来覆盖这些值:

      imports: [
        BrowserModule,
        ReactiveFormsModule,
        HttpClientModule,
        HttpClientXsrfModule.withOptions({
          cookieName: 'Csrf-Token',
          headerName: 'Csrf-Token',
        }),
        routing
      ]
    

    虽然禁用 Play 的 CSRF 保护(基于 Manu Chadha 的回答)可能是一种解决方法,但强烈建议不要这样做。

    【讨论】:

    • 这确实应该被列为正确答案。禁用 CSRF 很容易,但不是长期解决方案。我会注意到“Csrf-Token”这个名字是必不可少的。如果你在网上搜索 CSRF,你会找到各种名称。该字符串是 Play 所期望的,而其他字符串将不起作用。我目前正在客户端使用 React(通过 Slinky)编写代码,并使用 fetch 进行 Ajax 调用。在我的主要视图中,我有@import views.html.helper.CSRF 并将data-token='@CSRF.getToken.value' 添加到正文中。然后在 fetch 标头中,我获取数据令牌并将其添加到键“Csrf-Token”下。
    猜你喜欢
    • 2012-02-28
    • 1970-01-01
    • 1970-01-01
    • 2015-10-19
    • 1970-01-01
    • 2012-03-29
    • 1970-01-01
    • 1970-01-01
    • 2017-07-14
    相关资源
    最近更新 更多