استفاده از AuthSub با کتابخانه مشتری دات نت

جف فیشر، تیم Google Data APIs
آگوست 2007

مقدمه: چرا AuthSub مهم است؟

نکته مهم در مورد Google Data API (به اختصار "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" است.
  • امن این یک بولی است که به سرور می گوید که شما در Google ثبت نام کرده اید و به صورت رمزنگاری درخواست های شما را به سرور امضا می کند. این آرگومان معمولاً به‌طور پیش‌فرض نادرست است، مخصوصاً هنگام کار در یک محیط آزمایشی.
  • session این یک بولی دیگر است که نشان می دهد شما یک "نشانه جلسه" را به جای یک "یک بار مصرف" می خواهید. نقش این استدلال در یک لحظه روشن تر خواهد شد.

پس از کلیک کاربر در URL تولید شده، به صفحه حساب های Google منتقل می شود که به آنها اجازه می دهد به حساب Google خود وارد شوند. سپس آنها به صفحه وب که در متغیر "target" مشخص کرده اید، هدایت می شوند، اما با یک پارامتر پرس و جو "token" که حاوی یک نشانه یک بار مصرف است. به طور معمول، این توکن دقیقاً یک بار قابل استفاده است. یعنی می توان از آن برای انجام یک عمل در یک خوراک معین استفاده کرد. با این حال، اگر پارامتر "sesion" را درست تعیین کرده باشید، می توان آن را با یک "نشانه جلسه" تعویض کرد که می تواند تا زمانی که کاربر جلسه را پایان دهد، مجددا استفاده شود. شما می توانید این کار را به روش زیر انجام دهید:

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

در اینجا توکن را از پارامتر query استخراج می کنید و آن را با یک "نشانه جلسه" مبادله می کنید. سپس، برای اینکه بتوان آن را برای استفاده بعدی ذخیره کرد، می توانید آن را در آرایه Session خودکار دات نت ذخیره کنید. به طور طبیعی، شما همچنین می توانید رمز را در یک پایگاه داده ذخیره کنید. مرحله بعدی استفاده از این توکن برای درخواست احراز هویت است:

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 نام سرویس Calendar است. برای نام‌های دیگر سرویس‌ها، می‌توانید به پرسش‌های متداول Google Data APIs مراجعه کنید.

AuthSub امن (ثبت شده)

اگر تصمیم به ثبت برنامه وب خود دارید، می توانید سطح امنیتی بیشتری را در حین استفاده از AuthSub فعال کنید. این به شما امکان می‌دهد تمام درخواست‌های کدتان را به‌صورت دیجیتالی امضا کنید، تا کسی نتواند از نشانه‌های AuthSub صادر شده برای شما استفاده کند، مگر اینکه کلید خصوصی شما را داشته باشد. اولین گام این است که با تنظیم آرگومان "secure" روی true ، هنگام فراخوانی AuthSubUtil.getRequestUrl ، مطمئن شوید که پیوند صحیح AuthSub را ایجاد می کنید. دو تغییر کد دیگر وجود دارد که باید انجام دهید:

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

...

authFactory.PrivateKey = rsaKey;

ابتدا به جای null توجه کنید، اکنون متغیر "rsaKey" را به متد exchangeForSessionToken ارسال می کنید. از همین متغیر برای تنظیم ویژگی GAuthSubRequestFactory ما هنگام تنظیم اتصال به سرویس نیز استفاده می شود. متغیر "rsaKey" یک RSACryptoServiceProvider است که مربوط به جزء کلید خصوصی گواهی x509 است که در Google ثبت کرده اید.

ایجاد یک کلید خصوصی RSA و گواهی خودامضا می تواند کمی گیج کننده باشد، به خصوص که چارچوب دات نت کلیدها یا گواهی های ذخیره شده در قالب 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" مستقر در Mountain View، CA، ایالات متحده ثبت شود. ارزش های مناسب را برای شرکت خود در اینجا جایگزین کنید. فایل "test_cert.pem" حاوی اطلاعاتی است که باید در صفحه ثبت نام AuthSub ارسال کنید.

مرحله دوم یک فایل PFX از کلید خصوصی و گواهی شما تولید می کند. این فایل را می توان به کتابخانه سرویس گیرنده دات نت وارد کرد تا درخواست های ارائه شده به 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 کاربر به روشی ایمن و کنترل شده دسترسی داشته باشد. استفاده از کتابخانه سرویس گیرنده دات نت، ادغام وب سایت مبتنی بر ASP خود را با خدمات Google آسان می کند. این مقاله برای شروع کار شما طراحی شده است، اما منابع دیگری نیز وجود دارد که توصیه می شود با آنها مشورت کنید: