打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
使用ABAP CL_HTTP_CLIENT类消费OData服务时,如何避免CSRF令牌验证失败错误

Recently I meet with this cookie issue so I document it as a blog in case any other guys might meet with the same problem.

I am trying to create some Opportunity transaction data by consuming OData service via CL_HTTP_CLIENT. Since this is a update operation which needs to be finished by HTTP POST, so a CSRF token is needed in this HTTP post. Let’s first have a look what is a typical scenario running in Chrome extension postman:

(1) Perform a HTTP get operation with header field x-csrf-token = fetch to get a valid CSRF token from http response header field.

(2) launch a HTTP post request using the CSRF token got from previous step,

And a new opportunity could successfully be created in postman:

However, when I implement the above mentioned scenario in ABAP, I meet with trouble. Instead of the expected successful creation message, I always get the error message “CSRF token validation failed”.

Issue trouble shooting

Let’s go back to postman scenario. Although it seems only the header field x-csrf-token is specified in http request, however there is another field cookie which is added to http request under the hood.

We could get this cookie field from previous HTTP get request which is responsible for CSRF token retrieve:

It means in ABAP implementation, we need to first retrieve BOTH CSRF token and cookie field from the first HTTP GET request, and then added these two fields to the request of second HTTP POST request which actually performs the opportunity creation.

This solution is also explained in this thread usage of CSRF token in ABAP report for POST request.

I just added the complete source code of my implementation here and feel free to reuse it. The ABAP report to create Opportunity by consuming OData service:

zcl_odata_tool=>get_csrf_token_and_cookie( IMPORTING et_cookies = DATA(lt_cookie)                                                     ev_token = DATA(lv_token)  ).zcl_odata_tool=>create_opp( iv_token = lv_token it_cookies = lt_cookie ).

Source code for ZCL_ODATA_TOOL:

CLASS zcl_odata_tool DEFINITION  PUBLIC  FINAL  CREATE PUBLIC .  PUBLIC SECTION.    CLASS-METHODS get_csrf_token_and_cookie      EXPORTING        !et_cookies TYPE tihttpcki        !ev_token TYPE string .    CLASS-METHODS create_opp      IMPORTING        !iv_token TYPE string        !it_cookies TYPE tihttpcki .  PROTECTED SECTION.  PRIVATE SECTION.ENDCLASS.CLASS ZCL_ODATA_TOOL IMPLEMENTATION.  METHOD create_opp.    DEFINE insert_line.      lv_body = lv_body && &1.      lv_body = lv_body && cl_abap_char_utilities=>newline.    END-OF-DEFINITION.    DATA:lo_http_client TYPE REF TO if_http_client,             lv_status      TYPE i,             lt_fields      TYPE tihttpnvp,             lv_sysubrc     TYPE sysubrc.    CALL METHOD cl_http_client=>create_by_url      EXPORTING        url                = 'https://<your C4C host>/sap/c4c/odata/v1/c4codata/$batch'      IMPORTING        client             = lo_http_client      EXCEPTIONS        argument_not_found = 1        plugin_not_active  = 2        internal_error     = 3        OTHERS             = 4.    ASSERT sy-subrc = 0.    lo_http_client->propertytype_accept_cookie = if_http_client=>co_enabled.    CALL METHOD lo_http_client->request->set_method( if_http_request=>co_request_method_post ).    lo_http_client->request->set_header_field( name = 'Content-Type' value = 'multipart/mixed; boundary=batch_1' ).    lo_http_client->request->set_header_field( name = 'x-csrf-token' value = iv_token ).    lo_http_client->request->set_header_field( name = 'Authorization' value = 'your basic authentication code' ).    LOOP AT it_cookies ASSIGNING FIELD-SYMBOL(<cookie>).      lo_http_client->request->set_cookie( name = <cookie>-name                                           value = <cookie>-value ).    ENDLOOP.    DATA: lv_body TYPE string.    insert_line '--batch_1'.    insert_line 'Content-Type: multipart/mixed; boundary=changeset_1'.    lv_body = lv_body && cl_abap_char_utilities=>cr_lf.*    insert_line '--changeset_1'.    insert_line 'Content-Type: application/http'.    insert_line 'Content-Transfer-Encoding: binary'.    lv_body = lv_body && cl_abap_char_utilities=>cr_lf.    insert_line 'POST OpportunityCollection HTTP/1.1'.    insert_line 'Content-Length: 5000'.    insert_line 'Accept: application/json'.    insert_line 'Content-Type: application/json'.    lv_body = lv_body && cl_abap_char_utilities=>cr_lf.    insert_line '{'.    insert_line '"AccountID": "8000018122",'.    insert_line '"OwnerID": "8000018122",'.    insert_line `"Name": {"content": "Testing ticket creation via OData Jerry1"}`.    insert_line '}'.    insert_line '--changeset_1--'.    lv_body = lv_body && cl_abap_char_utilities=>cr_lf.    insert_line '--batch_1--'.    lo_http_client->request->set_cdata( data = lv_body ).    CALL METHOD lo_http_client->send      EXCEPTIONS        http_communication_failure = 1        http_invalid_state         = 2        http_processing_failed     = 3.    ASSERT sy-subrc = 0.    CALL METHOD lo_http_client->receive      EXCEPTIONS        http_communication_failure = 1        http_invalid_state         = 2        http_processing_failed     = 3.    IF sy-subrc <> 0.      CALL METHOD lo_http_client->get_last_error        IMPORTING          code    = lv_sysubrc          message = DATA(ev_message).      WRITE: / 'error occurred during receive data' COLOR COL_NEGATIVE.      RETURN.    ENDIF.    DATA(lv_json) = lo_http_client->response->get_cdata( ).    WRITE:/ lv_json.  ENDMETHOD.  METHOD get_csrf_token_and_cookie.    DATA:  lo_http_client TYPE REF TO if_http_client,           lv_status      TYPE i,           lt_fields      TYPE tihttpnvp,           lv_sysubrc     TYPE sysubrc.    CALL METHOD cl_http_client=>create_by_url      EXPORTING        url                = 'https://<your C4C host>/sap/c4c/odata/v1/c4codata/'      IMPORTING        client             = lo_http_client      EXCEPTIONS        argument_not_found = 1        plugin_not_active  = 2        internal_error     = 3        OTHERS             = 4.    ASSERT sy-subrc = 0.    lo_http_client->propertytype_accept_cookie = if_http_client=>co_enabled.    CALL METHOD lo_http_client->request->set_method( if_http_request=>co_request_method_get ).    lo_http_client->request->set_header_field( name = 'x-csrf-token' value = 'Fetch' ).    lo_http_client->request->set_header_field( name = 'Accept' value = 'application/json' ).    lo_http_client->request->set_header_field( name = 'Content-Type' value = 'application/json' ).    lo_http_client->request->set_header_field( name = 'Authorization' value = 'Your basic authentication' ).    CALL METHOD lo_http_client->send      EXCEPTIONS        http_communication_failure = 1        http_invalid_state         = 2        http_processing_failed     = 3.    ASSERT sy-subrc = 0.    CALL METHOD lo_http_client->receive      EXCEPTIONS        http_communication_failure = 1        http_invalid_state         = 2        http_processing_failed     = 3.    IF sy-subrc <> 0.      CALL METHOD lo_http_client->get_last_error        IMPORTING          code    = lv_sysubrc          message = DATA(ev_message).      WRITE: / 'Error when getting token:', ev_message.      RETURN.    ENDIF.    lo_http_client->response->get_header_fields( CHANGING fields = lt_fields ).    READ TABLE lt_fields ASSIGNING FIELD-SYMBOL(<field>) WITH KEY name = 'x-csrf-token'.    ev_token = <field>-value.    lo_http_client->response->get_cookies( CHANGING cookies = et_cookies ).    lo_http_client->close( ).  ENDMETHOD.ENDCLASS.

Further reading

You can find a list of all other blogs related to OData written by Jerry.

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Spring Cloud下基于OAUTH2认证授权的实现
ABAP中实现http client
网易云音乐mp3外链手动破解方法//最新编辑新址!!
Spring MVC防御CSRF、XSS和SQL注入攻击
OAuth 2.0安全案例回顾
Pikachu漏洞靶场通关指南(全15关)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服