CardSpace és ASP.NET AJAX 3: Adatok bekérése és elküldése

(Aki esetleg lemaradt volna a bevezetőről, ezen a címen találja meg.)

Hozzunk létre Visual Studioban egy új ASP.NET AJAX-Enabled Web Site-ot, méghozzá IIS-en http-n kereszül, nem pedig File System locationnel. Ehhez rendszergazdai jogokkal kell indítani a Studiot! Ha később szeretnénk debuggolni, akkor az Internet Information Services MMC snap-inben engedélyezzük a Windows Authenticationt az így létrehozott mappánkra.

A kártya adatainak bekérése nem ördöngősség, mindössze egy OBJECT tag kell hozzá, amiben megadjuk az ún. claimeket, azaz tudatjuk a klienssel és a felhasználóval, hogy milyen adatokat várunk tőle, valahogy így:

<object name="xmlToken" id="objIdentitySelector" style="visibility:hidden;">
  <param name="tokenType" 
         value="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1" />
  <param name="requiredClaims" 
         value="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname 
                http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname 
                http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress 
                http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier" />
</object>

A sok claim közül a legfontosabb a privatepersonalidentifier, ez az a kliens oldali azonosító, amire vadászunk. A visibility stílust azért állítottam hiddenre, hogy ne jelenjen meg a böngészőben kis piros kocka az OBJECT tag helyén és ne is foglaljon helyet.

Ezen kívül az OBJECT tag TYPE attribútumát application/x-informationcard értékre kell állítanunk, de ezt inkább JavaScriptből fogjuk megtenni. Az objektum akkor jeleníteni meg a kártya bekérő ablakot, ha valaki hozzáfér a value tulajdonságához, akkor viszont azonnal és mindig. Ez elég kellemetlen, hiszen az oldal elpostázásakor a value értéke mindenképpen kiolvasódik, ami nagyon zavaró, hiszen egyáltalán nem biztos, hogy emiatt történik postback. Gondoljunk csak arra, hogy ezt a funkcionalitást a login oldalon fogjuk elhelyezni, a már működő Login kontroll alternatívájaként. Az alapértelmezett viselkedés az lenne, hogy amikor a felhasználó megadja a nevét és a jelszavát és rákattint a bejelentkezés gombra, még a rendszer az arcába tolja a kártya kiválasztó (ún. Identity Selector) ablakot. Ezen nekem csak úgy sikerült felülkerekednem, hogy a viselkedést meghatározó TYPE attribútumot akkor állítjuk be, amikor szükséges.

Tegyünk az oldalra egy linket, ami majd meghívja a szükséges JavaScriptet:

    <a href="javascript: selectInfoCard();">Kártya kiválasztása</a>

A meghívott függvényben az a feladatunk, hogy egy rejtett mezőbe átmásoljuk az Identity Selector által visszaadott XML-t, ugyanis a rejtett mező tartalmát sokkal könnyebben tudjuk elérni szerver oldalon, mint az OBJECT tartalmát. Ehhez persze kell egy rejtett mező, amiben az ún. XML Token fog utazni:

    <input id="hidIdentityToken" type="hidden" runat="server" />

A rejtett mező és az objektum elérését legegyszerűbben az ASP.NET AJAX-ban megjelenő $get függvénnyel tehetjük meg:

    <script language="javascript" type="text/javascript">
        function selectInfoCard()
        {
            var oIS = $get( "objIdentitySelector" );
            var hIT = $get( "hidIdentityToken" );
            oIS.type="application/x-informationcard";
            hIT.value = oIS.value;
            $get( "form1" ).submit();    
        }
    </script>

Ezzel azért van legalább 2 probléma:

Az első, hogy ha mindezt egy kontrollban valósítjuk meg, akkor az objektumok elérése nem lesz ilyen egyszerű, a rejtett mező szerver kontroll lévén más azonosítót fog kapni. Ezt persze szerver oldalon le tudjuk kérdezni és ki tudjuk vezetni egy property-be:

    protected string HiddenFieldClientName
    {
        get
        {
            return this.hidIdentityToken.Name;
        }
    }

A property-t pedig be tudjuk drótozni a JavaScriptbe és a korábbi második sort kicserélhetjük erre:

    var hIT = $get( "<%= HiddenFieldClientName %>" );

A második problémát szintén az ASP.NET fogja okozni. Mivel az Identity Selector kontroll XML-t ad vissza és mi azt akarjuk a szerverre postázni, ezért "A potentially dangerous Request.Form value was detected from the client" hibaüzenetet fogunk kapni. A mezei megoldás persze az, hogy letiltjuk a validálást szerver oldalon, de mivel éppen olyan kódot írunk, amit majd a login oldalon is fogunk használni, ez nem túl bölcs lépés lenne.

Ehelyett sokkal szebb feladat, hogy megírjuk a Server.HtmlEncode függvényt kliens oldalra, amivel szépen hátéemelesítjük az XML, hogy aztán majd szerver oldalon egy csapásra vissza tudjuk alakítani. Sajnos ezt nekünk kell megírnunk, mert az AJAX Library nem tudja (pedig illene neki). Sokféle megoldás közül választhatunk, én úgy döntöttem, hogy a String osztály funkcionalitását terjesztem ki egy újabb függvénnyel (gyanítom, hogy ez nem tökéletes, de eddig működött nálam):

    String.prototype.htmlEncode = function() {
        s = this;
        a = s.split( "&" ); s = a.join( "&amp;" );
        a = s.split( "<" ); s = a.join( "&lt;" );
        a = s.split( ">" ); s = a.join( "&gt;" );
        a = s.split( '"' ); s = a.join( "&quot;" );
        return s;    
    }

Ezt felhasználva módosíthatjuk a selectInfoCard() metódust:

    hIT.value = new String( oIS.value ).htmlEncode();

Ha eddig ügyesek voltunk, akkor szerver oldalon egyetlen sorral el tudjuk érni a kártyát reprezentáló XML tokent:

    string xmlToken = this.Server.HtmlDecode( this.hidIdentityToken.Value );

Ezzel tehát megoldottunk a bejelentkezéshez szükséges adatok elkérését és elküldését. De ez persze nem fog mindig működni… folyt. köv. 

 

Technorati tags: , ,

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s