مساحة اعلانية

آخر المواضيع

الوصول إلى خدمات google باستخدام بروتوكول OAuth 2.0

في هذا المقال التعليمي سنقوم بدراسة إنشاء خدمات Google باستخدام بروتوكول OAuth 2.0.

نظرة عامة على بروتوكول OAuth 2.0
بروتوكول OAuth 2.0 يمثل معيار بسيط وآمن والذي يسمح  للتطبيقات بالوصول إلى مقدمي الخدمات الأساسية مثل like Facebook, G+، و Twitter بدون طلب كلمات مرور للمستخدمين. الفكرة برمتها تدور حول وجود رمز الوصول، شيء كالمفتاح الوحيد Unique key والذي يستطيع التعريف بالمستخدم بدلاً من كلمة المرور.
يتم الحصول على رموز الوصول عن طريق تطبيقات الطرف الثالث third-party applications بعد أن يقوم المستخدم بالمصادقة مع خدمة ويب. العملية كلها تعرف بتسلسل المصادقة، وتبدأ عندما يقوم المستخدم بإدخال بياناته المعتمدة في شاشة دخول المستخدم وتنتهي باكتساب رمز الوصول. بالعادة يتم تحديث رمز الوصول من وقت لآخر. مع وجود رمز الوصول هذا لا حاجة لإرسال أي بينات شخصية أو كلمة مرور يحتاجها تطبيق المستخدم.
إذا لم تكن لديك المعرفة الكافية ببروتوكول OAuth 2.0 عليك أن تقرأ المزيد عنه قبل إكمال هذه المقالة التعليمية ، تحديداً يمكنك القراءة من الروابط التالية لتتكون لديك الخلفية المطلوبة عن الموضوع:
بالعموم، تسلسل التحقق عبر بروتوكول OAuth 2.0 يسير كالآتي:
1- يجعل المستخدم يتصل بحسابه
2- الحصول على كود التحقق. ( مثل رمز الوصول)
3- تبادل كود التحقق لرمز الوصول وعمل تحديث لرمز الوصول
4- استخدام رمز الوصول للتفاعل مع خدمة ويب أو أي تطبيق
5- استخدام رمز التحديث لتحديث رمز الوصول عند الحاجة
Google وبروتوكول OAuth 2.0 تعتبر جوجل واحدة من مقدمي تطبيقات الطرف الثالث والتي اعتمد بروتوكول OAuth 2.0. فهي تقدم العديد من التطبيقات للوصول إلى معظم خدماتها( مثل الأجندة، المدونة وغيرها) من خلال تطبيقات العميل وتقدم توجيهات عن كيفية بناء تسلسل عملية التحقق بواسطة لغات برمجة مختلفة. كل تطبيق يحتاج إلى استخدام أي خدمة من خدمات Google يجب أولاً أن يقوم بالتسجيل مع وحدة تحكم تطوير Google، وهي لوحة إدارة تطبيقات العميل المطورة بواسطة المستخدم. عند تسجيل أي تطبيق في لوحة التحكم، يتم إنشاء id و client secret خاصة بهذا التطبيق. هذه القيم، بالإضافة لقيم أخرى، يتم استخدامها بواسطة بروتوكول OAuth للتحقق من تطبيق والحصول على رمز الوصول. بعد تسجيل التطبيق، هناك عدد من الخدمات المتاحة التي يمكن إدراجها في المشاريع. هذه الخدمات يتم الوصول إليها من خلال الواجهات المقدمة لكل خدمة. بعض هذه الخدمات مجانية بينما الأخرى تحتاج لأن تقوم بالدفع ليسمح لك Google باستخدامها لفترة تجريبية.
من هنا ولاحقاً سأفترض أنك على دراية جيدة بمبادئ بروتوكول OAuth 2.0، والآن هو الوقت لزيارة هذا الرابط Using OAuth 2.0 for Installed Applications وهو يحتوي على توثيق من Google. هذا التوثيق يعرض تسلسل التحقق المدعوم بواسطة Google لتطبيقات العميل المبنية للجوال أو تطبيقات سطح المكتب وهذا التوثيق المشار إليه في الرابط سيكون مرشد لنا في مشروع هذا المقال التعليمي. وأود أن أوصيك أيضا بتصفح المزيد حول خيارات القوائم على أعلى يسار النافذة والروابط بداخل النص لضمان فهم أعمق لخدمات Google وطريقة عمل بروتوكول OAuth 2.0.


نظرة عامة على المشروع
هذا المشروع سيعلمك كيفية إنشاء class يحتوي على بناء بروتوكول OAuth 2.0 على جانب العميل لاستخدام واجهات Google وخدماته. هذا ال class سيكون جزء من تطبيق تجريبي بسيط. وواجهة المستخدم GUI ستكون فعلاً بسيطة، ولأننا نحتاج لعمل فحص لل class، سنقضي معظم الوقت فعلياً في كتابة الكود. ولعمل فحص لبناء بروتوكول OAuth، سنقوم بطلب معلومات ملف المستخدم user profile information من Google والتي سيتم عرضها في تطبيقنا. كذلك لجعل عملنا مكتملاً بقدر الإمكان سنقوم بإضافة المزيد من الفحوصات ورسائل توضيح الخطأ. بعد الانتهاء من هذا ال class يمكن استخدامه في مشاريع حقيقية للوصل لخدمات Google. وبالطبع يمكن لأي شخص أن يقوم بعمل بعض التعديلات أو التحسينات عليه في أي وقت.
قبل أن نبدأ بكتابة سطر واحد من الكود، نحتاج لتسجيل التطبيق التجريبي في وحدة لوحة تحكم التطبيقات. لعمل ذلك نحتاج اسم التطبيق والذي قمت باختياره GoogleOAuthDemo. إذا كنت تفضل أي اسم آخر، كن متأكداً من استخدامه بدلاً من الاسم الذي أستخدمه أنا في الخطوات المتبعة.
هذه هي صورة التطبيق النهائي:



1- تسجيل تطبيق ال IOS

الخطوة الأولى
الخطوة الأولى هي تسجيل تطبيق ال IOS في وحدة تحكم تطبيقات Google لأننا نحتاج الحصول على a Client ID و Client Secret value. لذلك في نافذة متصفح جديدة، قم بزيارة موقع Google Developers . في أعلى يمين النافذة، يوجد زر Sign In. قم بالضغط عليه والنافذة التالية ستظهر.


إذا كنت تملك حساب في أي من خدمات Google مثل(gmail، google+، Drive، وغيرها) عندها تستطيع الدخول من خلال معلومات الدخول خاصتك، أما إذا كنت لا تملك حساب أو تريد إنشاء حساب جديد، الآن هو الوقت لعمل ذلك. ببساطة قم بالنقر على زر Sign Up.

في حالة أنك تقوم بعمل حساب جديد، قم بإدخال كل المعلومات المطلوبة، قم بإنشائه، وادخل إلى موقع مطوري Google.

الخطوة الثانية

بمجرد أنك اتصلت بموقع مطوري Google من خلال حسابك، من الممكن أن تصبح مهتماً بكل العاملين الذين تحتويهم هذه الصفحة، ولذلك قم بإلقاء نظرة إن أردت. بالتأكيد ستجد بعض المواضيع الممتعة التي تهمك. قم بالتوجه إلى نهاية الصفحة إلى أن تصل منطقة أدوات المطور، وقم بالنقر على رابط API Console.
الخطوة الثالثة
عندما تقوم بإنشاء تطبيق في وحدة تحكم المطورين، المعلومات الخاصة به يتم تجميعها مع بعضها ويتم تسميتها project. من خلالها يمكنك إدارة كل الواجهات، المستخدمين، التحقق والمزيد من العاملين في تطبيقاتك. أود نصيحتك بأن تلقي نظرة وتأخذ فكرة عن جزئية ال Help في أعلى يسار الصفحة إذا أردت أن تجد معلومات مفصلة عن لوحة التحكم.
دعنا نعود للوراء. عندما نظرت أول مرة على هذه الصفحة، لاحظت وجود  قائمة ساقطة في أعلى يسار الصفحة اسمها API Project. إذا قمت بفتحها ستجد خيارات أخرى إضافية بواسطتهم تستطيع مشاريع جديدة، إعادة تسميتهم أو حذفهم والمزيد من الخيارات. الآن نحن لن نحتاجها لذلك قم بإغلاقها إذا قمت بفتحها مسبقاً، أسفل القائمة السابقة يوجد أربع خيارات:
1- Overview 
2- Services
3- Team
4- API Access


إذا قمت بالضغط على خيار   Services، سوف ترى كل الخدمات التي يعرضها Google. بجانب كل خدمة هناك بعض الملاحظات تنوه من هذه الخدمات تحتاج إلى دفع. لاستخدام أي منها في تطبيق، أولاً يجب أن تقوم بتسجيل تطبيقك، ثم قم ببناء بروتوكول OAuth وأخيراً نسأل عن ال APIs المناسبة.
قم بالنقر على خيار API. في هذا المكان سنقوم بتسجيل التطبيق خاصتنا. قم بالنقر على الزر الأزرق بعوان "Create an OAuth 2.0 client ID...".

                                                                                                                                                      
في النافذة التي ستظهر، أضف Product Name  وهو كالتالي Google OAuth 2.0 iOS Implementation Demo value ثم اضغط next




في الخطة التالية، أكمل باقي الحقول كما يلي:         :
  • Application Type: Installed application
  • Installed Application Type: iOS
  • Bundle ID: com.yourdomain.googleoauthdemo (for example, com.gabrieltheodoropoulos.googleoauthdemo)

اضغط زر Create client ID الآن. وكما ترى في الصورة التالية بإمكانك بسهولة ان تجد client ID و secret values.


بإمكانك أن ترى أنك تستطيع تعديل كل المعلومات التي قمنا بإدخالها للتو باستخدام الروابط الموجودة والأزرار في الصفحة. البيانات التي سنستخدمها في التطبيق التجريبي هي         
  • client ID
  • client secret
  • Redirect URI
الآن انتهينا من تحقيق أول خطوة من هدفنا. تم تسجيل التطبيق في وحدة تحكم مطوري Google ونمتلك كل المعلومات الضرورية التي نحتاجها. ومع ذلك فالجزء الصعب هو القادم، حيث سنبني فعلياً كود بروتوكول  OAuth 2.0.
2- إنشاء المشروع التجريبي
إنه الوقت لبناء تطبيقنا. افتح Xcode وقم بإنشاء مشروع جديد. في الخطوة الأولى اختر خيار Single View Application 
ثم قم بتحديد الاسم GoogleOAuthDemo في حقل Product Name  من شاشة خيارات المشروع.

 في النهاية قم باختيار المكان الذي ستقوم بتخزين المشروع فيه على جهازك واضغط زر create



1-  
إنشاء الواجهة

الخطوة الأولى

قم بالضغط على ملف ViewController.xib  لفتح Interface Builder. اسحب وأسقط ال subviews التالية في ال view الرئيسي:
· A Table View
·A Toolbar.

وأيضاً، بالإضافة إلى زر الشريط الأساسي الموجود في شريط الأدوات قم بإضافة التالي:
Flexible Space Bar Button Item  وBar Button Item
تأكد من أن الزر الواحد على يسار شريط الأدوات، بينما الزر الآخر على الجهة اليمني منه والمسافة المرنة يجب أن تكون بينهم.

الخطوة الثانية

الآن لنقم بعمل اثنين من الإجراءات
· اختر View  وعدل على متغير Size  ليكون None وبالتالي يعمل التطبيق أيضاً على شاشات iphone3.5
1- افتح خانة Utilities 
2- افتح Attributes Inspector tab
3- في جزء ال Simulated Metrics  أعط المتغير Size  القيمة None

  • أعط الجدول الأبعاد التالية : X: 0, Y: 0, Width: 320, Height: 416.
  • عدل متغير Title  للزر على يسار الشريط إلى My Profile.
  • عدل متغير Title  للزر على يمين الشريط إلى Revoke access.
هذا هو كل ما نريده من الواجهة وهكذا يجب أن تبدو الآن:


4 - إعداد IBOutlets & IBActions
الخطوة الأولى

الواجهة الخاصة بنا أصبحت جاهزة ولكن نحتاج خاصية IBOutlet لوصل عرض الجدول. وكذلك نحتاج إلى اثنتين من IBAction methods. انقر على الزر الأوسط في جزء التعديل من ال Xcode لجعل مساعد التعديل يظهر.

الخطوة الثانية

لتحقيق هدف إنشاء اتصال IBOutlet افتح Document Outline وقم بهذه الخطوات:
1. قم بالضغط على Control + Click أو Right + Click على عرض الجدول
2. على القائمة التي تظهر انقر New Referencing Outlet
3. اسحب وأسقط في نافذة the Assistant Editor، كما ترى في الصورة التالية.


قم بإعطاء الجدول اسم وقم بالنقر على زر Connect ، أنا قمت بتسميته table.

الخطوة الثالثةوالآن لنقم بإنشاء IBAction methods. قم بتطبيق ال procedure التالية في كل زر من الاثنان المذكورين سابقاً

1. قم بالضغط على Control + Click أو Right + Click على الزر شمال الشريط
2. انقر على خيار Selector في جزء ال Sent Actions من القائمة التي تظهر
3. اسحب وأسقط في نافذة the Assistant Editor.


أعط ال
method  اسم  showProfile  وقم بإنشاءها


أعط اسم revokeAccess لل IBAction method الأخرى عندما تقوم بإنشائها الملف  ViewController.h   بعد خاصية IBOutlet و IBAction methods ستكون كالتالي

#import <UIKit/UIKit.h>
@interface ViewController : UIViewController@property (weak, nonatomic) IBOutlet UITableView *table;
- (IBAction)showProfile:(id)sender;- (IBAction)revokeAccess:(id)sender;
@end

5 – إنشاء ملف بناء بروتوكول OAuth 2.0

الخطوة الأولى

على الرغم أننا أضفنا عرض جدول في المشروع، فلن نقوم بإنشاء delegate methods الخاصة به. هذا فعلياً ما سنقوم به بعد الانتهاء من إنشاء الملف الخاص ببروتوكول OAuth 2.0. ما سنقوم به حالياً هو إنشاء ملف جديد لبناء بروتوكول OAuth.
في ال Project Navigator، قم بعمل التالي:
1. Control + Click أو Right + Click على مجموعة GoogleOAuthDemo
2. اختر خيار New File من القائمة

الخطوة الثانية

في النافذة التي تظهر اختر خيار Objective-C class كقالب للملف الجديد


ثم في حقل Subclass، اختر خيار UIWebView. الكلاس الجديد سيكون كلاس فرعي من الرئيسي UIWebView  لأننا نريد إظهار محتوى ويب للمستخدمين لجعلهم يدخلون باستخدام حسابات ال Google  خاصتهم وإعطئهم صلاحية على هذا التطبيق. في حقل ال Class أضف قيمة GoogleOAuth:

في الخطوة التالية، قم بالنقر على زر الإنشاء create لتنشئ الملف الجديد


 -6تسلسل بروتوكول OAuth 2.0
في هذا الجزء، سأقوم بتوضيح كيفية بناء البروتوكول وكيفية كل فحوصات وجود رموز الوصول. بداية بعد الحصول على ال access token، سيتم تخزينها مع بعض البيانات الأخرى التي تأتي معها. وهذا يرجع إلى المطور أن يختار الطريقة التي يخزن فيها البيانات. فمن الممكن أن تخزن كل شيء في قاعدة البيانات، أو حفظها في user defaults، أو يمكنك تخزين كل شيء في files ومن الممكن أيضاً استخدام طرق أكثر أمناً. في هذا المقال التعليمي أنا أفضل التخزين في ملفات واضحة داخل مجلد ال documents الموجود في مجلد ال app.
سنقوم بإنشاء ملفين مختلفين، رمز الوصول وأي معلومات أخرى تأتي معه من Google سيتم تخزينها في الملف الأول ما عدا تحديث رمز الوصول Refresh token حيث سيتم تخزينها في الملف الثاني لأننا نحتاج أن نحفظها لوقت أطول من أي معلومات أخرى، كما أننا نستخدمها عندما تنتهي صلاحية رمز الوصول. في كل مرة يتم تحديث رمز الوصول، محتويات الملف  الأول يتم الكتابة فوقها أي تمسح ويكتب بيانات جديدة. بجانب ذلك refresh token لا يتم تحديثها بهذا الرتم.
فيما يلي عرض لتسلسل البروتوكول وكيفية بناؤه.


ومع أن الصورة تعادل آلاف الكلمات ، إلا أني أفضل أن أقوم بتفصيل ال procedure كاملة لتكون أوضح. لتفصيل عملية التحقق:
في حال أن الملف الذي يحتوي على رمز الوصول غير موجود:1- الرابط الذي يتطلب التعامل مع رمز الوصول من خلاله يتم تكوينه. كل الوسائط parameters الضرورية للتحقق من المستخدم ستكون موجودة. سنحتاج client ID و client secret values.
2- ثم نقوم بعرض عرض ويب داخل التطبيق( لا نقوم باستدعاء تطبيق متصفح السفاري) لجعل المستخدم يدخل إلى Google. وبعد الدخول الناجح سيتم عرض رسالة للمستخدم بالصلاحيات.
3- يتم إرجاع كود تحقق من Google والذي سيتم تبادله مع رمز الوصول لاحقاً.
4- يتم تكوين رابط جديد بالparameters الجديدة. الهدف هو تبادل كود التحقق مع رمز الوصول.
5- إذا تم الحصول على رمز الوصول بنجاح، يتم إبلاغ ال class المستدعي من خلال method. غير ذلك سيتم استدعاءmethod أخرى لنعلم الclass المستدعي أنه لم يتم الحصول على رمز الوصول، وبناء عليه يتم اتخاذ الإجراءات اللازمأما في حال أن الملف الذي يحتوي على معلومات رمز الوصول كان موجود..
1- يتم تحميل معلومات رمز الوصول من الملف
2- يتم فحص رمز الوصول لمعرفة إذا كان منتهي الصلاحية أم لا
3- إذا كان رمز الوصول متاح، عندها يتم إعلام ال class  المستدعي بذلك من خلال method بأن رمز الوصول متاح وتنتهي الخطوات هنا حينها، أما في حال كان رمز الوصول غير متاح يفترض عمل تحديث له وهو ما سيتم توضيحه في الخطوات التالية.
4- إذا كان الملف المحتوي على تحديث رمز الوصول غير موجود عندها يبدأ برتوكول OAuth من جديد، أما إذا كان الملف موجود يتم تحميل refresh token
5- يتم طلب رمز وصول جديد. إذا كانت ال refresh token  غير متاحة، سيتم إرجاع نوع من رسائل الخطأ من Google ويتم توجيه المستخدم إلى البداية من جديد، غير ذلك يتم الحصول على رمز الوصول.
لنرى كيفية هذه الخطوات بالتفصيل الآن
7.بدء البناء
الخطوة الأولى
في البداية، افتح الملف GoogleOAuth.h وقم ب adopt للبروتوكولين التاليين بتعريفهم في @interface header line 
@interface OAuth : UIWebView <UIWebViewDelegate, NSURLConnectionDataDelegate>@end


الخطوة الثانية
والآن سننشئ enum type، مع قيم ال HTTP method المقبولة المطلوبة للعديد من استدعاءات API. وسنقوم باستخدامه عند استدعاء API method.
مباشرة فوق سطر @interface في ملف GoogleOAuth.h قم بإضافة الكود التالي:

typedef enum {    httpMethod_GET,    httpMethod_POST,    httpMethod_DELETE,    httpMethod_PUT} HTTP_Method;

الخطوة الثالثة

من المفيد دائماً استخدام الثوابت للأشياء التي لا نريدها أن تعمل أي مشاكل، وأيضاً هذا صحيح لل URL endpoints التي نود الوصول إليها من خلال تسلسل بروتوكول OAuth. لهذا السبب افتح الملف GoogleOAuth.m وقم بتعريف الثوابت الاثنين التاليين في بداية الملف.

#define authorizationTokenEndpoint @"https://accounts.google.com/o/oauth2/auth"#define accessTokenEndpoint @"https://accounts.google.com/o/oauth2/token"
الرابط الأول سيتم استخدامه للوصول إلى endpoint للحصول على كود التحقق، والذي سوف يتم تبادله لاحقاً مع رمز الوصول باستخدام ال endpoint الثانية. والآن سنقوم بتعريف بعض الخصائص والتي سنقوم بتخزين بعض البيانات فيها.
الخطوة الرابعة
أثناء العمل في ملف GoogleOAuth.m، داخل الجزء ال private من ال interface قم بإضافة الخصائص التالية. التعليقات فوق كل خاصية توضح الهدف الذي أنشئت له:
// The client ID from the Google Developers Console.@property (nonatomic, strong) NSString *clientID;// The client secret value from the Google Developers Console.@property (nonatomic, strong) NSString *clientSecret;// The redirect URI after the authorization code gets fetched. For mobile applications it is a standard value.@property (nonatomic, strong) NSString *redirectUri;// The authorization code that will be exchanged with the access token.@property (nonatomic, strong) NSString *authorizationCode;// The refresh token.@property (nonatomic, strong) NSString *refreshToken;// An array for storing all the scopes we want authorization for.@property (nonatomic, strong) NSMutableArray *scopes;// A NSURLConnection object.@property (nonatomic, strong) NSURLConnection *urlConnection;// The mutable data object that is used for storing incoming data in each connection.@property (nonatomic, strong) NSMutableData *receivedData;// The file name of the access token information.@property (nonatomic, strong) NSString *accessTokenInfoFile;// The file name of the refresh token.@property (nonatomic, strong) NSString *refreshTokenFile;// A dictionary for keeping all the access token information together.@property (nonatomic, strong) NSMutableDictionary *accessTokenInfoDictionary;// A flag indicating whether an access token refresh is on the way or not.@property (nonatomic) BOOL isRefreshing;// The parent view where the webview will be shown on.@property (nonatomic, strong) UIView *parentView;

الخطوة الخامسة
لاحظ أنه لا يوجد خاصية معينة لرمز الوصول ولكننا نستخدم accessTokenInfoDictionary NSMutableDictionary لتخزين كل البيانات المتعلقة برمز الوصول.
والآن وقت إضافة بعض التعريفات، أضف الكود التالي داخل (id)initWithFrame:(CGRect)frame:
- (id)initWithFrame:(CGRect)frame{    self = [super initWithFrame:frame];    if (self) {        // Set the access token and the refresh token file paths.        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);        NSString *docDirectory = [paths objectAtIndex:0];        _accessTokenInfoFile = [[NSString alloc] initWithFormat:@"%@/acctok", docDirectory];        _refreshTokenFile = [[NSString alloc] initWithFormat:@"%@/reftok", docDirectory];             // Set the redirect URI.        // This is taken from the Google Developers Console.        _redirectUri = @"urn:ietf:wg:oauth:2.0:oob";                 // Make any other required initializations.        _receivedData = [[NSMutableData alloc] init];        _urlConnection = [[NSURLConnection alloc] init];        _refreshToken = nil;        _isRefreshing = NO;    }    return self;}
باقي التعريفات ستكون داخل ال methods التي سنستخدمها.
8- تعريف البروتوكول
تعريف بروتوكول داخل class جديد دائماً ما يتم بعد إتمام وظائف كل ال class’، ولكن في حالتنا سيكون من الجيد تحضير تعريف البروتوكول قبل أن نكمل العمل. سنقوم بتعريف ال methods الخاصة بالبروتوكول والتي سيتم بناءها فيما بعد. ولذلك داخل ملف GoogleOAuth.h وفوق سطر @interface line قم بإضافة الكود التالي:
@protocol GoogleOAuthDelegate-(void)authorizationWasSuccessful;-(void)accessTokenWasRevoked;-(void)responseFromServiceWasReceived:(NSString *)responseJSONAsString andResponseJSONAsData:(NSData *)responseJSONAsData;-(void)errorOccuredWithShortDescription:(NSString *)errorShortDescription andErrorDetails:(NSString *)errorDetails;-(void)errorInResponseWithBody:(NSString *)errorMessage;@end
وهذا تفصيل بسيط لل methods:
·         authorizationWasSuccessful: يتم استدعاءها بعد كل عملية تحقق ناجحة، أي بعد الحصول على رمز وصول متاح
·         accessTokenWasRevoked: سيتم استدعاءها عندما يقوم المستخدم بسحب كل الصلاحيات     responseFromServiceWasReceived:andResponseJSONAsData:: سيتم استدعاءها في كل مرة يتم فيها استلام رد من API
    errorOccuredWithShortDescription:andErrorDetails:: يتم استدعاءها عند حدوث أي خطأ.
·         errorInResponseWithBody: يتم استدعاءها عندما يحدث خطأ في رد HTTP.
ثم داخل ال @interface قم بإضافة السطر التالي:

@interface OAuth : UIWebView <UIWebViewDelegate, NSURLConnectionDataDelegate>
@property (nonatomic, strong) id<GoogleOAuthDelegate> gOAuthDelegate;
@end
9- إعداد تسلسل التحقق

الخطوة الأولى

حتى الآن قمنا بتعريف كل المتغيرات، والتي سنحتاج فيما بعد عمل  Initialization لها، وعرفنا الثوابت، والبروتوكول، ولذلك حان الوقت للبدء ببناء تسلسل التحقق الفعلي. أفضل مكان للبدء به هو "entry" point. وهي public method سيستدعيها المستخدم في كل وقت يجب التحقق من هويته أو في كل وقت يود استخدام ال API.
افتح ملف GoogleOAuth.h وقم بإضافة تعريف الmethod التالية:
@interface GoogleOAuth : UIWebView <UIWebViewDelegate, NSURLConnectionDataDelegate>@property (nonatomic, strong) id<GoogleOAuthDelegate>

gOAuthDelegate;-(void)authorizeUserWithClienID:(NSString *)client_ID andClientSecret:(NSString *)client_Secret andParentView:(UIView *)parent_View andScopes:(NSArray *)scopes;@end

الخطوة الثانية

والآن لنبدأ ببناء ال method وباعتقادي أنه من الجيد أن نقوم ببناء ال method ثم نناقشها قليلاً. داخل ملف GoogleOAuth.m قم بإضافة الكود:

-(void)authorizeUserWithClienID:(NSString *)client_ID andClientSecret:(NSString *)client_Secret andParentView:(UIView *)parent_View andScopes:(NSArray *)scopes{ // Store into the local private properties all the parameter values. _clientID = [[NSString alloc] initWithString:client_ID]; _clientSecret = [[NSString alloc] initWithString:client_Secret]; _scopes = [[NSMutableArray alloc] initWithArray:scopes copyItems:YES]; _parentView = parent_View; // Check if the access token info file exists or not. if ([self checkIfAccessTokenInfoFileExists]) { // In case it exists load the access token info and check if the access token is valid. [self loadAccessTokenInfo]; if ([self checkIfShouldRefreshAccessToken]) { // If the access token is not valid then refresh it. [self refreshAccessToken]; } else{ // Otherwise tell the caller through the delegate class that the authorization is successful. [self.gOAuthDelegate authorizationWasSuccessful]; } } else{ // In case that the access token info file is not found then show the // webview to let user sign in and allow access to the app. [self showWebviewForUserLogin]; }}
لنتكلم قليلاً عن الطريقة التي تعمل بها ال method. كما ترى، أول شيء نقوم به هو تخزين القيم التي يتم تمريرها إلى ال method في متغيرات داخل ال method وهذه المتغيرات هي client ID و client secret و scopes array و UIView والتي سيظهر من خلالها login webview.
A scope indicates an API that the app requests access for.
ثم نقوم بعمل فحص إذا كان ملف معلومات رمز الوصول موجود، نقوم بتحميله باستخدام loadAccessTokenInfo method. ثم نقوم بفحص إذا كان متاح باستخدام checkIfShouldRefreshAccessToken method وإذا لم يكن متاحاً، نقوم بعمل تحديث له باستخدام refreshAccessToken method، في حال كان رمز الوصول متاح ولم تنتهي صلاحيته بعد فقط نقوم بإخبار الكلاس المستدعي  من خلال authorizationWasSuccessful delegate method. وأخيراً إذا لم يكن ملف معلومات رمز الوصول موجود، نقوم باستدعاء showWebviewForUserLogin method لتفتح webview وتسمح للمستخدم بالدخول.
كل ال methods المذكورة سابقاً سيتم بناءها على التوالي.
10 تعريف ال method
كما ترى بنفسك ال method يكمن عملها في استدعاء private method أخرى، وقبل أن نكمل العمل سنقوم بتعريف ال private methods التي سنقوم ببنائها داخل جزء the private @interface section.
لجعل الفكرة أبسط للفهم، أفضل أن نقوم بتقسيم ال private methods إلى قسمين:
1- الأولى تتضمن ال methods التي تعتبر جزء من تسلسل عملية التحقق نفسها وهذه هي ال methods

@interface OAuth()
...
...
-(void)showWebviewForUserLogin;
-(void)exchangeAuthorizationCodeForAccessToken;
-(void)refreshAccessToken;
@end
2- الفئة الثانية تتضمن ال methods المساعدة التي تدعم عملية بناء تسلسل التحقق ببناء عمليات أخرى محتملة لتعمل ال procedure بشكل صحيح تماماً وهذه ال  methods هي:
@interface OAuth()
...
...
-(NSString *)urlEncodeString:(NSString *)stringToURLEncode;
-(void)storeAccessTokenInfo;
-(void)loadAccessTokenInfo;
-(void)loadRefreshToken;
-(BOOL)checkIfAccessTokenInfoFileExists;
-(BOOL)checkIfRefreshTokenFileExists;
-(BOOL)checkIfShouldRefreshAccessToken;
-(void)makeRequest:(NSMutableURLRequest *)request;
@end

بجانب كل ما سبق، سنقوم ببناء delegate method التالية لل webview:
-(void)webViewDidFinishLoad:(UIWebView *)webView;
وباستخدامها سنقرأ كود التحقق.
بالإضافة لذلك سنقوم ببناء NSURLConnection delegate methods التالية:
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;-(void)connectionDidFinishLoading:(NSURLConnection *)connection;-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
لنبدأ الآن ولنرى كيف سيتم ربط هذه ال methods.
11- بناء تسلسل التحقق Authorization flow

 الخطوة الأولى

لنكمل الآن ببناء -(void)showWebviewForUserLogin. هذه ال method تخدم غرضين. الأول هو تكوين الرابط والذي سيستخدمه تطبيقنا في الحصول على كود التحقق. الغرض الثاني هو عرض webview للمستخدمين، والتي من خلالها سيقومون بالدخول إلى حساباتهم في Google وإعطاء الصلاحيات للتطبيق، دعنا نرى ال method  أولاً.
-(void)showWebviewForUserLogin{    // Create a string to concatenate all scopes existing in the _scopes array.    NSString *scope = @"";    for (int i=0; i<[_scopes count]; i++) {        scope = [scope stringByAppendingString:[self urlEncodeString:[_scopes objectAtIndex:i]]];                 // If the current scope is other than the last one, then add the "+" sign to the string to separate the scopes.        if (i < [_scopes count] - 1) {            scope = [scope stringByAppendingString:@"+"];        }    }         // Form the URL string.    NSString *targetURLString = [NSString stringWithFormat:@"%@?scope=%@&amp;redirect_uri=%@&amp;client_id=%@&amp;response_type=code",                                 authorizationTokenEndpoint,                                 scope,                                 _redirectUri,                                 _clientID];              // Do some basic webview setup.    [self setDelegate:self];    [self setScalesPageToFit:YES];    [self setAutoresizingMask:_parentView.autoresizingMask];         // Make the request and add self (webview) to the parent view.    [self loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:targetURLString]]];    [_parentView addSubview:self];}
يجب التنويه إلى ملاحظتين. الملاحظة الأولى أن كل المجالات الموجودة في _scopes array يتم تجميعها في NSString واحد بعد أن يتم تشفيرها. وهذا مهم جداً بحيث كل رمز موجود سيتم استبداله بالرمز المقابل له في ال URL encoding. يتم استخدام string مؤقت لغرض التجميع. داخل الstring المجمع يتم فصل ال scopes عن طريق الإشارة "+"
ومن ثم يتم تكوين ال URL string. كن متنبهاً للوسائط parameters التي تقبلها
وهي:
  • كود التحقق authorization code endpoint
·المجالات scopes
·ال redirect URI  وهو قيمة ثابتة للتطبيقات التي قمنا بتنزيلها
·client ID والذي نحصل عليه من وحدة تحكم مطور Google
·response_type وهي قيمة تعطى القيمة المعيارية للكود
في الجزء الثاني من ال method نقوم بإعداد webview والتي ستظهر للمستخدم. الكود هنا سهل فقط لاحظ بعد إعداد كل شيء واستدعاء loadRequest method يتم إضافة ال webview ك subview لل view الأصلي.

الخطوة الثانية

بمجرد أن يقوم المستخدم بالدخول ووافق على إعطاء تطبيقنا صلاحية الوصول، يتم إرجاع كود التحقق من Google. فعلياً هناك طريقتين للحصول عليه. الطريقة الأولى عن طريق ال cookies، حيث يتم تخزين الكود في  ملف cookieGoogle يعطي مثال على كيفية استخدامه. الطريقة الأخرى وهي الطريقة التي أفضل هي الحصول على كود التحقق من استعراض عنوان صفحة الويب. بمجرد حصولنا عليه نكون جاهزين للحصول على رمز الوصول.
هذا ما سوف نفعله في webview delegate method الوحيدة التي سنبنيها. دعونا نرى هذا.
-(void)webViewDidFinishLoad:(UIWebView *)webView{
    // Get the webpage title.
    NSString *webviewTitle = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
    //NSLog(@"Webview Title = %@", webviewTitle);
     
    // Check for the "Success token" literal in title.
    if ([webviewTitle rangeOfString:@"Success code"].location != NSNotFound) {
        // The oauth code has been retrieved.
        // Break the title based on the equal sign (=).
        NSArray *titleParts = [webviewTitle componentsSeparatedByString:@"="];
        // The second part is the oauth token.
        _authorizationCode = [[NSString alloc] initWithString:[titleParts objectAtIndex:1]];
         
        // Show a "Please wait..." message to the webview.
        NSString *html = @"<html><head><title>Please wait</title></head><body><h1>Please wait...</h1></body></html>";
        [self loadHTMLString:html baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];
         
        // Exchange the authorization code for an access code.
        [self exchangeAuthorizationCodeForAccessToken];
    }
    else{
        if ([webviewTitle rangeOfString:@"access_denied"].location != NSNotFound) {
            // In case that the user tapped on the Cancel button instead of the Accept, then just
            // remove the webview from the superview.
            [webView removeFromSuperview];
        }
    }
}
صيغة كود التحقق المرجع تشبه code=4/a5F4r45... ولذلك تم تقسيم الtitle إلى أجزاء بالاعتماد على الإشارة "=". وبعد ذلك نكون جاهزين لتبادله مع رمز الوصول

الخطوة الثالثة

الآن تم الحصول على رمز التحقق، وبالتالي لن نحتاج webview مجدداً. سنقوم بإزالتها في الخطوة التالية. سنحتاج الكلاس NSURLConnection و  NSURLRequestمن الآن وصاعداً. ما علينا فعله في exchangeAuthorizationCodeForAccessToken method هو فقط إعداد كل الوسائط parameters التي نحتاجها للحصول على رمز الوصول. أهم شيء أننا سنستخدم POST HTTP method وها هي ال method:
(void)exchangeAuthorizationCodeForAccessToken{    // Create a string containing all the post parameters required to exchange the authorization code    // with the access token.    NSString *postParams = [NSString stringWithFormat:@"code=%@&amp;client_id=%@&amp;client_secret=%@&amp;redirect_uri=%@&amp;grant_type=authorization_code",                            _authorizationCode,                            _clientID,                            _clientSecret,                            _redirectUri];         // Create a mutable request object and set its properties.    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:accessTokenEndpoint]];    [request setHTTPMethod:@"POST"];    [request setHTTPBody:[postParams dataUsingEncoding:NSUTF8StringEncoding]];    [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];         // Make the request.    [self makeRequest:request];}
لاحظ استخدام كود التحقق الذي حصلنا عليه في الخطوة السابقة.

الخطوة الرابعة

عند عمل طلب واستخدام a NSURLConnection قد يحدث أن الاتصال ينتهي بنجاح أو سوف يفشل. في حالتنا عندما يفشل الطلب فقط نريد إعلام الكلاس المستدعي من خلال delegate. لنكتب أول NSURLConnection delegate method.
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{    [self.gOAuthDelegate errorOccuredWithShortDescription:@"Connection failed." andErrorDetails:[error localizedDescription]];}
الآن هيا نذهب لحالة أن الاتصال نجح وتم الحصول على رمز الوصول.
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{    // This object will be used to store the converted received JSON data to string.    NSString *responseJSON;         // This flag indicates whether the response was received after an API call and out of the    // following cases.    BOOL isAPIResponse = YES;         // Convert the received data in NSString format.    responseJSON = [[NSString alloc] initWithData:(NSData *)_receivedData encoding:NSUTF8StringEncoding];            // Check for access token.    if ([responseJSON rangeOfString:@"access_token"].location != NSNotFound) {        // This is the case where the access token has been fetched.        [self storeAccessTokenInfo];                 // Remove the webview from the superview.        [self removeFromSuperview];                 if (_isRefreshing) {            _isRefreshing = NO;        }                 // Notify the caller class that the authorization was successful.        [self.gOAuthDelegate authorizationWasSuccessful];                 isAPIResponse = NO;    }}
لا تعتقد أن هذا هو الكود الوحيد الذي سيكون في هذه ال method فسيصبح الكود داخل هذه ال method كبير ولكن لا تشغل نفسك به الآن.
ملاحظة: هل ترى مؤشر isAPIResponse؟ هذا سيفيد لمعرفة متى يعود الرد ال API ومتى يعود إلى عملية التحقق. عندما يأتي في أي حالة في عملية التحقق سيصبح هذا المؤشر قيمته NO كما تستطيع أن ترى في حالة رمز الوصول. وستفهم ذلك من خلال السياق.
Google يقوم بإرجاع كائن عن طريق JSON والذي يحتوي على رمز الوصول مع بعض البيانات الأخرى. أول ما نقوم بعمله تحويل البيانات المستلمة إلى نص بحيث بعدها يمكننا معرفة ما نوع البيانات المستلمة والتعامل معها بالطريقة الصحيحة، بعمل ذلك في بداية ال method نفحص إذا تم استلام رمز الوصول أم لا. إذا كان موجود سيكون هذا جيد، وبالتالي علينا أن نقوم بحفظها في الملف، ونقوم بإزالة webview من superview. وفي حال تم الحصول على رمز الوصول أثناء عملية التحديث نقوم بإعطاء المؤشر المذكور سابقاً القيمة NO. وأخيراً سنستخدم ال delegate لإخبار الكلاس المستدعي أنه تم الحصول على رمز الوصول بنجاح.
قيمة ال JSON المرجعة ستكون شيئاً شبيه بهذا:
{  "access_token" : "ya29.AHES6ZSpPmQZwz30EcyhWE9mvi_lgvh4DX8gSQ9GpIbkLL5qhP9sYQ",  "token_type" : "Bearer",  "expires_in" : 3600,  "id_token" : "eyJhbGciOiJSUzI1NiIsImtpZCI6ImUxYzdhM2NkZGFmMzcxOWFlMGNlZGUzOTI4ZmZlZDI1MGFmMmQyODMifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwidG9rZW5faGFzaCI6ImNfWngxMzBaWGQySFlCT0lEWlhiVUEiLCJhdF9oYXNoIjoiY19aeDEzMFpYZDJIWUJPSURaWGJVQSIsImNpZCI6Ijg4ODk5MTE4OTQ4OS5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImF6cCI6Ijg4ODk5MTE4OTQ4OS5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImF1ZCI6Ijg4ODk5MTE4OTQ4OS5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImlkIjoiMTE0MzE1NTUzNzc0OTY1NTIwNTIzIiwic3ViIjoiMTE0MzE1NTUzNzc0OTY1NTIwNTIzIiwiaWF0IjoxMzczMjE5NDYwLCJleHAiOjEzNzMyMjMzNjB9.jM8_m8aqwW56V2YHob5d-Xlb69yTRBrd_FgagJlSSOxEgRcxpn3D6uDDBmbkiI7S_UgvCc07CAis9wmzTGrKvjpp8JR04ka_LlzdvlaWlFlMvCZgs13GNP8fpi_o4jTgpMLeUM47ZZbBtF0C2uU8XCaVAzTW-VOYZkNPT2SjDY4",  "refresh_token" : "1/xZWny-TMV0jZvDRuHxwMl5tTZSiN8yCGP7gaILbPPxk"}
الآن قم بإضافة الكود الموضح فوق هذا السطر
if ([_responseJSON rangeOfString:@"access_token"].location != NSNotFound) {
فهو مطلوب للتعامل مع أي طلب غير متاح قد يحصل.
if ([responseJSON rangeOfString:@"invalid_request"].location != NSNotFound) {    NSLog(@"General error occured.");         // If a refresh was on the way then set the respective flag to NO.    if (_isRefreshing) {        _isRefreshing = NO;    }         // Notify the caller class through the delegate.    [self.gOAuthDelegate errorInResponseWithBody:responseJSON];              isAPIResponse = NO;}
ال NSURLConnection مهمة جداً أيضاً، إذا أردت الخاصيتين فوق أن تعملان بشكل مناسب.
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{    // Append any new data to the _receivedData object.    [_receivedData appendData:data];}
انتهينا الآن من تسلسل عملية التحقق، ولكن لدينا الكثير لنقوم به قبل أن نقول أننا أتممنا إنشاء ال class.
12- تحديث رمز الوصول
المعلومات التي تم استلامها مع رمز الوصول هي الوقت الذي سيكون فيه رمز الوصول متاحاً بالثواني. عندما يكون رمز الوصول متاحاً يمكن استخدام بدون أي مشاكل عند استدعاء APIs. ولكن عند انتهاء صلاحية رمز الوصول من الضروري عمل refresh في الخلفية وحينها يمكن الحصول على رمز وصول جديد.
لفحص إذا كان رمز الوصول متاح أم لا سنستخدم checkIfShouldRefreshAccessToken method. والتي سنقوم ببنائها لاحقاً مع بقية ال methods  المساعدة. والآن سنركز على عملية refresh.
الطريقة التي نقوم بتحديث رمز الوصول من خلالها تشبه الطريقة التي نتبادل فيها كود التحقق لرمز الوصول. نقوم إعداد POST parameters وتشغيل NSURLRequest للحصول على رمز وصول جديد. هذه هي ال method:
-(void)refreshAccessToken{    // Load the refrest token if it's not loaded alredy.    if (_refreshToken == nil) {        [self loadRefreshToken];    }         // Set the HTTP POST parameters required for refreshing the access token.    NSString *refreshPostParams = [NSString stringWithFormat:@"refresh_token=%@&client_id=%@&client_secret=%@&grant_type=refresh_token",                                   _refreshToken,                                   _clientID,                                   _clientSecret                                   ];         // Indicate that an access token refresh process is on the way.    _isRefreshing = YES;         // Create the request object and set its properties.    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:accessTokenEndpoint]];    [request setHTTPMethod:@"POST"];    [request setHTTPBody:[refreshPostParams dataUsingEncoding:NSUTF8StringEncoding]];    [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];         // Make the request.    [self makeRequest:request];}
كما ترى، نحن فقط نحتاج لتحديث الرمز الذي حصلنا عليه مع رمز الوصول، ال client ID و client secret والقيمة المعيارية grant_type. لاشيء صعب أو جديد هنا.
ما يجب توضيحه هو أولاً، ال refresh token تأخذ وقت أطول من  access token. وهذا يعني أنه لا يتم استلام refresh token في كل مرة يتم استدعاء البروسيجر الخاصة بالتحديث. ممكن استخدام refresh token مرات عديدة والحقيقة تشير إلى الحاجة لطريقة أنجع للتخزين، ويجب أن يكون مكان أو طريقة التخزين تختلف عن ال access token. فمن الممكن إعادة كتابة الأخيرة عدة مرات وإذا عملنا refresh token معها، سوف يتم مسحها بعد أول refresh.
ثانياً: refresh token تصبح غير متاحة invalid أيضاً، فيهذه الحالة وإذا كانت ال access token تحتاج لتحديث، يجب قيادة المستخدم لإدخال معلومات الدخول وإعطاء صلاحيات الوصول مرة أخرى. وهذا ما يجب أخذه بعين الاعتبار في الكود.
داخل ال -(void)connectionDidFinishLoading:(NSURLConnection *)connection
حالة الحصول على access token من الرد فعلياً موجودة، مانحتاجه هو إضافة كود جديد والذي سوف يفحص إذا رد Google بأنه لدينا invalid refresh token لذا قبل سطر
 if ([_responseJSON rangeOfString:@"access_token"].location !=NSNotFound)
قم بإضافة الكود التالي:
// Check for invalid refresh token.// In that case guide the user to enter the credentials again.if ([responseJSON rangeOfString:@"invalid_grant"].location != NSNotFound) {    if (_isRefreshing) {        _isRefreshing = NO;    }         [self showWebviewForUserLogin];         isAPIResponse = NO;}
باستدعاء showWebviewForUserLogin method، سنبدأ الprocedure من جديد.

13- ال
   Private methods
 المساعدة:
الآن حان الوقت لإكمال الmethods المساعدة التي قمنا بتعريفها سابقاً.

الخطوة الأولى

لنبدأ ب -(NSString *)urlEncodeString:(NSString *)stringToURLEncode method، والتي تستخدم لنقل ال strings الخاصة بالرابط إلى ال a URL-encoded form. عندما يتم إرسال البيانات على الويب، ليس كل ال character ممكن تواجدها في الرابط، فال characters التي لا يمكن أن يتضمنها الرابط يجب استبدالها بأخرى، وهذا ما تقوم به ال method التالية:

-(NSString *)urlEncodeString:(NSString *)stringToURLEncode{    // URL-encode the parameter string and return it.    CFStringRef encodedURL = CFURLCreateStringByAddingPercentEscapes(NULL,                                                                     (CFStringRef) stringToURLEncode,                                                                     NULL,                                                                     (CFStringRef)@"!@#$%&*'();:=+,/?[]",                                                                     kCFStringEncodingUTF8);    return (NSString *)CFBridgingRelease(encodedURL);}
كما ترى، CFURLCreateStringByAddingPercentEscapes functionوالتي أنصح قراءة المزيد عنها، تقوم بإرجاع كائن من نوع CFStringRef، والذي يتم تحويله إلى NSString بعد إرجاعه. ليس من الصعب فهم ال parameters التي تأخذها هذه ال function. لاحظ أن هناك مجموعة من ال characters التي يجب استبدالها  بالإشارة "%". على سبيل المثال الإشارة "!" يتم استبدالها ب %21. والإشارة "*" إلى %2A وهكذا.

الخطوة الثانية

وسنعرض الآن الfunction  التالية:

-(void)storeAccessTokenInfo{
    NSError *error;

    // Keep the access token info into a dictionary.
    _accessTokenInfoDictionary = [NSJSONSerialization JSONObjectWithData:_receivedData options:NSJSONReadingMutableContainers error:&error];

    // Check if any error occured while converting NSData data to NSDictionary.
    if (error) {
        [self.gOAuthDelegate errorOccuredWithShortDescription:@"An error occured while saving access token info into a NSDictionary."
                                                andErrorDetails:[error localizedDescription]];
    }

    // Save the dictionary to a file.
    [_accessTokenInfoDictionary writeToFile:_accessTokenInfoFile atomically:YES];

    // If a refresh token is found inside the access token info dictionary then save it separately.
    if ([_accessTokenInfoDictionary objectForKey:@"refresh_token"] != nil) {
        // Extract the refresh token.
        _refreshToken = [[NSString alloc] initWithString:[_accessTokenInfoDictionary objectForKey:@"refresh_token"]];
  
        // Save the refresh token as data.
        [_refreshToken writeToFile:_refreshTokenFile atomically:YES encoding:NSUTF8StringEncoding error:&error];
  
        // If an error occurs while saving the refresh token notify the caller class.
        if (error) {
            [self.gOAuthDelegate errorOccuredWithShortDescription:@"An error occured while saving the refresh token."
                                                  andErrorDetails:[error localizedDescription]];
        }
    }
}
الأمور سهلة هنا. بداية يتم تخزين البيانات المستلمة التي تحتوي معلومات رمز الوصول في accessTokenInfoDictionary mutable dictionary وهو مخزن في ملف. ثم يتم فحص وجود refresh token في المعلومات المرجعة، إذا وجدت يتم استخلاصها وتخزينها في ملف آخر، ولا تنسى أننا يجب أن نخزن refresh token في ملف آخر غير المخصص لتخزين access token.

الخطوة الثالثة

الآن سنرى loadAccessTokenInfo method وسنناقشها فيما بعد:
-(void)loadAccessTokenInfo{    // Check if the access token info file exists.    if ([self checkIfAccessTokenInfoFileExists]) {        // Load the access token info from the file into the dictionary.        _accessTokenInfoDictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:_accessTokenInfoFile];    }    else{        // If the access token info file doesn't exist then inform the caller class through the delegate.        [self.gOAuthDelegate errorOccuredWithShortDescription:@"Access token info file was not found."                                              andErrorDetails:@""];    }}
بداية يتم فحص إذا كانت الملف الخاص بمعلومات ال access token موجود أم لا. إذا كان موجود عندها يتم تحميله في accessTokenInfoDictionary.إذا لم يكن الملف موجود لأي سبب عندها يتم إعلام الكلاس المستدعي بهذا عن طريق استدعاء errorOccuredWithShortDescription:andErrorDetails method.

الخطوة الرابعة
والآن لنرى كيفية تحميل ال refresh token:
-(void)loadRefreshToken{    // Check if the refresh token file exists.    if ([self checkIfRefreshTokenFileExists]) {        NSError *error;        _refreshToken = [[NSString alloc] initWithContentsOfFile:_refreshTokenFile encoding:NSUTF8StringEncoding error:&error];                 // If an error occurs while saving the refresh token notify the caller class.        if (error) {            [self.gOAuthDelegate errorOccuredWithShortDescription:@"An error occured while loading the refresh token."                                                  andErrorDetails:[error localizedDescription]];        }    }}
هذه الmethod تم بناءها بنفس طريقة بناء ال method السابقة، فنحن نقوم بفحص وجود الملف المحتوي على refresh code، وإذا كان موجود نقوم بتحميله في refreshToken string. أما في حال عدم وجوده نعلم الكلاس المستدعي بالخطأ عن طريق نفس الmethod المختصة لذلك.

الخطوة الخامسة

الآن سنقوم بفحص وجود ملف معلومات ال access token  من عدمه
-(BOOL)checkIfAccessTokenInfoFileExists{    // If the access token info file exists, return YES, otherwise return NO.    return (![[NSFileManager defaultManager] fileExistsAtPath:_accessTokenInfoFile]) ? NO : YES;}

الخطوة السادسة

قم بعمل نفس الشيء لفحص وجود ملف access token
-(BOOL)checkIfRefreshTokenFileExists{    // If the refresh token file exists then return YES, otherwise return NO.    return (![[NSFileManager defaultManager] fileExistsAtPath:_refreshTokenFile]) ? NO : YES;}

الخطوة السابعة

لنرى الآن كيفية فحص إذا كانت ال access token  متاحة أم لا. Google يقوم بإرجاع الوقت الذي ستبقى فيه ال access token متاحة مع بقية البيانات المرجعة، ويتم التعبير عن الوقت بالثواني والوقت عادة ما يكون 3600 ثانية أو ساعة. إذا انتهت صلاحية ال access token وأردنا تبادل البيانات مع Google service نحتاج فقط لتحديثها في الخلفية والحصول على واحدة جديدة.
الاستراتيجية المتبعة هنا سهلة للغاية. سنقوم بقراءة وقت إنشاء الملف المحتوي على معلومات ال access token كما سنقوم بقراءة الوقت الذي ستبقى فيه ال access token متاحة. إذا كان الوقت الذي مضى على إنشاء الملف أكبر من وقت حياة ال access token عندها تكون عملية التحديث ضرورية، أما في حال العكس فهذا يعني أنها ما زالت متاحة وهذا ما يوضحه الكود التالي:
-(BOOL)checkIfShouldRefreshAccessToken{
    NSError *error = nil;
    // Get the time-to-live (in seconds) value regarding the access token.
    int accessTokenTTL = [[_accessTokenInfoDictionary objectForKey:@"expires_in"] intValue];
    // Get the date that the access token file was created.
    NSDate *accessTokenInfoFileCreated = [[[NSFileManager defaultManager] attributesOfItemAtPath:_accessTokenInfoFile error:&error]
                                          fileCreationDate];

    // Check if any error occured.
    if (error != nil) {
        [self.gOAuthDelegate errorOccuredWithShortDescription:@"Cannot read access token file's creation date."
                                              andErrorDetails:[error localizedDescription]];
  
        return YES;
    }
    else{
        // Get the time difference between the file creation date and now.
        NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:accessTokenInfoFileCreated];
        // Check if the interval value is equal or greater than the accessTokenTTL value.
        // If that's the case then the access token should be refreshed.
        if (interval >= accessTokenTTL) {
            // In this case the access token should be refreshed.
            return YES;
        }
        else{
            // Otherwise the access token is valid.
            return NO;
        }
    }
}
إذا كانت ال access token تحتاج لتحديث سنقوم بإرجاع القيمة YES. وفي حالة العكس يتم إرجاع القيمة NO. الأمور واضحة جداً هنا ولا حاجة لمزيد من الشرح والتفاصيل هنا.

الخطوة الثامنة

ما تبقى الآن هو إنشاء makeRequest method وفائدتها عدم إعادة كتابة نفس الكود في كل مرة نود فيها استدعاء NSURLRequest الخاصة بالطلبات. ما سنقوم بعمله هو إفراغ محتويا الملف receivedData عن طريق إعطاء length القيمة zero وعمل طلب جديد.
-(void)makeRequest:(NSMutableURLRequest *)request{    // Set the length of the _receivedData mutableData object to zero.    [_receivedData setLength:0];         // Make the request.    _urlConnection = [NSURLConnection connectionWithRequest:request delegate:self];}

14- إضافات NSURLConnection

الخطوة الأولى

هناك العديد من الأشياء يجب إضافتها إلى ال connectionDidFinishLoading method لتكتمل، حتى الآن قمنا بإضافة دعم للأمور المتعلقة ب:
Invalid requests - الطلبات الغير متاحة
Invalid grants (e.g. an expired refresh token) - الصلاحيات الغير متاحة مثل أن تكون refresh token   غير متاحة
- الحصول على access token
ما تبقى الآن هو أن تدعم الmethod حالات المعطيات الخاطئة و أي رد ممكن أن يحتوي على كلمة خطأ بداخله. الرد يحتوي على رسالة خطأ عندما يتم استدعاء API وتكون ال access token غير متاحة. نحن دائماً نقوم بفحص إذا كانت ال access token  متاحة قبل القيام بأي طلبات. ومع ذلك تعتبر هذه قضية مفصلية يجب أن نتوقعها، ولأي حالة أخرى عامة بأن ال response يصف حدوث خطأ معين سنقوم باستدعاء errorInResponseWithBody method، ولذلك في نهاية connectionDidFinishLoading قم بكتابة الكود التالي:
// Check for invalid credentials.
// This checking is useful when an API is called without prior checking whether the
// access token is valid or not.
if ([responseJSON rangeOfString:@"Invalid Credentials"].location != NSNotFound ||
    [responseJSON rangeOfString:@"401"].location != NSNotFound) {
    [self refreshAccessToken];

    isAPIResponse = NO;
}

// This is the case where any other error message exists in the response.
if ([responseJSON rangeOfString:@"error"].location != NSNotFound) {
    [self.gOAuthDelegate errorInResponseWithBody:responseJSON];
    isAPIResponse = NO;
}

إذا نظرت إلى محتوى the connectionDidFinishLoading: method ستجد أن كل الحالات المتوقع ورودها عند Google response قد تم أخذها بعين الاعتبار. لسنا بحاجة لإضافة توقعات لحالات جديدة ما عدا استدعاء responseFromServiceWasReceived:andResponseJSONAsData: delegate method وهذه ال method سيتم استدعاؤها في كل مرة لدينا response ناتج عن استدعاء API وحدثت فيها أي حالة أخرى غير الحالات التي تم أخذها فعلياً بعين الاعتبار، هذا هو استدعاء ال method:

// If execution successfully arrives here then notify the caller class that a response was received.if (isAPIResponse) {    [self.gOAuthDelegate responseFromServiceWasReceived:responseJSON andResponseJSONAsData:_receivedData];}

الخطوة الثانية

من الجيد خصوصاً لل debugging أن يتم بناء ال method كالتالي:
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;    NSLog(@"%d", [httpResponse statusCode]);}

الكائن httpResponse يحتوي كود حالة ال HTTP المرجعة من الطلب. إذا كان كل شيء على ما يرام تكون هذه القيمة 200. ابحث على الويب لمزيد من المعلومات حول أكاود حالة ال http.

15- سحب صلاحية ال access token
في العديد من الحالات قد تحتاج لسحب صلاحية قمت بمنحها على تطبيق معين. Google تعطي رابط يتم من خلاله عمل طلب عند سحب الصلاحية.
افتح ملف GoogleOAuth.h لتعريف public method جديدة كما هو موضح في الأسفل:

@interface GoogleOAuth : UIWebView <UIWebViewDelegate, NSURLConnectionDataDelegate>
@property (nonatomic, strong) id<GoogleOAuthDelegate> gOAuthDelegate;
-(void)authorizeUserWithClienID:(NSString *)client_ID andClientSecret:(NSString *)client_Secret
                  andParentView:(UIView *)parent_View andScopes:(NSArray *)scopes;
-(void)revokeAccessToken;
@end
والآن افتح الملف GoogleOAuth.m:
-(void)revokeAccessToken{
    // Set the revoke URL string.
    NSString *revokeURLString = [NSString stringWithFormat:@"https://accounts.google.com/o/oauth2/revoke?token=%@",
                                 [_accessTokenInfoDictionary objectForKey:@"access_token"]
                                 ];
    // Create and make a request based on the URL string.
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:revokeURLString]];
    [self makeRequest:request];

    // Now that the request for revoking the access in Google has been made,
    // all local files regarding the access token should be removed as well.
    NSError *error = nil;
    // If the access token info file exists then delete it.
    if ([self checkIfAccessTokenInfoFileExists]) {
        [[NSFileManager defaultManager] removeItemAtPath:_accessTokenInfoFile error:&error];
  
        if (error != nil) {
            // If an error occurs while removing the access token info file then notify the caller class through the
            // next delegate method.
            [self.gOAuthDelegate errorOccuredWithShortDescription:@"Unable to delete access token info file."
                                                  andErrorDetails:[error localizedDescription]];
        }
    }

    // Check now if the refresh token file exists and then remove it.
    if ([self checkIfRefreshTokenFileExists]) {
        [[NSFileManager defaultManager] removeItemAtPath:_refreshTokenFile error:&error];
  
        if (error != nil) {
            // In case of an error while removing the file then notify the caller class through the delegate method.
            [self.gOAuthDelegate errorOccuredWithShortDescription:@"Unable to delete refresh token info file."
                                                  andErrorDetails:[error localizedDescription]];
        }
    }


    if (error == nil) {
        // If no error occured during file removals then use the next delegate method
        // to notify the caller class that the access has been revoked.
        [self.gOAuthDelegate accessTokenWasRevoked];
    }
}
في البداية نجهز ال URL string ونقوم بعمل الطلب. ثم يتم مسح أي ملف متعلق بال access token. وأخيراً يتم استدعاء ال delegate method.

16- استدعاء ال API
الكلاس الآن جاهز وإذا استخدمته الآن ستحصل على access token من Google. ولكن من دون بناء طريقة لاستدعاء ال API، البيانات الوحيدة التي ستحصل عليها هي بياناتك الشخصية، لذلك سنقوم ببناء آخر public method.
افتح ملف GoogleOAuth.h وقم بتعريف ال method كما تراها في الأسفل:

-(void)callAPI:(NSString *)apiURL withHttpMethod:(HTTP_Method)httpMethod
                    postParameterNames:(NSArray *)params postParameterValues:(NSArray *)values;
لاحظ أن أي API يحتاج لإرسال البيانات في Google يجب أن يكون في a key-value pair. الوسائط parameters لهذا هي:
· apiURL: هو ال URL string المطلوب لعمل استدعاء لل API.
· httpMethod: الmethod المستخدمة لاستدعاء ال API وهي التي نقوم فيها باستخدام ال enum data type الذي أنشأناه مسبقاً.
·  params:كائن من نوع NSArray يحتوي على مفاتيح key-value pair form parameters.
·  values: كائن من نوع NSArray يحتوي على قيم مفاتيح key-value pair form parameter.

الآن قم بتشغيل ملف GoogleOAuth.m وابني ال method:
-(void)callAPI:(NSString *)apiURL withHttpMethod:(HTTP_Method)httpMethod                            postParameterNames:(NSArray *)params                            postParameterValues:(NSArray *)values{      // Check if the httpMethod value is valid.    // If not then notify for error.    if (httpMethod != httpMethod_GET && httpMethod != httpMethod_POST && httpMethod != httpMethod_DELETE && httpMethod != httpMethod_PUT) {        [self.gOAuthDelegate errorOccuredWithShortDescription:@"Invalid HTTP Method in API call" andErrorDetails:@""];    }    else{        // Create a string containing the API URL along with the access token.        NSString *urlString = [NSString stringWithFormat:@"%@?access_token=%@", apiURL, [_accessTokenInfoDictionary objectForKey:@"access_token"]];        // Create a mutable request.        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];              // Depending on the httpMethod value set the respective property of the request object.        switch (httpMethod) {            case httpMethod_GET:                [request setHTTPMethod:@"GET"];                break;            case httpMethod_POST:                [request setHTTPMethod:@"POST"];                break;            case httpMethod_DELETE:                [request setHTTPMethod:@"DELETE"];                break;            case httpMethod_PUT:                [request setHTTPMethod:@"PUT"];                break;                          default:                break;        }                       // In case of POST httpMethod value, set the parameters and any other necessary properties.             if (httpMethod == httpMethod_POST) {            // A string with the POST parameters should be built.            // Create an empty string.            NSString *postParams = @"";            // Iterrate through all parameters and append every POST parameter to the postParams string.            for (int i=0; i<[params count]; i++) {                postParams = [postParams stringByAppendingString:[NSString stringWithFormat:@"%@=%@",                                                                  [params objectAtIndex:i], [values objectAtIndex:i]]];                              // If the current parameter is not the last one then add the "&" symbol to separate post parameters.                if (i < [params count] - 1) {                    postParams = [postParams stringByAppendingString:@"&"];                }            }                      // Set any other necessary options.            [request setHTTPBody:[postParams dataUsingEncoding:NSUTF8StringEncoding]];            [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];        }                    // Make the request.        [self makeRequest:request];    }}
أصبح الكلاس الآن جاهزاً للعمل.
17- تكوين التطبيق التجريبي

الخطوة الأولى
في بداية بناء هذا المشروع، قمنا بإضافة جدول والآن هو الوقت لإعداده، لذلك أولاً افتح الملف ViewController.h

وقم بإعداد البروتوكول كما في السطر الأول:
 @interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>@property (weak, nonatomic) IBOutlet UITableView *table;
- (IBAction)showProfile:(id)sender;
- (IBAction)revokeAccess:(id)sender;
@end
بجانب البروتوكولين السابقين، نحتاج أيضاً لتبني البروتوكول الخاص بنا، ولذلك في بداية الملف قم بعمل استيراد للملف GoogleOAuth.h  وقم بتبني  بروتوكول  GoogleOAuthDelegate كما في السطر الثاني من الكود:
#import <UIKit/UIKit.h>
#import "GoogleOAuth.h"
@interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, GoogleOAuthDelegate>
@property (weak, nonatomic) IBOutlet UITableView *table;
- (IBAction)showProfile:(id)sender;
- (IBAction)revokeAccess:(id)sender;
@end

الخطوة الثانية

الآن افتح ملف ViewController.h. في الprivate section  من ال interface أضف بإضافة هاتين المصفوفتين لاحتياجنا لهم في تخزين معلومات ملف المستخدم والتي سيتم عرضها في الجدول:

@interface ViewController ()@property (nonatomic, strong) NSMutableArray *arrProfileInfo;@property (nonatomic, strong) NSMutableArray *arrProfileInfoLabel;@end
فعلياً، arrProfileInfoLabel ستحتوي على بيانات تصف كل حقل من معلومات الملف المرجعة من Google. هذه البيانات ستوضع في detailTextLabel من كل خلية.
ونحتاج أيضاً لعمل Object من الكلاس الذي أنشأناه، أضف الكود التالي بعد تعريف المصفوفات مباشرة:

@interface ViewController ()
@property (nonatomic, strong) NSMutableArray *arrProfileInfo;
@property (nonatomic, strong) NSMutableArray *arrProfileInfoLabel;
@property (nonatomic, strong) GoogleOAuth *googleOAuth;
@end

الخطوة الثالثة

افتح ال method viewDidLoad لتعريف المصفوفتين والكائن من نوع googleOAuth، كما ستعمل set for delegates بما في ذلك delegate عرض الجدول:

- (void)viewDidLoad
{
    [super viewDidLoad];
    [_table setDelegate:self];
    [_table setDataSource:self];

    _arrProfileInfo = [[NSMutableArray alloc] init];
    _arrProfileInfoLabel = [[NSMutableArray alloc] init];

    _googleOAuth = [[GoogleOAuth alloc] initWithFrame:self.view.frame];
    [_googleOAuth setGOAuthDelegate:self];

}

الخطوة الرابعة

الآن يجب أن ننشئ ال methods الخاصة بعرض الجدول، وستكون المصفوفتان اللتان قمنا بعريفهما لا تحويان أي بيانات.
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return 1;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return [_arrProfileInfo count];
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier];

    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
   
        [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
        [cell setAccessoryType:UITableViewCellAccessoryNone];
   
        [[cell textLabel] setFont:[UIFont fontWithName:@"Trebuchet MS" size:15.0]];
        [[cell textLabel] setShadowOffset:CGSizeMake(1.0, 1.0)];
        [[cell textLabel] setShadowColor:[UIColor whiteColor]];
   
        [[cell detailTextLabel] setFont:[UIFont fontWithName:@"Trebuchet MS" size:13.0]];
        [[cell detailTextLabel] setTextColor:[UIColor grayColor]];
    }

    [[cell textLabel] setText:[_arrProfileInfo objectAtIndex:[indexPath row]]];
    [[cell detailTextLabel] setText:[_arrProfileInfoLabel objectAtIndex:[indexPath row]]];

    return cell;
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return 60.0;
}

الخطوة الخامسة

إنه الوقت لبناء IBAction methods التي أنشأناها في بداية المشروع. بدءاً من showProfile: method سنستدعي authorizeUserWithClienID: andClientSecret: andParentView: andScopes: من كلاس GoogleOAuth، والذي بدوره سيقوم بتشغيل تسلسل عملية التحقق:
- (IBAction)showProfile:(id)sender {    [_googleOAuth authorizeUserWithClienID:@"YOUR_CLIENT_ID"                           andClientSecret:@"YOUR_CLIENT_SECRET"                           andParentView:self.view                           andScopes:[NSArray arrayWithObjects:@"https://www.googleapis.com/auth/userinfo.profile", nil]     ];}
عليك التأكد من قيم client ID و client secret الخاصة بك.
لنبني الآن ال revokeAccess: IBAction method وهي عبارة عن سطر واحد من الكود كما يلي:
- (IBAction)revokeAccess:(id)sender {    [_googleOAuth revokeAccessToken];}

الخطوة السادسة

وأخيراً تبقى علينا هو delegate methods. باستخدام أول method IBAction، نعطي إشارة لتسلسل التحقق بالبدء. باستخدام delegate methods سنتحكم في كل شيء ونحصل على البيانات التي نريد. لذلك لنبنيهم واحدة تلو الأخرى.
سنبدأ من authorizationWasSuccessful: method. ويتم استدعاءها بعد الحصول على access token جديد أو عندما يكون لدينا access token ما زالت متاحة. وبذلك نكون جاهزين لاستدعاء ال API.
-(void)authorizationWasSuccessful{    [_googleOAuth callAPI:@"https://www.googleapis.com/oauth2/v1/userinfo"            withHttpMethod:httpMethod_GET            postParameterNames:nil postParameterValues:nil];}

والآن لنبني ال accessTokenWasRevoked: method. وستقوم بعرض تنبيه للمستخدم وإفراغ المصفوفات ومحتويات الجدول
-(void)accessTokenWasRevoked{    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@""                                                    message:@"Your access was revoked!"                                                   delegate:self cancelButtonTitle:nil otherButtonTitles:@"OK", nil];    [alert show];         [_arrProfileInfo removeAllObjects];    [_arrProfileInfoLabel removeAllObjects];         [_table reloadData]; }

لمعالجة الأخطاء سنقوم بتسجيل رسائل الخطأ وها هي ال methods الخاصة بذلك
-(void)errorOccuredWithShortDescription:(NSString *)errorShortDescription andErrorDetails:(NSString *)errorDetails{
    NSLog(@"%@", errorShortDescription);
    NSLog(@"%@", errorDetails);
}

-(void)errorInResponseWithBody:(NSString *)errorMessage{
    NSLog(@"%@", errorMessage);
}

وأخيراً، أهم delegate method  والتي يتم الحصول من خلالها على ال Google response مع معلومات ملف المستخدم وسنملأ المصفوفات. نقوم بفحص إذا كان حقل ال family_name موجود في رد ال JSON وذلك للتأكد من أن معلومات ملف المستخدم موجودة في ال response.
-(void)responseFromServiceWasReceived:(NSString *)responseJSONAsString andResponseJSONAsData:(NSData *)responseJSONAsData{    if ([responseJSONAsString rangeOfString:@"family_name"].location != NSNotFound) {        NSError *error;        NSMutableDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:responseJSONAsData                                                                          options:NSJSONReadingMutableContainers                                                                            error:&error];        if (error) {            NSLog(@"An error occured while converting JSON data to dictionary.");            return;        }        else{            if (_arrProfileInfoLabel != nil) {                _arrProfileInfoLabel = nil;                _arrProfileInfo = nil;                _arrProfileInfo = [[NSMutableArray alloc] init];            }                         _arrProfileInfoLabel = [[NSMutableArray alloc] initWithArray:[dictionary allKeys] copyItems:YES];            for (int i=0; i<[_arrProfileInfoLabel count]; i++) {                [_arrProfileInfo addObject:[dictionary objectForKey:[_arrProfileInfoLabel objectAtIndex:i]]];            }                         [_table reloadData];        }    }}
18- بروتوكول OAuth 2.0 أثناء العمل
شغل المشروع وأظهر ال iPhone simulator. بداية الجدول سيكون فارغاً، وذلك لعدم وجود أي بيانات. انقر على زر My Profile وأدخل معلوماتك للدخول إلى حساب ال Google الخاص بك. في النافذة التالية اسمح للتطبيق باستخدام معلومات المستخدم لديك. بمجرد أن ترجع إلى الى الجدول ستجد بياناتك الشخصية على الشاشة.
أوقف تشغيل التطبيق وشغله ثانية. انقر على My Profile ولاحظ أنه لن يطلب منك أي معلومات للدخول، وبدلاً من ذلك بياناتك الشخصية سيتم استرجاعها وعرضها في الجدول.
بعد ذلك جرب أن تسحب صلاحية الوصول واذهب إلى ملفك الشخصي profile مرة أخرى، في هذه الحالة سيطلب منك معلومات الدخول مرة أخرى.

الخلاصة
خلال هذا المقال التعليمي رأينا كيف يعمل بروتوكول OAuth 2.0، وتم بناء كلاس بسيط ولكنه يعمل بشكل كامل، ويحتوي على أداة ممكن أن يعاد استخدامها في التطبيقات الأخرى المعنية بالتعامل مع الخدمات التي يقدمها Google. وبالطبع ممكن إضافة المزيد من الوظائف في أي وقت.
في هذا المقال التعليمي حاولت أن أغطي كل الجوانب المطلوبة لبناء Google services باستخدام بروتوكول  OAuth 2.0. في المستقبل

الكــاتــب

    • مشاركة

ليست هناك تعليقات:

جميع الحقوق محفوظة لــ الشبح للمعلوميات 2019 ©