2017-08-14 1 views
1

Ich habe eine API-Prozedur geschrieben, um das Senden an eine HTTP-RestAPI mit JwToken-Authentifizierung zu testen. In diesem Szenario ist es für das Patientenmanagementsystem und ich erstelle einen Termin. Die API-Geschäftsregel lässt keine doppelten Buchungen für die gleiche Zeit zu.Python-Postanforderungen an HTTP-RestAPI mit JwToken-Authentifizierung generiert doppelte Posts

Ich benutze eine Python 3.5.3 Virtual Environment (schreiben in pycharm IDE) und führen meine Tests mit dem Pytest Rahmen arbeiten. Auch mit PyJWT 1.5.2. , Anfragen 2.18.3, simplejson 3.11.1 und urllib3 1.22 ist installiert (ich nehme an, Anfragen verwendet urllib3). Ich benutze simplejson.dumps anstelle der normalen json.dumps, weil die virtuelle Umgebung diese Bibliothek nicht hatte und ich Schwierigkeiten hatte, sie hinzuzufügen. Soweit ich sagen kann, hat simplejson die gleiche Funktionalität für die Dump-Prozedur.

Mit dem unten stehenden Code kann ich Requests.post Aufruf ausführen, um eine Json-Datennutzdaten erfolgreich zu liefern und einen Post zu generieren, aber dann scheint es anschließend einen zweiten Post durchzuführen, der einen 409 Konfliktfehler generiert. Ich habe Zugang zu einer Protokolldatenbank auf dem entsprechenden API-Server und kann sehen, dass es tatsächlich versucht hat, zweimal zu posten, aber ich kann nicht herausfinden, warum dies geschieht, und ich denke, dass etwas in der Anforderungsbibliothek zweimal aufgerufen wird . Möglicherweise wegen der Json, die ich poste.

Die Ausgabe sieht wie folgt aus:

https://targerserver.url.com.au/API/Core/v2.1/appointment/ 
200 
{'statusMessages': [], 'appointment': {'startDateTime': '2017-08-15T11:00:00 +10:00', 'appointmentReferenceNumber': '39960337', 'notes': '', 'clients': [{'clientId': 'abeff2be-ce6e-4324-9b57-e28ab7967b6c'}], 'status': 'Booked', 'locationId': 'd8d4fe7c-765a-46a3-a389-54ce298a27e9', 'notifyPractitioner': False, 'endDateTime': '2017-08-15T11:30:00 +10:00', 'subject': 'Jim Beam ', 'appointmentId': '08b37ce3-25e1-4e2a-9bb7-9ec2d716f83b', 'practitioner': {'practitionerId': 'a630f4ad-8b4b-4e06-8cee-7db56ba8b9bf'}}} 
collected 1 item 

test_PMSAPI_availability.py https://targerserver.url.com.au/API/Core/v2.1/appointment/ 
409 

Mein Json erfordert ein Objekt (das ein Wörterbuch ist) und auch eine Liste der Schlüssel für ein anderes Feld (das hat einen Eintrag in es) und ich frage mich, wenn die Anforderungsbibliothek dies nicht verarbeitet. Dies ist ein Beispiel, was die json sieht aus wie

payload_str = {"startDateTime":"2017-08-15T11:00+10:00","endDateTime":"2017-08-15T11:30+10:00","practitioner": {"practitionerId":"a630f4ad-8b4b-4e06-8cee-7db56ba8b9bf"}, "locationId":"d8d4fe7c-765a-46a3-a389-54ce298a27e9","clients":[{"clientId":"abeff2be-ce6e-4324-9b57-e28ab7967b6c"}]} 

ich ähnlichen Code haben, der für Get Anrufe auf dem gleichen System gearbeitet hat, aber Entsendung der Json wirklich problematisch zu sein scheint. Wir haben andere Tools, um Aufrufe an die gleichen API-Endpunkte zu senden, die diese Probleme nicht zu haben scheinen. Die Protokolle würden vorschlagen, dass die JSON-Daten, die ich liefere, mit denen eines anderen Tools mit denselben Daten identisch sind.

Was ich von der Ausgabe sehen kann, ist, dass ein erfolgreicher 200-Code auf die erste Antwort erhalten wird, aber wenn Abfrage response.status_code es 409 Antwort geworden ist. Ich habe auch versucht, nichts mit der Antwort zu tun, falls dies dazu führte, dass die Anfrage erneut angefordert und der Konflikt erzeugt wurde.

Mein Code sieht wie folgt aus:

import jwt 
import _datetime 
import requests 
import simplejson 
from requests.packages.urllib3.exceptions import InsecureRequestWarning 
from string import Template 

def app_undertest_credentials(keyname): 
    app_credentials = {'app_consumer_id': 'MyTestApp', 
         'app_consumer_secret': 'where my secret goes', 
         'app_access_token': 'where my access token goes', 
         'base_url': 'https://targerserver.url.com.au' 
         } 

    return app_credentials.get(keyname) 
def end_points_dict(keynameStr, versionStr): 
    end_points = {'location': '/API/Core/$version/location/', 
        'practitioner': '/API/Core/$version/practitioner/', 
        'availabilityslot': '/API/Core/$version/AvailabilitySlot/', 
        'client': '/API/Core/$version/client/', 
        'healthfundproviderlist': '/API/Core/$version/healthfundproviderlist/', 
        'timezone': '/API/Core/$version/timezone/', 
        'clientgroup': '/API/Core/$version/clientgroup/', 
        'appointment': '/API/Core/$version/appointment/' 
        } 
    lower_keynameStr = keynameStr.lower() 
    url_extension_no_version = Template(end_points.get(lower_keynameStr)) 
    url_extension_with_version = url_extension_no_version.safe_substitute(version=versionStr) 
    return url_extension_with_version 

def test_api_appointment_post(): 
    # Set Client app credentials 
    app_consumer_id = app_undertest_credentials('app_consumer_id') 
    app_consumer_secret = app_undertest_credentials('app_consumer_secret') 
    app_access_token = app_undertest_credentials('app_access_token') 
    base_url = app_undertest_credentials('base_url') 
    end_point_url_sfx_str = end_points_dict('Appointment', 'v2.1') 
    httpmethod = 'POST' 

    # Create dictionary for json post payload 
    data_payload = {'startDateTime':'2017-08-15T11:00+10:00', 
       'endDateTime':'2017-08-15T11:30+10:00', 
       'practitioner': {'practitionerId':'a630f4ad-8b4b-4e06-8cee-7db56ba8b9bf'}, 
       'locationId': 'd8d4fe7c-765a-46a3-a389-54ce298a27e9', 
       'clients': [{'clientId':'abeff2be-ce6e-4324-9b57-e28ab7967b6c'}] 

    # Create claims dictionary payload for generation of JwToken 
    claims = { 
     'iss': 'http://myappsdomain.com.au', 
     'aud': 'https://targetservers.domain.com.au', 
     'nbf': _datetime.datetime.utcnow(), 
     'exp': _datetime.datetime.utcnow() + _datetime.timedelta(seconds=60), 
     'consumerId': app_consumer_id, 
     'accessToken': app_access_token, 
     'url': base_url + end_point_url_sfx_str, 
     'httpMethod': http_method 
    } 

    #create jwtoken and then convert to string 
    encoded_jwt_byte = jwt.encode(claim_payload, app_consumer_secret, algorithm='HS256') 
    jwt_str = encoded_jwt_byte.decode() 

    #Create authentication header 
    headers = {'Authorization': 'JwToken' + ' ' + jwt_str, 'content-type': 'application/json'} 

    uri = base_url + end_point_url_sfx_str 
    response = requests.post(uri, headers=headers, json=datapayload) 
    print(response.status) 
    print(response.json()) 
    response.close() 

Ich bin angesichts wireshark mit meinem Anruf, um herauszufinden, was tatsächlich zu senden, aber ich vermute, dass mir nur sagen, dass die Anrufe zweimal gesendet werden

+0

[Bearbeiten] Ihre Frage, mit welchem ​​Python-Modul und Version Sie verwenden, entweder 'python_jwt' oder 'pyjwt'? – stovfl

+0

Ich habe in dem anderen Modul hinzugefügt Versionen in Verwendung PyJWT 1.5.2., Anfragen 2.18.3, simplejson 3.11.1 und urllib3 1.22 – Roochiedoor

Antwort

1

Kommentar: Aber ich benötige eine Base64-codierte Zeichenfolge für das Senden der API Requestest.

In Bezug auf die Quelle

segments.append(base64url_encode(signature)) 
    return base64.urlsafe_b64encode(input).replace(b'=', b'') 
return b'.'.join(segments) 

alle ist base64 und kehrte als bytes. So sollten Sie sich gut mit

jwt_str = str(encoded_jwt_byte) 

kann leider nicht PyJWT verwenden.
Versucht mit python_jwt und es funktioniert wie erwartet.

mit Python getestet: 3.4.2 - Anfragen: 2.11.1

Sie benötigen wirklich zu encode(... und dann decode()?

#create jwtoken and then convert to string 
encoded_jwt_byte = jwt.encode(claim_payload, app_consumer_secret, algorithm='HS256') 
jwt_str = encoded_jwt_byte.decode() 

Wird jwt_str nicht das gleiche wie claim_payload sein?

+0

Aus irgendeinem Grund mit meinem System, wenn ich den jwtoken mit jwt.encode erstellen erstellt es Byte-Code trotz der Dokumentation sagt, es sollte eine Zeichenfolge zurückgeben ZB sieht es aus wie b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIU .... Aber ich benötigen eine Base64-codierte Zeichenfolge für das Senden der API-Anforderung. Durch erneutes Entschlüsseln wird eine Base64-codierte Zeichenfolge erstellt, die ich unter https://jwt.io/ überprüfen kann und die für meine get-Anfragen funktioniert. Wenn Sie irgendwelche Vorschläge haben, warum es ist, empfange ich eine Byte-Zeichenkette anstelle einer base64 codierten Zeichenkette, die ich – Roochiedoor

+0

interessiert bin Gerade verwirklichte ich jwt_str = str (coded_jwt_byte, 'utf-8') anstelle der Decodierung, die zu sein scheint das gleiche tun, wenn es nicht das Geheimnis hat, mit zu dekodieren. – Roochiedoor

+0

@ Roochiedoor: Meine Antwort aktualisiert – stovfl

0

Okay, die Ursache meines doppelten Post-Problems gefunden. Es war meine eigene dumme Schuld. Ganz unten in meiner Python-Datei am unteren Bildschirmrand hatte ich die Testfunktion aufgerufen und diese Zeile nicht bemerkt (daher habe ich es versäumt, sie in meinem obigen Code zu posten). Es setzt die Testfunktion in eine vollständige Wiederholungsschleife. .... :(Eine solche dummen Neuling Fehler. Danke für den Rat stovfl des codierten JwToken zur Handhabung.

Im Nachhinein jeden Beitrag auf Stackoverflow ich in Bezug auf doppelte Beiträge zu APIs gefunden habe war, weil es eine war Schleife in den Code des Benutzers, ich konnte es einfach nicht finden ..

Verwandte Themen