שימוש ב-AuthSub עם ספריית הלקוח .NET

ג'ף פישר, צוות Google Data APIs
אוגוסט 2007

מבוא: למה AuthSub חשוב?

היתרון הנהדר של Google Data APIs (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 זוהי מחרוזת המכילה את כתובת האתר של אפליקציית האינטרנט שלך. זה הדף שאליו המשתמש יופנה לאחר האימות.
  • scope המחרוזת הזו נקבעת על סמך ה-API שבו אתם משתמשים. הוא תואם לאחד מהפידים ב-GData API. לדוגמה, העדכון שמכיל את כל פרטי היומן של משתמש הוא "http://www.google.com/calendar/feeds/default/private/full".
  • secure זהו בוליאני שמיידע את השרת שרשמתם ב-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;

כאן מגדירים אובייקט מסוג יומן שירות לביצוע אינטראקציה עם ה-API של יומן Google באמצעות 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 ב-Mountain View, קליפורניה בארה"ב. יש להחליף את הערכים המתאימים לחברה שלכם כאן. הקובץ "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. המאמר הזה נועד לעזור לכם להתחיל, אבל יש מקורות מידע נוספים שמומלץ להתייעץ איתם: