استخدام AuthSub مع مكتبة عميل .NET

جيف فيشر، فريق Google Data APIs
آب (أغسطس) 2007

المقدمة: ما سبب أهمية AuthSub؟

إن الأمر الرائع حول واجهات برمجة التطبيقات (API) لبيانات Google (اختصارًا "GData") هو كيفية السماح للمطورين بإنشاء تطبيقات تتفاعل مع خدمات Google. وبشكل أكثر تحديدًا، فهي تسمح لك بالوصول إلى بيانات المستخدم الخاصة لاستخدامها في تطبيقك. تمكنك واجهات برمجة التطبيقات من كتابة التطبيقات لمزامنة هذه البيانات واستيرادها وتصديرها وإدارتها بأي صورة أخرى. وعلى الرغم من أن واجهات برمجة التطبيقات تمنحك هذه الإمكانيات القوية، يلزمك تذكر استخدامها بشكل مسؤول. نظرًا لأن بيانات المستخدم هي معلومات خاصة، فإنك تحتاج بشكل طبيعي إلى الدخول إليها بطريقة آمنة. ويتمثل جزء رئيسي من ذلك في إمكانية المصادقة على خوادم 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 يتم تحديد هذه السلسلة من خلال واجهة برمجة التطبيقات التي تستخدمها. وهذا يتطابق مع إحدى الخلاصات في واجهة برمجة تطبيقات GData. فعلى سبيل المثال، الخلاصة التي تحتوي على جميع معلومات التقويم لأحد المستخدمين هي "http://www.google.com/calendar/feeds/default/private/full".
  • Secure هذه طريقة منطقية تخبر الخادم الذي سجّلته مع Google بالتوقيع المشفّر على طلباتك إلى الخادم. وتكون هذه الوسيطة غير صحيحة بشكل تلقائي، خاصةً عند العمل في بيئة اختبار.
  • الجلسة هذه قيمة منطقية أخرى تشير إلى أنك تريد "رمز مميز للجلسة" بدلاً من "رمز مميز للاستخدام لمرة واحدة". سيصبح دور هذه الوسيطة أكثر وضوحًا في لحظة.

بعد أن ينقر المستخدم على عنوان 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 باستخدام AuthSub للمصادقة. لاحظ أن "cl" المستخدم في دالة إنشاء GAuthSubRequestFactory هو اسم الخدمة للتقويم. يمكنك الرجوع إلى الأسئلة الشائعة حول Google Data APIs للتعرُّف على أسماء الخدمات الأخرى.

AuthSub (مسجَّل) آمن

إذا اخترت تسجيل تطبيق الويب، يمكنك تمكين مستوى إضافي من الأمان أثناء استخدام AuthSub. يسمح لك ذلك بتوقيع جميع الطلبات المقدّمة من خلال رمزك رقميًا، ما يجعلها غير قادرة على استخدام رموز AuthSub المميزة إليك، إلّا إذا كان لديها مفتاحك الخاص. الخطوة الأولى هي التأكد من إنشاء رابط AuthSub الصحيح عند استدعاء AuthSubUtil.getRequestUrl عن طريق ضبط الوسيطة "آمنة" على 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 لتوقيع الطلبات التي تم إجراؤها رقميًا على واجهات برمجة تطبيقات GData. توضح الشفرة التالية كيفية استيراد المفتاح الخاص من ملف PFX إلى تطبيق ويب:

protected AsymmetricAlgorithm getRsaKey()
{

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

  return privateKey;
}

يمكن استخدام الدالة getRsaKey() التي يحدّدها هذا المقتطف بدلاً من المتغيّر "rsaKey" الموضّح أعلاه عند استخدامها للمصادقة على واجهات برمجة التطبيقات. وبطبيعة الحال، يجب استبدال مسار الملف بالموقع المناسب لملف 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. تم إعداد هذه المقالة لمساعدتك في البدء، ولكن هناك موارد إضافية ننصحك بالرجوع إليها: