Ez az előző cikk folytatása konkrét példakódokkal.

Adatbázis

Tegyük fel, hogy az adatbázisban fogjuk tárolni a felhasználókat.


CREATE TABLE WsApiUsers (
   ApiKey      Char(32) NOT NULL UNIQUE,
   SecretKey   VARCHAR(40) NOT NULL UNIQUE,
 PRIMARY KEY (ApiKey)
);

Az ApiKey egyedi azonosító a felhasználók azonosítására szolgál.
A SecretKey egy titkosító kulcs, ami nem összetévesztendő
a jelszóval. Ezzel a titkos kulccsal kell a felhasználónak titkosítania egy
sztringet (a sessionId-t), amit majd a kiszolgálótól kap.

Szükségünk van még egy adatbázis táblára, amelyben az
éppen aktív munkamenetek listáját fogjuk tárolni.
Minden munkamenetet az egyedi SessionID azonosít, és ehhez még különböző információk társulnak.

WsActiveSessions tábla oszlopai
SessionID A munkamenet egyedi azonosítója.
IP A kliens IP cime. Jól jöhet ez az információ, ha a későbbiekben úgy
döntünk, hogy feljavitjuk az autentikációt.
Például az autentikáció a jelszó és a felhasználói néven kívül ellenőrizné még a kliens IP címét is.
Csak egy bizonyos IP címről, vagy IP cím subnetről érkező SOAP üzeneteket engedne tovább. Így valamelyest
erősítenénk a webszolgáltatás biztonságát.
UserID Ez egy idegen kulcs, és a WsApiUsers adatbázis táblára mutat. Ha értéke NULL,
a kliens még nem jelentkezett be (nincsen autentikálva), kiléte ismeretlen.


CREATE TABLE WsActiveSessions (
	SessionID  Char(40) NOT NULL UNIQUE,
	IP         Char(32) NOT NULL,
 	UserID     SMALLINT UNSIGNED NULL,
 Primary Key (SessionID),
 FOREIGN KEY (UserID) REFERENCES WsApiUsers (ID)
)
ENGINE=HEAP
MAX_ROWS = 250;

A kliens

A kliensnek először egy munkamenet azonosítót kell kérnie a getSessionId tagfüggvény meghívásával.
Második lépésben összefűzzük a titkos kulcsot a kiszolgálótól kapott sessionId-val, majd a kapott
karakterláncból egy 128 bites kivonatot képezünk MD5 titkosítással. Ebben az a jó, hogy a titkos kulcsunkat nem
küldjük el a hálózaton keresztül.

autentikacio

Figyeljük meg az XML üzeneteket. Vegyük észre, hogy a login metódus meghívása már
tartalmazza a SOAP Header elemben a munkamenet azonosítót. A getSessionId metódus ugyanis
az egyetlen metódus, amely meghívható üres SOAP Header elemmel, a többi metódus
megköveteli a sessionId jelenlétét a SOAP fejlécben.

A kiszolgáló

Kezdjük a WSDL megírásával.
A munkamenet azonosítót így deklaráltuk a WSDL fájlban:

Arra van szükségünk, hogy hozzáférjünk a SOAP üzenet fejlécében lévő sessionId elem tartalmához.
Erre konkrét példát egy előző blogbejegyzésben találunk:
"PHP SOAP kiterjesztés - SOAP Header használata".

Továbbá azt is tudnunk kell, hogy a kliens melyik metódust hívta meg.
Ezt is az XML üzenetből tudjuk kiparszolni a köv. kóddal (a lényeg az XPath kifejezés).

Ha a kliens a getSessionId tagfüggvényt hívta meg, akkor nem ellenőrizzük a sessionId jelenlétét a SOAP fejlécben.
Ellenkező esetben SOAP fault-ot dobunk, ha a sessionId hiányzik a SOAP fejlécből.

Amikor megkaptuk a sessionId-t a SOAP üzenetben, leellenőrizzük, hogy létezik-e ilyen aktív munkamenet a
WsActiveSessions adatbázis táblában. Ha igen, akkor felújítjuk a PHP sessiont a
session_id() PHP funkcióval.

Ettől a pillanattól kezdve elérhetőek a klienshez tartozó session változók is.

Minden SOAP üzenet tartalmaz egy kiegészítő SOAP fejlécet (Header elem).
Az opcionális fejléc elem, a Header kiegészítő adatok megadására szolgál.
Ugyanabból a célból létezik, mint a HTTP Header. Leggyakrabban a Header elembe
a munkamenet (session) azonosítót, vagy a kliens hitelesítéséhez szükséges adatokat teszik.

Kliens

Lássuk, hogyan kell a PHP5-ben megjelent SOAP kiterjesztéssel beállítani egy SOAP fejlécet.
Tegyük fel, hogy a munkamenet azonosítot kell elküldenünk minden egyes SOAP üzenetben.
A Header elem bármilyen elemeket tartalmazhat, csakis tőlünk függ a tartalma
(na meg persze a kiszolgáló oldalon a WSDL fájlban deklaráltaktól).
A példa kedvéért a munkamenet azonosítót egy sessionId nevű elemben kell elhelyeznünk,
ami egy további ApiUserAuthHeader szülő elemben kell, hogy legyen. Ezek az elemek pedig a
urn:ExampleAPI névtérben kellenek, hogy legyenek.
Lássunk egy kész SOAP üzenetet, amit a kliens küld a kiszolgálónak.

Íme a PHP kód:

A SoapHeader osztály
szolgál SOAP fejléc létrehozására. Létre kellett hoznunk egy ApiUserAuthHeader osztályt, aminek egy
sessionId tulajdonságot adunk.

Annak ellenére, hogy a SoapHeader konstruktorában, az első paraméterrel beállítottuk az urn:ExampleAPI, a SOAP
kiterjesztés valamilyen okból mégsem ad a sessionId elemnek prefixet,
ezért volt szükség az ApiUserAuthHeader osztály konstruktorában a sessionId-t SoapVar objektummal létrehozni
(egyébként elég lett volna egy sima publikus sessionId nevű változó is).
Erről itt olvashatunk többet: http://bugs.php.net/bug.php?id=40318&edit=1.

A login metódusnak a paramétereket így is átadhattuk volna, ez is helyes megoldás:

Ha viszont így hívtuk volna meg a login metódust, akkor a SOAP kiterjesztés helytelenül kódolta volna a paramétereket a SOAP törzsben.


$ret = $client->__call('login',array('WorkaholicGroupApiKey','0c9ed93ec403851a2f7682aceb98a5a9'));

Kiszolgáló

Kiszolgáló oldalon a következőkre van szükségünk:

Elkapni a beérkezett SOAP XML üzenetet

$request = file_get_contents('php://input'); 

Kiparszolni belőle a sessionId elem tartalmát

Linkek

Az Eclipse fejlesztőkörnyezet hasznos eszközöket nyújt webszolgáltatások fejlesztőinek is.
Egyik ilyen hasznos eszköze (az Eclips-hez írt Web Tools Platform része) a
Web Service Explorer.
SOAP webszolgáltatások tesztelésére, debuggolására szolgál. Az Eclipse letöltési oldaláról az Eclipse Classic-ot ajánlom letölteni, mivel ahhoz már nem kell semmit sem hozzáinstallálni.


Eclipse Web Service Explorer screen