CrossDomain Witam ! Dziś postanowiłem dokładnie wyedukować się w tematyce komunikacji sieciowej za pomocą Silverlight. Choć ta tematyka jest mi znana, to jednak niektórych rzeczy nie próbowałem w praktyce. Cóż to za aplikacja, która czegoś nie pobiera i nie wyświetla na swój własny sposób. Spis treści jest następujący:
Aplikacja Silverlight wykonuje się wewnątrz przeglądarki, nawet będąc w trybie poza nią wykonuje się oddzielnie (SandBox). Dlatego też trzeba zrobić to inaczej, niż np. w ASP.NET, ponieważ jest on technologią wykonującą się po stronie serwera więc może otrzymywać bezpośrednio dane . Czyli nasza aplikacja w Silverlight nie ma bezpośredniego dostępu do bazy danych bez użycia jakiegoś łącznika, który najczęściej nazywamy usługą sieciową (web service).
Między domenowy dostęp - Client acces policy
Ten sam zabieg bezpieczeństwa dotyczy komunikacji między różnymi domenami. Akurat powiem, że kiedyś złapałem się na tym pisząc prostą aplikację pobierającą plik XML. Jeśli nasza aplikacja jest hostowana , uruchomiona pod adresem “http://cezarywalenciuk.blogspot.com” i próbuje użyć usługi sieciowej, która jest hostowana na “http://dropbox.pl” to zapytanie staje się między domenowe. Z powodu wymogów bezpieczeństwa aplikacja nie uruchomi usługi sieciowej.
Oczywiście problem polega na tym, że komu ufać a komu nie. To da się rozwiązać. Silverlight tak jak kiedyś Flash wymagał od klienta aby aplikacja była hostowana na tej samej domenie. Gdy wykonuje się zapytanie między domenowe (sprawdzałem nawet w Fiddler2) Silverlight prosi automatycznie o plik xml “cross-domain-policy”, jeśli go nie znajdzie to serwer uznaje, że nie ma prawa użyć danego zasobu.
Plik clientaccesspolicy.xml musi znajdować się w samym root. domeny gdzie hostujemy naszą aplikację. Nawet jeśli prawidłowy plik istnieje, to jeśli się tam nie znajduje jest bezużyteczny.
Jeśli plik xml ma poprawnie napisane atrybuty to nasza aplikacja będzie miała dostęp do danego zasobu. Wzór pliku wygląda następująco i można sobie pomóc ściągając z Extension-Menagera w Visual Studio 2010 gotowy wzór takiego pliku.
<?xml version="1.0" encoding="utf-8" ?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="/*Specify request headers like Content-Type,SOAPAction*/">
<domain uri="/*Specify domains with granted access*/"/>
</allow-from>
<grant-to>
<resource include-subpaths="false" path="/"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
Aby być bardziej zabawnym do pliku wystarczy dodać gwiazdkę “*” w “http-headers” i w “domain uri” i w sumie w ten sposób wszystkie zapytania zostaną uznane za poprawne. Na pewno w tym kursie będę wracał do tego jeszcze nie raz. Warto jednak się zapoznać z głębszą strukturą tego pliku.
Element/atrybut | Wymagany | Opis |
access-policy | Tak | Element root w pliku policy. |
cross-domain-policy | Tak | Zawiera jedną bądź więcej elementów policy. |
policy | Tak | Definiuje zasady dla pojedynczej domeny albo grup domen. |
allow-from | Tak | Informacje o dozwolonych domenach, jeśli nie zawiera elementu to żaden dostęp nie jest zezwalany. |
http-request-headers | Nie | Definiuje jaki nagłówek jest zezwalany, który został wysłany przez usługę sieciową w danej domenie. Jeśli jest pusty żadne nagłówki nie są dozwolone. |
domain | Tak | Definiuje domenę. |
uri | Tak | Definiuje, jaki dokładnie może mieć dostęp. |
grant-to | Tak | Jaki zasób ma być dostępny. |
resource | Tak | Wymagany dla klasy “WebClient” and “HttpWebRequest”. Definiuje jaki zasób powinien być użyty w danej polityce. |
Path | Tak | Jak jak wyżej. Format Uri jest relatywny względem początku domeny. |
include-subpaths | Nie | Tak jak wyżej. Jeśli jest pusty dostęp do podfolderów jest zabroniony. |
socket-resource | Tak | Wymagany przy dostępnie przez socket-y.Definiuje, jaki socket jest dostępny. |
Port | Tak | Wymagany przy dostępnie przez socket-y. Definiuje porty w zasięgu od 4502 do 4534. |
Protocol | Tak< | Wymagany przy dostępnie przez socket-y. Definiuje jakie protokoły są dostępne przez daną politykę. Jedynym protokołem, który jest teraz dostępny jest TCP. |
Ograniczenie, jeśli chodzi o Silverlight i plik Client acces policy:
- Może być ona używana tylko przez klasy “WebClient” i “HttpWebRequest” oraz przez usługi korzystające z proxy . Sockety nie są dostępne.
- Cała domena musi zezwolić na dostęp Silverlight do pliku crossdomain.xml. Silverlight nie obsługuje zaawansowanych właściwości crossdomain.xml.
Bezpieczeństwo jest zawsze najważniejsze. Akurat nie chciałbyś aby aplikacje takie jak Flash i Silverlight miały dostęp do wszystkiego albo żeby ktoś bez twojej zgody korzystał z twoich plików, na twoim serwerze.
Prosta aplikacja symulująca zdarzenie cross-domain
Aby zrobić symulacje takiego zdarzenia stworzyłem dwa puste projekty web i dałem im określone porty. CrossDomainTest ma port 4000 a HostSilverlight ma port 9000. Stworzyłem prostą aplikację Silverlight, która zawiera jeden przycisk i jeden TextBlock. w “CrossDomainTest” dodałem plik xml “clienaccesspolicy.xml” oraz folder “zasób” a w nim plik txt, który pobierzemy i odtworzymy.
Układ Projektów i plik xml.
W Silverlight po naciśnięciu naszego przycisku zostanie pobrany plik za pomocą prostej klasy “WebClient”. Po asynchronicznym pobieraniu zajdzie zdarzenie “OpenReadComleted”. Sprawdzam czy plik pobrał się poprawnie po czym wyświetlam go w TextBlock-u TB_1.
private void button1_Click(object sender, RoutedEventArgs e)
{
WebClient client = new WebClient();
client.OpenReadCompleted +=
new OpenReadCompletedEventHandler(client_OpenReadCompleted);
string s = @"http://localhost:4000/Zasob/TextFile.txt"
client.OpenReadAsync(new Uri(s, UriKind.Absolute));
}
void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if (!e.Cancelled && (e.Error == null))
{
using (TextReader writer = new StreamReader(e.Result))
{
TB_1.Text = writer.ReadToEnd();
}
}
else
{
WebException webEx = e.Error as WebException;
if (webEx != null)
{
TB_1.Text = webEx.Message;
}
else if (e.Error is SecurityException)
{
SecurityException secEX = e.Error
as SecurityException;
TB_1.Text = secEX.InnerException.Message;
}
}
}