Używanie AuthSub z biblioteką klienta .NET

Jeff Fisher, zespół Google Data API
sierpień 2007 r.

Wprowadzenie: dlaczego uwierzytelnienie jest ważne?

Ogromną zaletą interfejsów API danych Google („GData”) jest to, że pozwalają deweloperom tworzyć aplikacje, które wchodzą w interakcje z usługami Google. Mówiąc bardziej szczegółowo, umożliwiają one dostęp do prywatnych danych użytkowników do użycia w aplikacji. Interfejsy API umożliwiają zapisywanie aplikacji do synchronizowania, importowania i eksportowania danych oraz zarządzania nimi w inny sposób. Chociaż interfejsy API dają te zaawansowane możliwości, należy pamiętać o odpowiedzialnym korzystaniu z nich. Dane użytkownika to informacje prywatne, dlatego chcesz mieć do nich bezpieczny dostęp. Istotnym elementem jest bezpieczne uwierzytelnianie na serwerach Google.

Załóżmy, że masz świetną aplikację internetową, którą chcesz powiązać z danymi przechowywanymi w usługach internetowych Google. Teraz musisz się uwierzytelnić, aby uzyskać dostęp do tych danych prywatnych. Może użyć czegoś prostego, na przykład ClientLogin? To może załatwić sprawę, ale wtedy jeszcze dane prywatne będą obsługiwane: dane logowania użytkownika. ClientLogin wymaga, aby aplikacja prosiła o nazwę użytkownika Google oraz hasło. Jest to dopuszczalne w przypadku aplikacji komputerowych, które działają na osobistych komputerach użytkowników, ale nie są idealnymi aplikacjami internetowymi. Poza odpowiedzialnością za przetwarzanie tych danych na własnym serwerze niektórzy z Twoich ostrożnych użytkowników mogą bać się, że będziesz przechowywać ich dane. Inną częstą wskazówką użytkowników jest chęć przyznania programowi dostępu tylko do jednej usługi (takiej jak wydarzenia w Kalendarzu Google), ale nie innej usługi (takiej jak Dokumenty Google). AuthSub rozwiązuje oba te problemy, pozwalając użytkownikowi uwierzytelnić się na serwerach Google. Dzięki temu program może zażądać dostępu tylko do tego, czego potrzebuje.

Skoro znasz już tajniki teorii AuthSub, czas zająć się kodowaniem. W tym artykule zastosowaliśmy proste rozwiązania i wykonaliśmy wszystkie działania na jednej stronie ASP, ale możesz łatwo zintegrować przedstawione tu techniki z własną aplikacją.

Obsługa uwierzytelniania

Co jest więc potrzebne do korzystania z AuthSub w aplikacji internetowej? Najpierw zaimportujemy kilka standardowych plików z biblioteki klienta GData:

<%@ Import Namespace="Google.GData.Client" %>
<%@ Import Namespace="Google.GData.Extensions" %>
<%@ Import Namespace="System.Net" %>

Pierwszą rzeczą, jaką musisz zrobić, jest wysłanie użytkownika do specjalnie przygotowanego adresu URL. Dzięki temu serwery Google obsługują uwierzytelnianie i przekierowują użytkownika z powrotem do Twojej witryny. Na szczęście nie trzeba generować adresu URL ręcznie, bo istnieją odpowiednie metody. Spójrzmy na przykład:

authSubUrl = AuthSubUtil.getRequestUrl(target, scope, secure, session);
  • target to ciąg znaków zawierający adres URL Twojej aplikacji internetowej. Na ten adres zostanie przekierowany użytkownik po uwierzytelnieniu.
  • zakres Ten ciąg zależy od używanego interfejsu API. Odpowiada to jednemu z plików danych w interfejsie GData API. Na przykład kanał zawierający wszystkie informacje z kalendarza użytkownika to „http://www.google.com/calendar/feeds/default/private/full”.
  • bezpieczny to wartość logiczna, która informuje serwer zarejestrowany w Google, a także szyfruje Twoje żądania na serwerze. Ten argument jest zwykle domyślnie fałszywy, zwłaszcza podczas pracy w środowisku testowym.
  • session To kolejna wartość logiczna, która wskazuje, że wolisz „tokena sesji”, a nie „jednorazowego tokena”. Rola tego argumentu stanie się za chwilę bardziej zrozumiała.

Gdy użytkownik kliknie wygenerowany adres URL, zostanie przeniesiony na stronę kont Google, na której będzie mógł się zalogować. Następnie zostaną przekierowani z powrotem na stronę internetową podaną w zmiennej „target”, ale z parametrem zapytania „token”, który zawiera token jednorazowy. Standardowo tego tokena można użyć dokładnie raz. Oznacza to, że można go użyć do wykonania jednego działania na danym kanale. Jeśli jednak ustawisz parametr „session” na wartość true, możesz wymienić go na „token sesji”, którego użytkownik może używać ponownie do momentu zakończenia sesji. Możesz to zrobić w ten sposób:

String token = Request.QueryString["token"];
Session["token"] = AuthSubUtil.exchangeForSessionToken(token, null).ToString();

W tym miejscu możesz wyodrębnić token z parametru zapytania i wymienić go na „token sesji”. Następnie możesz zapisać go w automatycznej tablicy Session w domenie .NET. Oczywiście możesz też przechowywać token w bazie danych. Następnym krokiem jest użycie tego tokena do wykonania uwierzytelnionego żądania:

GAuthSubRequestFactory authFactory = new GAuthSubRequestFactory("cl", "My-Cool-Application");
authFactory.Token = (String) Session["token"];
CalendarService service = new CalendarService(authFactory.ApplicationName);
service.RequestFactory = authFactory;

W tym miejscu konfigurujesz obiekt CalendarService do interakcji z interfejsem Google Calendar API za pomocą uwierzytelniania AuthSub. Pamiętaj, że „cl” w konstruktorze GAuthSubRequestFactory to nazwa usługi Kalendarz. Informacje o innych nazwach usług znajdziesz w najczęstszych pytaniach o interfejsy Google Data API.

Bezpieczny (zarejestrowany) mechanizm AuthSub

Jeśli zdecydujesz się zarejestrować aplikację internetową, możesz włączyć dodatkowy poziom zabezpieczeń podczas korzystania z AuthSub. Umożliwia to cyfrowe podpisywanie wszystkich żądań złożonych przez Twój kod, dzięki czemu nikt nie może korzystać z przypisanych Ci tokenów AuthSub, dopóki nie będzie mieć Twojego klucza prywatnego. Najpierw upewnij się, że generujesz prawidłowy link AuthSub podczas wywoływania AuthSubUtil.getRequestUrl. W tym celu ustaw argument „secure” na true. Musisz wprowadzić jeszcze 2 zmiany w kodzie:

String token = Request.QueryString["token"];
Session["token"] = AuthSubUtil.exchangeForSessionToken(token, rsaKey).ToString();

...

authFactory.PrivateKey = rsaKey;

Najpierw uwaga: zamiast null przekazujesz zmienną „rsaKey” do metody exchangeForSessionToken. Ta sama zmienna służy też do ustawiania właściwości obiektu GAuthSubRequestFactory podczas konfigurowania połączenia z usługą. Zmienna „rsaKey” to RSACryptoServiceProvider odpowiadający komponentowi klucza prywatnego certyfikatu x509, który został zarejestrowany w Google.

Generowanie klucza prywatnego RSA i samodzielnie podpisanego certyfikatu może być niejasne, zwłaszcza dla domen .NET, które nie rozumieją kluczy ani certyfikatów przechowywanych w formacie PEM. Poniższe polecenia pokazują, jak wygenerować klucz prywatny i certyfikat publiczny przy użyciu pakietu narzędzi OpenSSL:

openssl req -x509 -nodes -days 365 -newkey rsa:1024 -sha1 -subj \
  '/C=US/ST=CA/L=Mountain View/CN=www.example.com' -keyout \
  test_key.pem -out test_cert.pem

openssl pkcs12 -export -in test_cert.pem -inkey test_key.pem \
  -out test_cert.pfx -name "Testing Certificate"

Pierwszy etap generuje klucz prywatny i publiczny certyfikat X509 odpowiednio w formacie PEM: „test_key.pem” i „test_cert.pem”. Pamiętaj, że certyfikat jest ustawiony na „www.example.com” w Mountain View w Kalifornii, USA. Zastąp odpowiednie wartości swojej firmy. Plik „test_cert.pem” zawiera informacje, które musisz przesłać na stronie rejestracji AuthSub.

Drugi etap generuje plik PFX z klucza prywatnego i certyfikatu. Plik ten można zaimportować do biblioteki klienta .NET, aby podpisywać cyfrowe żądania wysyłane do interfejsów API GData. Ten kod pokazuje, jak zaimportować klucz prywatny z pliku PFX do aplikacji internetowej:

protected AsymmetricAlgorithm getRsaKey()
{

  X509Certificate2 cert = new X509Certificate2("C:/MyAspSite/test_cert.pfx","");
  RSACryptoServiceProvider privateKey = cert.PrivateKey as RSACryptoServiceProvider;

  return privateKey;
}

Funkcje getRsaKey() zdefiniowanej w tym fragmencie kodu można używać zamiast zmiennej „rsaKey” widocznej powyżej, gdy służy do uwierzytelniania w interfejsach API. Ścieżka pliku powinna zostać zastąpiona odpowiednią lokalizacją wygenerowanego pliku PFX.

Pełna lista kodów

Najprostszym sposobem, aby pokazać, jak korzystać z metod wykazanych w poprzedniej sekcji, jest rzeczywisty przykład. Poniższy przykładowy kod to prosta strona ASP używająca do uwierzytelniania użytkownika przy użyciu AuthSub, a następnie drukująca wydarzenia z Kalendarza Google.

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<%@ Import Namespace="Google.GData.Client" %>
<%@ Import Namespace="Google.GData.Extensions" %>
<%@ Import Namespace="Google.GData.Calendar" %>
<%@ Import Namespace="System.Net" %>

<script runat="server">
    void PrintCalendar() {

        GAuthSubRequestFactory authFactory = new GAuthSubRequestFactory("cl", "TesterApp");
        authFactory.Token = (String) Session["token"];
        CalendarService service = new CalendarService(authFactory.ApplicationName);
        service.RequestFactory = authFactory;

        EventQuery query = new EventQuery();

        query.Uri = new Uri("http://www.google.com/calendar/feeds/default/private/full");

        try
        {
            EventFeed calFeed = service.Query(query);
            foreach (Google.GData.Calendar.EventEntry entry in calFeed.Entries)
            {
                Response.Write("Event: " + entry.Title.Text + "<br/>");
            }
        }
        catch (GDataRequestException gdre)
        {
            HttpWebResponse response = (HttpWebResponse)gdre.Response;
            
            //bad auth token, clear session and refresh the page
            if (response.StatusCode == HttpStatusCode.Unauthorized)
            {
                Session.Clear();
                Response.Redirect(Request.Url.AbsolutePath, true);
            }
            else
            {
                Response.Write("Error processing request: " + gdre.ToString());
            }
        }
    }

</script>


<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Test Site</title>
</head>
<body>

    <form id="form1" runat="server">
    <h1>AuthSub Sample Page</h1>
    <div>
    <%
        GotoAuthSubLink.Visible = false;
        
        if (Session["token"] != null)
        {
            PrintCalendar();
        }
        else if (Request.QueryString["token"] != null)
        {
            String token = Request.QueryString["token"];
            Session["token"] = AuthSubUtil.exchangeForSessionToken(token, null).ToString();
            Response.Redirect(Request.Url.AbsolutePath, true);
        }
        else //no auth data, print link
        {
            GotoAuthSubLink.Text = "Login to your Google Account";
            GotoAuthSubLink.Visible = true;
            GotoAuthSubLink.NavigateUrl = AuthSubUtil.getRequestUrl(Request.Url.ToString(),
                "http://www.google.com/calendar/feeds/",false,true);
        }
        
     %>
    <asp:HyperLink ID="GotoAuthSubLink" runat="server"/>

    </div>
    </form>
</body>
</html>

Podsumowanie

AuthSub umożliwia Twojej aplikacji internetowej dostęp do danych przechowywanych na koncie Google użytkownika w bezpieczny i kontrolowany sposób. Korzystanie z biblioteki klienta .NET ułatwia integrację witryny opartej na ASP z usługami Google. Ten artykuł jest przeznaczony na początek, ale możesz skorzystać z dodatkowych zasobów: