Использование AuthSub с клиентской библиотекой .NET

Джефф Фишер, команда Google Data API
Август 2007 г.

Введение: Почему важен AuthSub?

Главное преимущество API Google Data (сокращенно «GData») заключается в том, что они позволяют разработчикам создавать приложения, взаимодействующие с сервисами Google. В частности, они предоставляют доступ к личным данным пользователей для использования в вашем приложении. API позволяют создавать приложения для синхронизации, импорта, экспорта и управления этими данными. Хотя API предоставляют вам эти мощные возможности, необходимо помнить о необходимости ответственного их использования. Поскольку пользовательские данные — это конфиденциальная информация, естественно, доступ к ним должен быть безопасным. Ключевым фактором является возможность безопасной аутентификации на серверах Google.

Допустим, у вас есть отличное новое веб-приложение, которое вы хотите связать с данными, хранящимися в веб-сервисах Google. Теперь вам нужна аутентификация для доступа к этим конфиденциальным данным. Почему бы не использовать что-то простое, например, ClientLogin ? Что ж, это сработает, но тогда вы будете работать с ещё более конфиденциальными данными: учётными данными пользователя. ClientLogin требует, чтобы ваше приложение запрашивало имя пользователя и пароль Google. Это приемлемо для настольного приложения, работающего на персональном компьютере пользователя, но не идеально для веб-приложения. Помимо ответственности, связанной с обработкой этих учётных данных на вашем собственном сервере, некоторые из ваших наиболее осторожных пользователей, возможно, опасаются, что вы можете хранить их информацию. Ещё один распространённый вопрос для пользователей — предоставить программе доступ только к одной конкретной службе (например, к событиям в своём Google Календаре), но не к какой-либо другой (например, к Google Документам). AuthSub решает обе эти проблемы, позволяя пользователю проходить аутентификацию через серверы Google, а вашей программе — запрашивать только необходимый ей доступ.

Теперь, когда вы достаточно ознакомились с теорией AuthSub, пора переходить к кодированию! В этой статье я решил упростить всё и реализовать на одной ASP-странице, но вы без труда сможете интегрировать продемонстрированные здесь методы в своё собственное приложение.

Обработка аутентификации

Итак, что же необходимо для использования AuthSub в вашем веб-приложении? Во-первых, есть несколько стандартных импортов из клиентской библиотеки GData:

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

Первое, что вам нужно сделать, — это перенаправить пользователя на специально созданный URL. Это позволит серверам Google выполнить аутентификацию и перенаправить пользователя обратно на ваш сайт. К счастью, вам не нужно генерировать этот URL вручную, так как существуют методы, позволяющие сделать это автоматически. Рассмотрим пример:

authSubUrl = AuthSubUtil.getRequestUrl(target, scope, secure, session);
  • target — это строка, содержащая URL-адрес вашего веб-приложения. Сюда будет перенаправлен пользователь после аутентификации.
  • Область действия этой строки определяется используемым API. Она соответствует одному из каналов API GData. Например, канал, содержащий всю информацию из календаря пользователя, — это «http://www.google.com/calendar/feeds/default/private/full».
  • Это логическое значение, сообщающее серверу, что вы зарегистрированы в Google и что ваши запросы к серверу будут криптографически подписаны. Этот аргумент обычно имеет значение false по умолчанию, особенно при работе в тестовой среде.
  • session. Это ещё один логический аргумент, указывающий, что вам нужен «токен сеанса», а не «токен одноразового использования». Роль этого аргумента станет более ясна чуть позже.

После того, как пользователь нажмёт на сгенерированный URL, он будет перенаправлен на страницу учётных записей Google, где он сможет войти в свою учётную запись Google. Затем он будет перенаправлен обратно на веб-страницу, указанную в переменной «target», но с параметром запроса «token», содержащим одноразовый токен. Обычно этот токен можно использовать только один раз. То есть, его можно использовать для выполнения одного действия в заданном фиде. Однако, если вы указали параметр «session» как true , его можно обменять на «токен сеанса», который можно использовать повторно до тех пор, пока пользователь не завершит сеанс. Это можно сделать следующим образом:

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

Здесь вы извлекаете токен из параметра запроса и обмениваете его на «токен сеанса». Затем, чтобы сохранить его для дальнейшего использования, вы можете сохранить его в автоматическом массиве Session .NET. Конечно, вы также можете сохранить токен в базе данных. Следующий шаг — использовать этот токен для выполнения аутентифицированного запроса:

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

Здесь вы настраиваете объект CalendarService для взаимодействия с API Google Calendar, используя AuthSub для аутентификации. Обратите внимание, что «cl», используемый в конструкторе GAuthSubRequestFactory , — это имя сервиса Calendar. Другие имена сервисов можно найти в разделе часто задаваемых вопросов по API Google Data .

Безопасный (зарегистрированный) AuthSub

Если вы решите зарегистрировать своё веб-приложение , вы сможете повысить уровень безопасности при использовании AuthSub. Это позволит вам подписывать все запросы, выполняемые вашим кодом, что исключит возможность использования выданных вам токенов AuthSub без вашего закрытого ключа. Первым шагом является обеспечение корректной ссылки AuthSub при вызове AuthSubUtil.getRequestUrl путем установки аргумента «secure» в значение true . Необходимо внести ещё два изменения в код:

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

...

authFactory.PrivateKey = rsaKey;

Во-первых, обратите внимание, что вместо null вы теперь передаёте методу exchangeForSessionToken переменную "rsaKey". Эта же переменная используется для установки свойства нашего GAuthSubRequestFactory при настройке подключения к сервису. Переменная "rsaKey" — это RSACryptoServiceProvider соответствующий компоненту закрытого ключа сертификата x509, зарегистрированного в Google.

Генерация закрытого ключа RSA и самоподписанного сертификата может быть немного запутанной, особенно учитывая, что .NET Framework не распознаёт ключи и сертификаты, хранящиеся в формате PEM. Следующие команды показывают, как сгенерировать закрытый ключ и открытый сертификат с помощью набора инструментов 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"

На первом этапе генерируются закрытый ключ и открытый сертификат X509 в формате PEM с именами "test_key.pem" и "test_cert.pem" соответственно. Обратите внимание, что сертификат зарегистрирован на сайте "www.example.com" в Маунтин-Вью, штат Калифорния, США. Подставьте сюда значения, соответствующие вашей компании. Файл "test_cert.pem" содержит информацию, которую необходимо предоставить на странице регистрации AuthSub .

На втором этапе генерируется PFX-файл из вашего закрытого ключа и сертификата. Этот файл можно импортировать в клиентскую библиотеку .NET для цифровой подписи запросов к API GData. Следующий код показывает, как импортировать закрытый ключ из PFX-файла в веб-приложение:

protected AsymmetricAlgorithm getRsaKey()
{

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

  return privateKey;
}

Функция getRsaKey() определённая в этом фрагменте кода, может использоваться вместо переменной rsaKey, показанной выше, при аутентификации в API. Естественно, путь к файлу следует заменить на соответствующее расположение сгенерированного вами PFX-файла.

Полный листинг кода

Проще всего продемонстрировать использование методов, показанных в предыдущем разделе, на живом примере. Следующий пример кода представляет собой простую ASP-страницу, которая использует AuthSub для аутентификации пользователя, а затем выводит события из его 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>

Заключение

AuthSub позволяет вашему веб-приложению безопасно и контролируемо получать доступ к данным, хранящимся в учётной записи Google пользователя. Использование клиентской библиотеки .NET упрощает интеграцию вашего ASP-сайта со службами Google. Эта статья предназначена для начала работы, но мы рекомендуем вам ознакомиться с дополнительными ресурсами: