Stöd för Azure IoT-klient-SDK för tokenservrar från tredje part
Artikeln Kontrollera åtkomst till IoT Hub illustrerar hur en tokentjänst från tredje part kan integreras med IoT Hub. Den här artikeln beskriver stödet för sas-tokenautentisering (signatur för delad åtkomst) i var och en av Azure IoT-klient-SDK:erna. Den beskriver också både vad som behöver implementeras i ett enhetsprogram med hjälp av motsvarande SDK för varje språk och hur du använder enhetsbeomfångs- eller modulbeomfångstoken för principerna för delad åtkomst för DeviceConnect eller ModuleConnect.
Kontext och problem
I den Azure IoT Hub säkerhetsdokumentationen beskrivs mönstret för token-server från tredje part för SAS-autentisering med IoT Hub av IoT-enheter som använder Azure IoT-klient-SDK:er. Felaktiga antaganden som gjorts av en kund under ett nyligen genomfört enterprise-engagemang tyder dock på att du utan ytterligare förtydligande kan få ett missvisande intryck av den supportnivå som implementeras som standard i Azure IoT-klient-SDK:er.
Den här artikeln beskriver inlärningen från det engagemanget och förklarar vad som behöver göras i varje SDK för enheter för att uppnå autentisering med token-server från tredje part. Den här artikeln bör också hindra dig från att göra liknande felaktiga antaganden om stöd för mönstret token-server från tredje part i Azure IoT-klientens SDK.
Lösning
Azure IoT-klient-SDK:er ger olika nivåer av stöd för SAS-tokenautentisering, där var och en kräver anpassad kod för att slutföra funktionerna för autentisering och tokenhantering.
Utvärderingsfrekvensen för token beror på det valda transportprotokollet – MQTT, AMQP eller HTTPS. Variationen beror på protokollets kapacitet för att stödja proaktiv förnyelse av token och sessions-time-out. Endast AMQP implementerar proaktiv förnyelsesupport. Det innebär att de andra transporterna stänger anslutningen vid autentiseringsfel för SAS-token och sedan måste utföra en ny anslutningsåtgärd. Det här är en potentiellt dyr anslutningsåtgärd för klienten.
Om SAS-autentiseringen misslyckas utlöses ett fel av transportimplementering som kan hanteras i enhetsprogrammet av händelsehanteraren "Anslutningsstatus har ändrats". Om du inte implementerar en sådan hanterare stoppas vanligtvis enhetsprogrammet på grund av felet. Med rätt implementering av händelsehanteraren och tokenförnyelsefunktionen kan transporterna försöka ansluta på nytt.
Följande bild illustrerar mönstret token-server från tredje part:

Följande bild illustrerar implementeringsstöd i Azure IoT-klient-SDK med Mobile Net Operator-integrering:

Exempelimplementeringarna ingår i lagringsplatsen För Azure-exempel GitHub.
Problem och överväganden
Tänk på följande när du bestämmer om du vill implementera det här mönstret:
Klient-AZURE IOT HUB för Enhetsetableringstjänsten (Azure DPS) stöder inte SAS-tokenautentisering. Azure DPS-REST APIstöder SAS-tokenautentisering. För att kunna använda Azure DPS med en tokentjänst från tredje part för SAS-autentisering måste ett enhetsprogram därför implementera enhetens DPS-process med hjälp av Azure DPS-REST API.
Detta består av att göra en första åtgärd för registreringsbegäran och sedan avse API:et för driftstatus tills DPS-processen lyckas eller misslyckas. Om det lyckas kan du få information om enhetsetablering genom att begära dem från Azure DPS REST API Runtime Registration.
Referenser:
När du ska använda det här mönstret
Du bör använda det här mönstret när du vill autentisera till Azure IoT Hub IoT-enheter med hjälp av olika Azure IoT-klient-SDK:er. I stället för att använda klient-SDK:er för SAS-tokenautentisering använder du Azure DPS-REST API för att säkerställa implementering av proaktivt förnyelsestöd för alla transportmekanismer.
Exempel
Följande avsnitt innehåller exempel som du kan använda för olika programmeringsspråk, till exempel Embedded C, .NET, Java och Python.
Azure IoT Hub SDK för C- och Azure IoT Hub-enhets-SDK för Embedded C
Följande metod kan användas i enhetsprogram som skapats med Azure IoT C SDK eller Azure IoT Embedded C SDK. Ingen av SDK:erna tillhandahåller livslängdshantering för SAS-token, och därför måste du implementera en funktion för sas-tokenlivslängdshanterare.
SAS-token kan användas via IOTHUB_CLIENT_CONFIG struktur genom att ange deviceSasToken-medlemmen till token och göra deviceKey null. Andra oanvända värden, till exempel protocolGatewayHostName,måste också anges till null.
CONFIG = (IOTHUB\_CLIENT\_CONFIG\*)MALLOC(SIZEOF (IOTHUB\_CLIENT\_CONFIG));
CONFIG-\>PROTOCOL = PROTOCOL;
CONFIG-\>DEVICEID = DEVICEID;
CONFIG-\>IOTHUBNAME = IOTHUBNAME;
CONFIG-\>IOTHUBSUFFIX = IOTHUBSUFFIX;
CONFIG-\>DEVICEKEY = 0;
CONFIG-\>DEVICESASTOKEN = TOKEN;
CONFIG-\>PROTOCOLGATEWAYHOSTNAME = 0;
`The created IOTHUB\_CLIENT\_CONFIG can then be provided to the IoTHubDeviceClient\_Create function to establish a DeviceClient instance.`
IF ((IOTHUBCLIENTHANDLE = IOTHUBDEVICECLIENT\_CREATE(CONFIG)) == NULL)
{
(VOID)PRINTF("ERROR: IOTHUBCLIENTHANDLE IS NULL!\\R\\N");
}
`To capture SAS token authentication failures, a handler needs to be implemented for the IoTHubDeviceClient\_SetConnectionStatusCallback.`
(VOID)IOTHUBDEVICECLIENT\_SETCONNECTIONSTATUSCALLBACK(IOTHUBCLIENTHANDLE,
CONNECTION\_STATUS\_CALLBACK, NULL);
Den connection_status_callback kan fånga IOTHUB_CLIENT_CONNECTION_STATUS_REASON av IOTHUB_CLIENT_CONNECTION_EXPIRED_SAS_TOKEN utlösa en förnyelse av SAS-token via tokentjänsten från tredje part. Detta krävs för alla transporter för att samla in anslutningsproblem, men krävs specifikt av transporter som inte stöder proaktiv förnyelse av SAS-token. Proaktiv hantering av LIVSLÄNGD för SAS-token kan implementeras som en funktion som körs upprepade gånger under "drift"-loopen för enhetsprogram. Att säkerställa att livslängden för token utvärderas ofta och tokenförnyelse kan köras proaktivt när det behövs.
Sammanfattning av implementering av SAS-tokenautentisering för CDK:er:
Implementera en ConnectionStatusCallback-hanterare för att samla IOTHUB_CLIENT_CONNECTION_EXPIRED_SAS_TOKEN händelse och utlösa tokenförnyelse.
Använd en IOTHUB_CLIENT_CONFIG för att ange enhetens SAS-token för IoTHubDeviceClient_Create.
Implementera proaktiv hantering av SAS-tokenlivslängd som en del av enhetsprogrammets åtgärdsloop.
Referenser:
Azure IoT Hub SDK för .Net
Azure IoT-klient-SDK för .Net implementerar stöd för livslängdshantering för SAS-token via den abstrakta Klassen DeviceAuthenticationWithTokenRefresh. En konkret implementering av den här klassen, som lägger till tokenförnyelsefunktioner, kan tillhandahållas som autentiseringsmetod för en DeviceClient.Create-metod. Transportimplementeringarna förnyar automatiskt token via autentiseringsmetoden efter behov. En ConnectionStatusChangesHandler krävs för att samla in anslutningsändringar och förhindra att undantag utlöses av transporterna.
Exempelimplementering som baseras på Klassen DeviceAuthenticationWithTokenRefreash
INTERNAL CLASS STSDEVICEAUTHENTICATIONWITHTOKENREFRESH :
DEVICEAUTHENTICATIONWITHTOKENREFRESH
{
PRIVATE READONLY STRING \_STSCONNECTURL =
"HTTP://LOCALHOST:8080/STS/AZURE/TOKEN/OPERATIONS?SR={0}/DEVICES/{1}";
PRIVATE CONST INT DEFAULTTIMETOLIVESECONDS = 1 \* 60 \* 60;
PRIVATE CONST INT DEFAULTBUFFERPERCENTAGE = 15;
PUBLIC STSDEVICEAUTHENTICATIONWITHTOKENREFRESH(STRING DEVICEID, INT
SUGGESTEDTIMETOLIVESECONDS, INT TIMEBUFFERPERCENTAGE) : BASE(DEVICEID,
SUGGESTEDTIMETOLIVESECONDS, TIMEBUFFERPERCENTAGE)
{
IF (STRING.ISNULLORWHITESPACE(DEVICEID))
{
THROW NEW ARGUMENTNULLEXCEPTION(NAMEOF(DEVICEID));
}
}
PROTECTED OVERRIDE TASK\<STRING\> SAFECREATENEWTOKEN(STRING IOTHUB, INT
SUGGESTEDTIMETOLIVE)
{
STRING RESULT;
STRING URL = STRING.FORMAT(\_STSCONNECTURL, IOTHUB, DEVICEID);
HTTPCLIENTHANDLER HANDLER = NEW HTTPCLIENTHANDLER();
HTTPCLIENT = NEW HTTPCLIENT(HANDLER);
TRY
{
VAR APIRESPONSE = HTTPCLIENT.GETASYNC(URL).RESULT;
IF (APIRESPONSE.ISSUCCESSSTATUSCODE)
{
RESULT = APIRESPONSE.CONTENT.READASSTRINGASYNC().RESULT;
}
ELSE
{
THROW NEW HTTPREQUESTEXCEPTION();
}
}
CATCH (HTTPREQUESTEXCEPTION)
{
RESULT = NULL;
}
RETURN TASK.FROMRESULT(RESULT);
}
}
Sammanfattning av implementering av SAS-tokenautentisering Azure IoT Hub SDK för enheter för .Net:
Implementera en konkret klass baserat på den abstrakta klassen DeviceAuthenticationWithTokenRefresh, som implementerar tokenförnyelsefunktioner.
Implementera en ConnectionStatusChangesHandler för att avbilda transportanslutningsstatus och undvika undantag som utlöses av transportimplementering.
Referenser:
Azure IoT Hub SDK för Java
Azure IoT Client SDK för Java implementerar stöd för hantering av SAS-tokenlivslängd via SasTokenProvider-gränssnittet. En klass som implementerar det här gränssnittet med sas-tokenförnyelsefunktioner kan användas som SecurityProvider i en DeviceClient-konstruktor. Transportimplementeringarna förnyar automatiskt token via säkerhetsprovidern efter behov. En ConnectionStatusChangeCallback måste registreras för att samla in anslutningsändringar och förhindra att undantag utlöses av transporterna.
Exempelimplementering av säkerhetsprovidern som implementerar SasTokenProvider-gränssnittet:
IMPORT JAVA.IO.IOEXCEPTION;
IMPORT JAVA.NET.URI;
IMPORT JAVA.NET.HTTP.HTTPCLIENT;
IMPORT JAVA.NET.HTTP.HTTPREQUEST;
IMPORT JAVA.NET.HTTP.HTTPRESPONSE;
IMPORT JAVA.TIME.DURATION;
PUBLIC CLASS STSSECURITYPROVIDER IMPLEMENTS SASTOKENPROVIDER {
PRIVATE FINAL STRING HOSTNAME;
PRIVATE FINAL STRING DEVICEID;
PRIVATE INT RENEWALBUFFERSECONDS;
PRIVATE LONG EXPIRYTIMESECONDS;
PRIVATE CHAR[] SASTOKEN;
PUBLIC STSSECURITYPROVIDER(STRING HOSTNAME, STRING DEVICEID)
{
THIS.HOSTNAME = HOSTNAME;
THIS.DEVICEID = DEVICEID;
THIS.RENEWALBUFFERSECONDS = 120;
THIS.EXPIRYTIMESECONDS = (SYSTEM.CURRENTTIMEMILLIS() / 1000);
}
\@OVERRIDE
PUBLIC CHAR[] GETSASTOKEN() {
LONG CURRENTTIMESECONDS = (SYSTEM.CURRENTTIMEMILLIS() / 1000);
TRY {
IF (THIS.SASTOKEN == NULL \|\| THIS.EXPIRYTIMESECONDS +
THIS.RENEWALBUFFERSECONDS \>= CURRENTTIMESECONDS) {
THIS.SASTOKEN = STSGETTOKEN();
ASSERT THIS.SASTOKEN != NULL;
STRING T = STRING.COPYVALUEOF(THIS.SASTOKEN);
STRING[] BITS = T.SPLIT("SE=");
LONG L = LONG.PARSELONG(BITS[1]);
THIS.EXPIRYTIMESECONDS = L; // THE SE= NUMBER
THIS.RENEWALBUFFERSECONDS = (INT) (L \* 0.15); // RENEW WITHIN 15% OF EXPIRY
}
} CATCH (INTERRUPTEDEXCEPTION \| IOEXCEPTION E) {
E.PRINTSTACKTRACE();
}
RETURN THIS.SASTOKEN;
}
PRIVATE CHAR[] STSGETTOKEN() THROWS IOEXCEPTION, INTERRUPTEDEXCEPTION {
STRING STSURL =
STRING.FORMAT("HTTP://LOCALHOST:8080/STS/AZURE/TOKEN/OPERATIONS?SR=%S/DEVICES/%S",
THIS.HOSTNAME, THIS.DEVICEID);
HTTPREQUEST REQUEST = HTTPREQUEST.NEWBUILDER()
.URI(URI.CREATE(STSURL))
.TIMEOUT(DURATION.OFMINUTES(2))
.HEADER("CONTENT-TYPE", "APPLICATION/JSON")
.BUILD();
HTTPCLIENT CLIENT = HTTPCLIENT.NEWBUILDER()
.VERSION(HTTPCLIENT.VERSION.HTTP\_1\_1)
.CONNECTTIMEOUT(DURATION.OFSECONDS(20))
.BUILD();
HTTPRESPONSE\<STRING\> RESPONSE = CLIENT.SEND(REQUEST,
HTTPRESPONSE.BODYHANDLERS.OFSTRING());
IF(RESPONSE.STATUSCODE() \<200 \|\| RESPONSE.STATUSCODE()\>=300) {
RETURN NULL;
}
IF(RESPONSE.BODY().ISEMPTY()) {
RETURN NULL;
}
RETURN RESPONSE.BODY().TOCHARARRAY();
}
}
Implementeringssammanfattning för SAS-tokenautentisering Azure IoT Hub SDK för Java:
Implementera SasTokenProvider-gränssnittet i en klass och inkludera tokenförnyelsefunktioner.
Implementera en ConnectionStatusChangeCallback-hanterare för att samla in ändringar av transportanslutningsstatus och undvika undantag som utlöses av transportimplementering.
Referenser:
Azure IoT Hub SDK för Python
Sdk Azure IoT Hub för Python implementerar stöd för SAS-token via metoder på IoTHubDeviceClient-objektet. Dessa metoder gör det möjligt att skapa en enhetsklient med hjälp av en token och möjligheten att ange en uppdaterad token när enhetsklienten har skapats. De implementerar inte livslängdshantering för token, men det kan enkelt implementeras som en asynkron åtgärd.
En Python 3.7-exempelimplementering som bara visar funktionskonturerna:
ASYNC DEF MAIN():
\# GET A SASTOKEN YOU GENERATED
SASTOKEN = GET\_NEW\_SASTOKEN()
\# THE CLIENT OBJECT IS USED TO INTERACT WITH YOUR AZURE IOT HUB.
DEVICE\_CLIENT = IOTHUBDEVICECLIENT.CREATE\_FROM\_SASTOKEN(SASTOKEN)
\# CONNECT THE CLIENT.
AWAIT DEVICE\_CLIENT.CONNECT()
\# DEFINE BEHAVIOR FOR PROVIDING NEW SASTOKENS TO PREVENT EXPIRY
ASYNC DEF SASTOKEN\_KEEPALIVE():
WHILE TRUE:
AWAIT ASYNCIO.SLEEP(NEW\_TOKEN\_INTERVAL)
SASTOKEN = GET\_NEW\_SASTOKEN()
AWAIT DEVICE\_CLIENT.UPDATE\_SASTOKEN(SASTOKEN)
\# ALSO RUN THE SASTOKEN KEEPALIVE IN THE EVENT LOOP
KEEPALIVE\_TASK = ASYNCIO.CREATE\_TASK(SASTOKEN\_KEEPALIVE())
\# CANCEL THE SASTOKEN UPDATE TASK
KEEPALIVE\_TASK.CANCEL()
\# FINALLY, SHUT DOWN THE CLIENT
AWAIT DEVICE\_CLIENT.SHUTDOWN()
IF \_\_NAME\_\_ == "\_\_MAIN\_\_":
ASYNCIO.RUN(MAIN())
Sammanfattning av Azure IoT Hub SDK för Python SAS-tokenautentisering:
Skapa en funktion för generering av SAS-token.
Skapa en enhetsklient med IoTHubDeviceClient.create_from_sastoken.
Hantera tokenlivslängd som en separat aktivitet och förse enhetsklienten med en förnyad token när det krävs av IoTHubDeviceClient.update_sastoken-metoden.
Referenser:
Azure IoT Hub sdk för enheter för Node.JS/JavaScript
Azure IoT för Node.JS/JavaScript implementerar en SharedAccessSignatureAuthenticationProvider som skickar en SAS-token till enhetsklienten och transporterar för att autentisera med IoT Hub. Den implementerar inte några funktioner för tokenförnyelse. Enhetsprogrammet måste hantera livslängden för token och förnya token efter behov.
Använd enhetens klientmetoder frånSharedAccessSignature och updateSharedAccessSignature för att initiera en anslutning med IoT Hub och ange en förnyad token till SharedAccessSignatuteAuthenticationProvider, vilket gör att autentiseringsprovidern skickar en newTokenAvailable-händelse till transporterna.
Ett grundläggande SAS-tokenexempel finns i simple_sample_device_with_sas.js exempel.
Sammanfattning av Azure IoT Hub SDK för Node.JS/JavaScript
Implementera livslängdshantering och förnyelse för SAS-token.
Använd enhetsklienten frånSharedAccessSignature för att skapa en klientinstans för enheten.
Använd enhetsklientuppdateringSharedAccessSignature för att ange en förnyad token.
Referenser: