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

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

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

Отличительной особенностью API данных Google (сокращенно «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-адрес вашего веб-приложения. Сюда будет перенаправлен пользователь после аутентификации.
  • scope Эта строка определяется тем, какой API вы используете. Он соответствует одному из каналов в GData API. Например, фид, содержащий всю информацию календаря для пользователя, называется "http://www.google.com/calendar/feeds/default/private/full".
  • secure Это логическое значение, которое сообщает серверу, что вы зарегистрированы в Google , и будет криптографически подписывать ваши запросы к серверу. Этот аргумент обычно по умолчанию равен false, особенно при работе в тестовой среде.
  • session Это еще одно логическое значение, указывающее, что вам нужен «токен сеанса», а не «одноразовый токен». Роль этого аргумента станет более ясной через мгновение.

После того, как пользователь нажмет на сгенерированный URL-адрес, он попадет на страницу учетных записей Google, которая позволит им войти в свою учетную запись Google. Затем они будут перенаправлены обратно на веб-страницу, которую вы указали в переменной «target», но с параметром запроса «токен», который содержит токен одноразового использования. Обычно этот токен можно использовать ровно один раз. То есть его можно использовать для выполнения одного действия с данным каналом. Однако, если вы указали параметр "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 для взаимодействия с Google Calendar API, используя AuthSub для аутентификации. Обратите внимание, что «cl», используемый в конструкторе для GAuthSubRequestFactory , является именем службы для календаря. Другие названия служб можно найти в разделе часто задаваемых вопросов по API данных Google .

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

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

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

...

authFactory.PrivateKey = rsaKey;

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

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