יום שבת, 15 בינואר 2011

Picasa Api With C#



לאחר המאמר שלי בנושא התממשקות ל Facebook החלטתי לעשות מאמר נוסף על התממשקות ל Picasa - תוכנת האחסון תמונות ב Google, אז גם פה הנושא הוא מורכב ואפילו יותר מורכב מ Facebook (אם חשבתם ש Facebook מסובך תראו מה Google עשו לנו).

קצת רקע:
הרעיון של ה Api  הוא לאפשר לאפליקציות צד שלישי לעבוד מול התכנים והחשבונות של המשתמשים ובעצם לקבל תשתית מלאה לביצוע שאילתות על התוכנות של Google.

גוגל מאוד רחבה מבחינת התשתיות שהיא נותנת עבור חברות צד שלישי כמעט כל המוצרים של גוגל מכילים רכיבי Api עבור התממשקות חיצונית ואם סתם בא לי לבנות עכשיו מערכת לניהול תמונות אני יכול לעשות זאת בעזרת ה Api של Picasa בנקודת הנחה שהיא מיועדת למשתמשים עם חשבון ב Picasa וכך אני יכול לעשות לשאר האפליקציות של Google כמו Google Maps , Google Earth , Gmail ועוד.

יופי שזה אפשרי אבל מה בנוגע לפרטיות של החשבונות שלי?

מרבית ה Apis בדומה ל Faceook / Google מכילים מספר כלי אימות והצפנה על מנת לשמור על מידע של המשתמשים, גוגל מאפשרת זאת במספר דרכים שעליהם אני אפרט בהמשך, כרגיל גם המאמר הזה מחולק לחלקים, יצירת חשבון ב Google והוספת Domain ב Webmaster tool, תהליך ה Authentication, ביצוע שאילתה וקבלת נתונים.

הגדרות ב Google
תחילה יש ליצור חשבון ב Google (אני לא מאמין שלמשהו אין אבל בכל מקרה זה חובה), לאחר מכן יש להצהיר על הדומיין שלנו בגוגל דרך הלינק https://www.google.com/accounts/ManageDomains , יש לרשום את הדומיין שלנו על מנת ש Google היפתח לנו את הגישה ל Api




ניתן לבחור דרכים שונות לאימות אני בחרתי Add a meta tag to your site's home page , זאת שורת Metadata שנשתול בעמוד הראשי של ה Domain שלנו.


 
לאחר שהוא יגש אליו ויאמת אותו הוא יכריז שהוא Active וייצר לנו מספר מפתחות בדומה ל Facebook


  • Target Url Path Prefix - הכתובת המלאה של הדף שהולך להתחבר ל Picasa ב domain שלנו לדוגמה: http//www.mysite.com/picasa.aspx
  •  Domain Description - ניתן לתת תיאור אבל הוא לא חובה.
  • Upload New X509 - ניתן לתת Certificate שעליו נדבר בהמשך אבל גם הוא לא חובה.


כלים נחוצים:

Google Data Protocol - המחלקות שאיתם נתממשק דרך הקוד שלנו באתר, התמיכה מרובה וניתן למצוא מחלקות להמון שפות כמו Java , Javascript , PHP,Python,.Net , להורדה: Client Libraries

OpenSSL - כלי ליצירת Certificates חינמי, להורדה: OpenSSL - Windows

סקירה על המחלקות שבהם נשתמש:
  • Google.GData.Client.dll
  • Google.GData.Extensions.dll
  •  Google.GData.Photos.dll

מחלקות ה Client  וה Extensions קבועות עבור כל סוגי ה Apis ש Google מאפשרת לנו להתממשק אליהם עבור כל Api יש קובץ התממשקות משלו, במקרה של אנחנו משתמשים ב Photos אם ההיתי מעוניין להשתמש בשירות אחר עליי לצרף את המחלקה שמייצגת אותו לפרוייקט.

Authentication

תהליך האימות של האפליקציה שלנו גמיש , עבור תוכנות מבוססות Web ותוכנות מבוססות Desktop גם רמת האבטחה ניתנת לשינוי בחלק זה נעבור כיצד ניתן לאמת את החשבונות של המשתמשים.

קיימים 2 ערוצי התממשקות:

1.Client Authentication

הכנסת שם משתמש וסיסמא לחשבון של Google , הדרך הזאת נפוצה באפליקציות Desktop שמעוניינות להתממשק ל Picasa אבל מאוד לא מומלצת לאתרים שמעונינים להתממשק ל Picasa כי המשתמש צריך להכניס את פרטי ההתחברות שלו בתוך האתר שלנו, סביר להניח שהוא לא יעשה את זה מטעמי אבטחת מידע.


2. Web Application Client Authentication

הדרך הטובה ביותר להתממשקות של אתרים צד שלישי למערכות ה Api ללא צורך להתממשקות דרך האתר אלא בעזרת Token של ה Session של המשתמש, כלומר המשתמש צריך להיות מחובר לחשבון שלו ב Google , והמערכת שלנו לוקחת את ה Session שלו מ Google.

אם אנחנו לא נשתמש ב Certificate נראה את ההודעה הבאה:
נראה סימן קריאה צהוב שאומר רק אם המשתמש סומך על האתר שיאשר את הכניסה כלומר Google לא מכיר את ה Domain שלנו כאתר אמין, אלא אם כן נצור Certificate ונעלה אותו ל Google ב Manage Domain שהראיתי מקודם אבל אל דאגה נעבור גם על זה.
עכשיו נעבור על הקוד שלנו על מנת להבין את התממשקות, תחילה ניצור לנו אתר אינטרנט חדש ב Visual Studio, ונצרף אליו את המחלקות מה Sdk של Google , נלך לפונקציה Page_Load.

הבדיקה הראשונה שלנו בודקת אם אין לנו Token שגוגל הפיק לנו עבור המשתמש, אם אין Token נעשה את הקוד הבא:


 if (Request["token"] == null)
{
  Session["tokan"] = null;
  string d = AuthSubUtil.getRequestUrl("http://mywebsite.com/picasa.aspx", 
  "http://picasaweb.google.com/data/", false, true);
   Response.Redirect(d);
}
עכשיו נעבור לנו על הקוד, יש לנו אובייקט שנקרא AuthSubUtil שהוא הכלי שמנהל לנו את התממשקות , GetRequest זאת הפונקציה ששולחת את המשתמש מהאתר שלנו לאתר של Google על מנת שיאשר את התתחברות ל Domain שלנו, הפונקציה מקבלת קבוצה של פרמטרים שעליהם אני אפרט:

1.Url - הכתובת הראשונה שאנו רואים http://mywebsite.com/picasa.aspx זאת הכתובת שהמשתמש יחזור אליה מ Google לאחר שיאשר את ההתממשקות.

2.Url Api - זאת הכתובת שמייצגת את הכתובת של ה Api של Google לשם המשתמש יעבור לאחר שהפונקציה הזאת תופעל - לכל מוצר יש את כתובת ה Api שלו.

3.Bool Secure - מייצג אם יש Certificate עבור ה Domain שלנו.

4.Bool Session - אם לקבל מפתח חד פעמי שניתן לבצע איתו פעולה בודדת או לקבל מפתח של ה Session עצמו שניתן לבצע בעזרתו פעולות רבות.

לאחר מכן נבצע Redirect עלמנת לתפוס את ה Token שחזר לנו.


 Google Certificate

יצירת Certificate מתבצעת בעזרת הכלי OpenSSL (להורדה גש לשלב "כלים נחוצים"), פורמט התעודה שלנו הוא X.509 , נצטרך לעשות Private Key ואת ה Certificate Key של התעודה, נעשה זאת בעזרת הפקודה הבאה:

C:\OpenSSL-Win32\bin>openssl req -x509 -nodes -days 365 -newkey rsa:1024 -sha1 -subj
"/C=US/ST=CA/L=Mountain View/CN=www.mysite.com" -keyout
test_key.pem -out test_cert.pem 

השורה האדומה מסמנת לנו את פרטי החברה שעליה רשום ה Certificate שלנו:
C-Country
ST- State
L-Location
CN - Company name

לאחר פקודה זו נוצרו לנו 2 קבצי Pem שאת קובץ test_cert.pem נעלה ל Google, ב Manage Domains שראינו בהתחלה.

השלב הבא הוא יצירת קובץ Pfx שנוכל לעבוד בו עם האפליקציה שלנו ב .Net שמכיל את המפתח הפרטי שלנו, נריץ את הפקודה הבאה:

C:\OpenSSL-Win32\bin>openssl pkcs12 -export -in test_cert.pem -inkey test_key.pem
-out test_cert.pfx -name "MyCertificate"

עכשיו נחזור לקוד של ההתממשקות:

string d = AuthSubUtil.getRequestUrl("http://mywebsite.com/picasa.aspx", "http://picasaweb.google.com/data/", true, true);

ונסמן את ה bool Secure כ True, נעלה את קובץ ה Pfx לאתר שלנו.

נוסיף לנו פונקציה נוספת בקוד שלנו שבה נשתמש בהמשך:

private AsymmetricAlgorithm getRsaKey()
{
  X509Certificate2 cert = new X509Certificate2(Server.MapPath("~/test_cert.pfx"),"certificatepassword");
  RSACryptoServiceProvider privateKey = cert.PrivateKey as RSACryptoServiceProvider;
  return privateKey;
}

הפונקציה תקרא מקובץ ה Pfx את המפתח הפרטי שלנו ו Google תאמת אותו מול קובץ ה Pem שהעלנו עבור ה Domain ב Google.

עכשיו נחזור לנו להמשך התהליך, נניח שקיבלנו את ה Token שלנו מ Google עכשיו נעשה בדיקה אם יש לנו Token נריץ את הקוד הבא:

 if (Request["token"] != null)

{
  string token = Request.QueryString["token"];
  Session["token"] = AuthSubUtil.exchangeForSessionToken(token, null).ToString();
  Response.Redirect(Request.Url.AbsolutePath, true);
}

 מה שאנחנו בעצם עושים הוא לקחת את ה Token מה Request ונבקש מ Google בעזרת הכלי AuthSubUtil שיחזיר לנו Token של ה Session , הפונקציה exchangeForSessionToken מקבלת 2 ערכים הראשון הוא ה Tokan ש Google החזיר לנו בשלב ההתממשקות הראשונית, הפרמטר השני זה ההצפנה , אם אין לנו Cetificate Private Key נשלח Null , אם יש Cetificate Private Key נקרא לפונקציה שקוראת את המפתח מקובץ ה Pfx שיצרנו.

Session["token"] = AuthSubUtil.exchangeForSessionToken(token, getRsaKey()).ToString();


ב 2 המצבים צריכים לטעון את ה Token שחוזר ב Session של האתר שלנו על מנת שנוכל לבצע יותר מפעולה בודדת, ובעצם סיימנו את תהליך ההתממשקות ועכשיו נעבור לשאילתות מול ה Api.

ביצוע שאילתות מול ה Api

לאחר שסיימנו את תהליך ההתממשקות ניתן להתחיל לבצע שאילתות מול ה Api של Google, תחילה נצהיר על האובייקט:
GAuthSubRequestFactory - שהוא מכיל בתוכו את ה Tokan שבתוך ה Session של האתר שלנו , ובעצם נשלח ל Google ברגע שנבצע שאילתה, בנוסף צריך להגדיר את ה Api של התוכנה Picasa שהקוד שלה הוא "lh2" ,שוב פעם לכל Api יש את הקוד שלו (לרישמת הקודים עבור שאר האפליקציות), וכמובן נשלח לו את ה Domain שלנו כ ApplicationName.

GAuthSubRequestFactory authFactory = new GAuthSubRequestFactory("lh2", "http://www.mywebsite.com/");
authFactory.Token = Session["token"].ToString();
 
השלב הבא הוא להצהיר על ה Service עצמו, האובייקט שלנו הוא PicasaService שמקבל ApplicationName שהגדרנו באובייקט GAuthSubRequestFactory.
 
PicasaService myservice = new PicasaService(authFactory.ApplicationName);

נצהיר על סוג השאילתה שלנו (Query) , יש המון סוגים של שאילתות, בדוגמה שנראה פה נשתמש ב PhotoQuery שהיא שאילתה עבור התמונות ללא קשר לאלבום אבל ניתן לבצע שאילתה גם על אלבומים בעזרת האובייקט AlbumQuery.

 PhotoQuery query = new PhotoQuery(PicasaQuery.CreatePicasaUri("default"));

ה default מייצג את ה User במקרה של Client Authentication נשלח שם משתמש וסיסמא:
PhotoQuery query = new PhotoQuery(PicasaQuery.CreatePicasaUri(username,password));


אובייקט PicasaQuery בונה לנו את ה Url שאליו אנו פונים ב Api.

את התוצאות שחוזרות לנו בפורמט Xml נאחסן באבייקט PicasaFeed.
PicasaFeed feed = myservice(query)

מה שנשאר לנו לעשות הוא להריץ ריצה על ה Feed על מנת לחלץ משם את התמונות שחזרו לנו מה Api.
foreach (AtomEntry aentry in feed.Entries)
{
myphotos = myphotos +  aentry.Content.Src.ToString();
}
 
קוד מלא לדוגמה:
 
using Google.GData.Photos;
using Google.GData.Client;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
using System.Net;

public partial class picasa : System.Web.UI.Page
{
   public string myphotos = "";
   public string myerror = "";
   protected void Page_Load(object sender, EventArgs e)
   {
      if (Session["token"] != null)
     {
       get_images();
     }
     else if (Request["token"] != null)
     {
       string token = Request.QueryString["token"];
       Session["token"] = AuthSubUtil.exchangeForSessionToken(token, null).ToString();
       Response.Redirect(Request.Url.AbsolutePath, true);
     }
     else if (Request["token"] == null)
      {
       Session["tokan"] = null;
       string d = AuthSubUtil.getRequestUrl("http://www.mywebsite.com/picasa.aspx", 
       "https://picasaweb.google.com/data/", false, true);
       Response.Redirect(d);
      }
}

private void get_images()
{
  GAuthSubRequestFactory authFactory = new GAuthSubRequestFactory("lh2", "http://www.mywebsite.com/");
  authFactory.Token = Session["token"].ToString();
  PicasaService myservice = new PicasaService(authFactory.ApplicationName);
   picasaser.RequestFactory = authFactory ;
   try
   {
     PhotoQuery query = new PhotoQuery(PicasaQuery.CreatePicasaUri("default"));
     PicasaFeed feed = myservice.Query(query);
     foreach (AtomEntry aentry in feed.Entries)
    {
      myphotos = myphotos + aentry.Content.Src.ToString() ;
    }
   }
   catch (GDataRequestException gdre)
   {
     HttpWebResponse response = (HttpWebResponse)gdre.Response;
     //bad auth token, clear session and refresh the page
      if (response.StatusCode == HttpStatusCode.Unauthorized)
     {
      Session["tokan"] = null;
      Response.Redirect(Request.Url.AbsolutePath, true);
     }
     else
     {
       Response.Write("Error processing request: " + gdre.ToString());
     }
   }
}

private AsymmetricAlgorithm getRsaKey()
{
  X509Certificate2 cert = new X509Certificate2(Server.MapPath("~/test_cert.pfx"),"mycertificatepassword");
  RSACryptoServiceProvider privateKey = cert.PrivateKey as RSACryptoServiceProvider;
  return privateKey;
 }
}

לאתרי מידע נוספים:

בהצלחה...

אין תגובות:

הוסף רשומת תגובה