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


    使用CL_HTTP_CLIENT测试消费OData会出现:CSRF token validation failed

    解决办法如下:

    1.需要两个创建两个cl_http_client

    2.第一个cl_http_client用get获取token和cookies

    3.第二个cl_http_client用前面获取的token和cookies来执行post操作

    直接上代码:

    DATA: lo_http_client   TYPE REF TO if_http_client,  "第一个cl_http_client
          lo_http_client1   TYPE REF TO if_http_client, "第二个cl_http_client
          lv_service       TYPE string,
          lv_result        TYPE string,
          lv_csrf          TYPE string,
          lt_cookies       TYPE tihttpcki,
          lo_ixml          TYPE REF TO if_ixml,
          lo_streamfactory TYPE REF TO if_ixml_stream_factory,
          lo_istream       TYPE REF TO if_ixml_istream,
          lo_document      TYPE REF TO if_ixml_document,
          lo_parser        TYPE REF TO if_ixml_parser.
    
    lv_service = 'http://*****.*****.com:8800/sap/opu/odata/SAP/ZODATA_TEST_SRV/ZWERKSSet'.  "URL
    
    "第一个cl_http_client使用GET获取token和cookies
    cl_http_client=>create_by_url(
      EXPORTING
        url                = lv_service
      IMPORTING
        client             = lo_http_client
      EXCEPTIONS
        argument_not_found = 1
        plugin_not_active  = 2
        internal_error     = 3
        OTHERS             = 4 ).
    
    lo_http_client->propertytype_logon_popup = lo_http_client->co_disabled.
    CALL METHOD lo_http_client->authenticate(
      EXPORTING
    *   client   = ''
    *   proxy_authentication = 'X'
        username = '*******'      "账户
        password = '*******'      "密码
    *   LANGUAGE = 'E'
                   ).
    CALL METHOD lo_http_client->request->set_header_field
      EXPORTING
        name  = 'Content-Type'
        value = 'application/JSON; charset=utf-8'.
    
    CALL METHOD lo_http_client->request->set_header_field
      EXPORTING
        name  = 'x-csrf-token'
        value = 'Fetch'.
    
    CALL METHOD lo_http_client->request->set_method( 'GET' ).
    
    lo_http_client->send(
      EXCEPTIONS
        http_communication_failure = 1
        http_invalid_state         = 2 ).
    
    lo_http_client->receive(
      EXCEPTIONS
        http_communication_failure = 1
        http_invalid_state         = 2
        http_processing_failed     = 3 ).
    
    CLEAR lv_result .
    lv_result = lo_http_client->response->get_cdata( ).
    lv_csrf  = lo_http_client->response->get_header_field( NAME = 'x-csrf-token' ).       "获取token
    lo_http_client->response->get_cookies( CHANGING cookies = lt_cookies ).               "获取cookies
    lo_ixml = cl_ixml=>create( ).
    BREAK-POINT.
    
    lo_streamfactory = lo_ixml->create_stream_factory( ).
    lo_istream = lo_streamfactory->create_istream_string(
                                     lv_result ).
    lo_document = lo_ixml->create_document( ).
    lo_parser = lo_ixml->create_parser(
                           stream_factory = lo_streamfactory
                           istream        = lo_istream
                           document       = lo_document ).
    lo_parser->parse( ).
    CALL METHOD lo_http_client->close.
    
    "第二个cl_http_client用前面获取的token和cookies来执行POST
    cl_http_client=>create_by_url(
      EXPORTING
        url                = lv_service
      IMPORTING
        client             = lo_http_client1
      EXCEPTIONS
        argument_not_found = 1
        plugin_not_active  = 2
        internal_error     = 3
        OTHERS             = 4 ).
    lo_http_client1->propertytype_logon_popup = lo_http_client->co_disabled.
    CALL METHOD lo_http_client1->authenticate(
      EXPORTING
    *   client   = ''
    *   proxy_authentication = 'X'
        username = '*******'      "账户
        password = '*******'      "密码
    *   LANGUAGE = 'E'
                   ).
    CALL METHOD lo_http_client1->request->set_header_field
      EXPORTING
        name  = 'Content-Type'
        value = 'application/JSON; charset=utf-8'.
    
    CALL METHOD lo_http_client1->request->set_header_field
      EXPORTING
        name  = 'x-csrf-token'
        value = lv_csrf.                "使用第一个cl_http_clien获取的token
    
    "设置cookies
    LOOP AT lt_cookies ASSIGNING FIELD-SYMBOL(<cookie>).
          lo_http_client1->request->set_cookie( name = <cookie>-name
                                               value = <cookie>-value ).
    ENDLOOP.
    
    CALL METHOD lo_http_client1->request->set_method( 'POST' ).
    
    DATA lv_json TYPE string.
    DATA: len TYPE i .
    lv_json =  '{"Werks": "7777", "Active": true}'.          "这边键值要注意,键第一个字母大写,其他小写
    len = strlen( lv_json ) .
    
    CALL METHOD lo_http_client1->request->set_cdata
      EXPORTING
        data   = lv_json
        offset = 0
        length = len.
    
    lo_http_client1->send(
      EXCEPTIONS
        http_communication_failure = 1
        http_invalid_state         = 2 ).
    
    lo_http_client1->receive(
      EXCEPTIONS
        http_communication_failure = 1
        http_invalid_state         = 2
        http_processing_failed     = 3 ).
    
    CLEAR lv_result .
    lv_result = lo_http_client1->response->get_cdata( ).
    lo_ixml = cl_ixml=>create( ).
    BREAK-POINT.
    
    lo_streamfactory = lo_ixml->create_stream_factory( ).
    lo_istream = lo_streamfactory->create_istream_string(
                                     lv_result ).
    lo_document = lo_ixml->create_document( ).
    lo_parser = lo_ixml->create_parser(
                           stream_factory = lo_streamfactory
                           istream        = lo_istream
                           document       = lo_document ).
    lo_parser->parse( ).
    CALL METHOD lo_http_client1->close.

    如下是大佬直接封装的类,膜拜一下,原文地址:http://blog.itpub.net/24475491/viewspace-2717093/

    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                = ''
          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.
        "这个使用的是name = 'Content-Type' value = 'multipart/mixed; boundary=batch_1'
        "用application/JSON; charset=utf-8就不用那么麻烦了
        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                = ''
          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.

    调用:

    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 ).
  • 相关阅读:
    Android LogCat使用详解
    新时代新潮流WebOS 【20】WebKit的结构与解构
    Android调试的必杀技——反汇编
    真机缺少com.google.android.maps.jar解决方法:
    test
    VMware让ubuntu与win7共享文件方法
    android手机通过笔记本无线wifi上网
    新时代新潮流WebOS 【22】WebKit,鼠标引发的故事
    获取证书
    获取局域网内部机器的MAC地址
  • 原文地址:https://www.cnblogs.com/seven1314pp/p/15867261.html
Copyright © 2020-2023  润新知