OAuth 2.0

ويوضّح هذا المستند بروتوكول OAuth 2.0 وحالات استخدامه وكيفية الحصول على معرِّفات العملاء وكيفية استخدامه مع مكتبة برامج Google API لنظام .NET.

بروتوكول OAuth 2.0

OAuth 2.0 هو بروتوكول التفويض الذي تستخدمه أداة Google APIs. يجب أن تتعرف على البروتوكول من خلال قراءة الروابط التالية:

الحصول على معرِّفات وأسرار العملاء

يمكنك الحصول على معرِّفات العملاء وأسرارهم في وحدة التحكم في واجهة Google API. هناك أنواع مختلفة من معرّفات العملاء، لذا احرص على اختيار النوع الصحيح لتطبيقك:

في كل مقتطف من مقتطفات الرمز أدناه (باستثناء مقتطف حساب الخدمة)، يجب تنزيل سر العميل وتخزينه باسم client_secrets.json في مشروعك.

بيانات الاعتماد

بيانات اعتماد المستخدم

UserCredential هي فئة مساعد آمنة تستخدم سلاسل المحادثات من أجل استخدام رمز دخول للوصول إلى موارد محمية. تنتهي صلاحية رمز الدخول عادةً بعد ساعة واحدة، وبعد ذلك ستتلقى رسالة خطأ إذا حاولت استخدامه.

تعمل ميزتا UserCredential وAuthorizationCodeFlow على "إعادة تحميل" الرمز المميّز تلقائيًا، ما يعني ببساطة الحصول على رمز دخول جديد. يتم إجراء ذلك باستخدام رمز مميّز طويل الأمد لإعادة التحميل، والذي ستحصل عليه مع رمز الدخول إذا كنت تستخدم المَعلمة access_type=offline أثناء مسار رمز التفويض.

في معظم التطبيقات، يُنصح بتخزين رمز الدخول الخاص ببيانات الاعتماد والرمز المميّز لإعادة التحميل في مساحة تخزين دائمة. بخلاف ذلك، ستحتاج إلى تقديم صفحة تفويض في المتصفّح كل ساعة إلى المستخدم النهائي، لأنّ رمز الدخول تنتهي صلاحيته بعد ساعة من تلقّيه.

للتأكّد من استمرار الرموز المميّزة للوصول وإعادة التحميل، يمكنك تقديم طريقة التنفيذ الخاصة بك لاستخدام IDataStore، أو يمكنك استخدام إحدى عمليات التنفيذ التالية التي توفّرها المكتبة:

  • تضمن FileDataStore لنظام .NET أن تظل بيانات الاعتماد ثابتة في الملف.

ServiceAccountCredential

إنّ السمة ServiceAccountCredential مشابهة للسمة UserCredential، ولكنّها تخدم غرضًا مختلفًا. يتوافق الإصدار 2.0 من Google OAuth مع التفاعلات من خادم إلى خادم، مثل التفاعلات بين تطبيق ويب وGoogle Cloud Storage. يجب أن يُثبت التطبيق صاحب الطلب هويته الخاصة للوصول إلى واجهة برمجة التطبيقات، ولا حاجة إلى مشاركة المستخدم النهائي. يخزِّن ServiceAccountCredential مفتاحًا خاصًا يُستخدم لتوقيع طلب للحصول على رمز دخول جديد.

يُستخدم كل من UserCredential وServiceAccountCredential في تنفيذ IConfigurableHttpClientInitializer حتى تتمكن من تسجيل كلٍّ من هذه الخيارات على النحو التالي:

  • يعني ذلك أنّه معالِج استجابة غير صالح، لذلك ستتم إعادة تحميل الرمز المميّز إذا تلقّى رمز حالة HTTP 401.
  • أداة اعتراض، لاعتراض عنوان Authorization في كل طلب.

التطبيقات المثبتة

رمز نموذجي باستخدام Books API:

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

using Google.Apis.Auth.OAuth2;
using Google.Apis.Books.v1;
using Google.Apis.Books.v1.Data;
using Google.Apis.Services;
using Google.Apis.Util.Store;

namespace Books.ListMyLibrary
{
    /// <summary>
    /// Sample which demonstrates how to use the Books API.
    /// https://developers.google.com/books/docs/v1/getting_started
    /// <summary>
    internal class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            Console.WriteLine("Books API Sample: List MyLibrary");
            Console.WriteLine("================================");
            try
            {
                new Program().Run().Wait();
            }
            catch (AggregateException ex)
            {
                foreach (var e in ex.InnerExceptions)
                {
                    Console.WriteLine("ERROR: " + e.Message);
                }
            }
            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
        }

        private async Task Run()
        {
            UserCredential credential;
            using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
            {
                credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
                    GoogleClientSecrets.Load(stream).Secrets,
                    new[] { BooksService.Scope.Books },
                    "user", CancellationToken.None, new FileDataStore("Books.ListMyLibrary"));
            }

            // Create the service.
            var service = new BooksService(new BaseClientService.Initializer()
                {
                    HttpClientInitializer = credential,
                    ApplicationName = "Books API Sample",
                });

            var bookshelves = await service.Mylibrary.Bookshelves.List().ExecuteAsync();
            ...
        }
    }
}
  
  • في هذا الرمز النموذجي، يتم إنشاء مثيل UserCredential جديد من خلال استدعاء الطريقة GoogleWebAuthorizationBroker.AuthorizeAsync. تحصل هذه الطريقة الثابتة على ما يلي:

    • سر العميل (أو تدفق إلى سر العميل).
    • النطاقات المطلوبة.
    • معرّف المستخدِم.
    • الرمز المميز للإلغاء لإلغاء عملية.
    • مخزن بيانات اختياري إذا لم يتم تحديد مخزن البيانات، يكون الإعداد التلقائي هو FileDataStore مع مجلد Google.Apis.Auth تلقائي. تم إنشاء المجلد في "Environment.SpecialFolder.ApplicationData".
  • يتم ضبط UserCredential الذي تعرضه هذه الطريقة على أنّه HttpClientInitializer في BooksService (باستخدام أداة الإعداد). كما هو موضّح أعلاه، ينفِّذ UserCredential مهيئ عميل HTTP.

  • لاحظ أنّه في نموذج الرمز البرمجي أعلاه، يتم تحميل معلومات سر العميل من ملف، ولكن يمكنك أيضًا تنفيذ ما يلي:

    credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
        new ClientSecrets
        {
            ClientId = "PUT_CLIENT_ID_HERE",
            ClientSecret = "PUT_CLIENT_SECRETS_HERE"
        },
        new[] { BooksService.Scope.Books },
        "user",
        CancellationToken.None,
        new FileDataStore("Books.ListMyLibrary"));
          

يمكنك إلقاء نظرة على نموذج الكتب.

تطبيقات الويب (ASP.NET Core 3)

تتوافق واجهات برمجة تطبيقات Google مع OAuth 2.0 لتطبيقات خادم الويب.

إنّ Google.Apis.Auth.AspNetCore3 هي المكتبة المقترَحة للاستخدام مع معظم سيناريوهات OAuth 2.0 المستنِدة إلى Google في تطبيقات ASP.NET Core 3. وتنفِّذ معالج مصادقة OpenIdConnect الخاص بـ Google. وهو متوافق مع المصادقة المتزايدة، ويحدّد IGoogleAuthProvider قابل للإدخال لتوفير بيانات اعتماد Google التي يمكن استخدامها مع Google APIs.

يصف هذا القسم كيفية ضبط Google.Apis.Auth.AspNetCore3 واستخدامه. يستنِد الرمز البرمجي المعروض هنا إلى Google.Apis.Auth.AspNetCore3.IntegrationTests، وهو تطبيق ASP.NET Core 3 عادي يعمل بكامل طاقته.

إذا أردت الاطّلاع على هذه المستندات كبرنامج تعليمي، ستحتاج إلى تطبيق ASP.NET Core 3 الخاص بك وإكمال هذه الخطوات كشرط أساسي.

المتطلبات الأساسية

  • ثبِّت حزمة Google.Apis.Auth.AspNetCore3.
  • نستخدم Google Drive API، لذلك عليك أيضًا تثبيت حزمة Google.Apis.Drive.v3.
  • أنشِئ مشروعًا على Google Cloud إذا لم يكن لديك مشروع حاليًا. اتّبِع هذه التعليمات للقيام بذلك. وسيكون هذا هو المشروع الذي تم تعريف تطبيقك عليه.
  • تأكَّد من تفعيل Google Drive API. لتفعيل واجهات برمجة التطبيقات، يُرجى اتّباع هذه التعليمات.
  • يمكنك إنشاء بيانات اعتماد التفويض التي من شأنها تحديد تطبيقك بالنسبة إلى Google. اتّبِع هذه التعليمات لإنشاء بيانات اعتماد التفويض وتنزيل ملف client_secrets.json. أمران مهمّان:
    • لاحظ أن نوع بيانات الاعتماد يجب أن يكون تطبيق ويب.
    • لتشغيل هذا التطبيق، معرّف الموارد المنتظم (URI) الوحيد لإعادة التوجيه الذي تحتاج إلى إضافته هو https://localhost:5001/signin-oidc.

اضبط تطبيقك لاستخدام Google.Apis.Auth.AspNetCore3.

تم ضبط Google.Apis.Auth.AspNetCore3 في فئة Startup أو بديل مشابه قد تستخدمه. يتم استخراج المقتطفات التالية من Startup.cs في مشروع Google.Apis.Auth.AspNetCore3.IntegrationTests.

  • أضِف الأمر التالي باستخدام الأمر إلى ملف Startup.cs.
    using Google.Apis.Auth.AspNetCore3;
  • في طريقة Startup.ConfigureServices، يمكنك إضافة الرمز التالي، ويمكنك تغيير العنصرَين النائبَين لـ Client-ID وسر العميل باستخدام القيم المضمّنة في ملف client_secrets.json. ويمكنك تحميل هذه القيم مباشرةً من ملف JSON أو يمكنك تخزينها بأي طريقة آمنة أخرى. يمكنك إلقاء نظرة على طريقة ClientInfo.Load في مشروع Google.Apis.Auth.AspNetCore3.IntegrationTests للاطّلاع على مثال حول كيفية تحميل هذه القيم مباشرةً من ملف JSON.
    public void ConfigureServices(IServiceCollection services)
    {
        ...
    
        // This configures Google.Apis.Auth.AspNetCore3 for use in this app.
        services
            .AddAuthentication(o =>
            {
                // This forces challenge results to be handled by Google OpenID Handler, so there's no
                // need to add an AccountController that emits challenges for Login.
                o.DefaultChallengeScheme = GoogleOpenIdConnectDefaults.AuthenticationScheme;
                // This forces forbid results to be handled by Google OpenID Handler, which checks if
                // extra scopes are required and does automatic incremental auth.
                o.DefaultForbidScheme = GoogleOpenIdConnectDefaults.AuthenticationScheme;
                // Default scheme that will handle everything else.
                // Once a user is authenticated, the OAuth2 token info is stored in cookies.
                o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            })
            .AddCookie()
            .AddGoogleOpenIdConnect(options =>
            {
                options.ClientId = {YOUR_CLIENT_ID};
                options.ClientSecret = {YOUR_CLIENT_SECRET};
            });
    }
          
  • في طريقة Startup.Configure، تأكّد من إضافة مكوّنات البرمجيات الوسيطة لتفويض ASP.NET Core 3 وتفويضها إلى مسار التعلّم، وكذلك إلى عمليات إعادة التوجيه باستخدام HTTPS:
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        ...
        app.UseHttpsRedirection();
        ...
    
        app.UseAuthentication();
        app.UseAuthorization();
    
        ...
    }
          

استخدام بيانات اعتماد المستخدم للوصول إلى Google APIs بالنيابة عنه

يمكنك الآن إضافة طرق إجراءات إلى وحدات التحكّم التي تتطلّب بيانات اعتماد المستخدم للوصول إلى Google APIs نيابةً عنها. يعرض المقتطف التالي كيفية إدراج الملفات في حساب Google Drive للمستخدم الذي تمت مصادقته. لاحظ شيئين في الغالب:

  • لا يحتاج المستخدم إلى المصادقة فحسب، بل يجب أيضًا أن يمنح النطاق https://www.googleapis.com/auth/drive.readonly لتطبيقك، الذي تحدده من خلال السمة GoogleScopedAuthorize.
  • نستخدم آلية تضمين التبعية العادية الخاصة بـ ASP.NET Core 3 لتلقّي IGoogleAuthProvider الذي نستخدمه للحصول على بيانات اعتماد المستخدم.

الرمز:

  • أضِف أولاً ما يلي باستخدام التوجيهات إلى وحدة التحكّم.
    using Google.Apis.Auth.AspNetCore3;
    using Google.Apis.Auth.OAuth2;
    using Google.Apis.Drive.v3;
    using Google.Apis.Services;
          
  • أضِف إجراء وحدة التحكّم على النحو التالي (وأضِفه مع عرض بسيط يتلقّى نموذج IList<string>):
    /// <summary>
    /// Lists the authenticated user's Google Drive files.
    /// Specifying the <see cref="GoogleScopedAuthorizeAttribute"> will guarantee that the code
    /// executes only if the user is authenticated and has granted the scope specified in the attribute
    /// to this application.
    /// </summary>
    /// <param name="auth">The Google authorization provider.
    /// This can also be injected on the controller constructor.</param>
    [GoogleScopedAuthorize(DriveService.ScopeConstants.DriveReadonly)]
    public async Task<IActionResult> DriveFileList([FromServices] IGoogleAuthProvider auth)
    {
        GoogleCredential cred = await auth.GetCredentialAsync();
        var service = new DriveService(new BaseClientService.Initializer
        {
            HttpClientInitializer = cred
        });
        var files = await service.Files.List().ExecuteAsync();
        var fileNames = files.Files.Select(x => x.Name).ToList();
        return View(fileNames);
    }
          

وهذه هي الأساسيات يمكنك إلقاء نظرة على HomeController.cs من مشروع Google.Apis.Auth.AspNetCore3.IntegrationTests لمعرفة كيفية تحقيق ذلك:

  • مصادقة المستخدم فقط، بدون نطاقات محددة
  • وظيفة تسجيل الخروج
  • تفويض إضافي عبر الرمز. لاحظ أن المقتطف أعلاه يعرض تفويضًا متزايدًا من خلال السمات.
  • فحص النطاقات الممنوحة حاليًا
  • فحص رموز الدخول وإعادة التحميل
  • فرض إعادة تحميل رمز الدخول لا داعي لتنفيذ هذا الإجراء بنفسك لأنّ Google.Apis.Auth.AspNetCore3 سيرصد ما إذا كانت صلاحية رمز الدخول قد انتهت أو أوشكت على الانتهاء وسيعيد تحميله تلقائيًا.

حساب الخدمة

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

يوقِّع تطبيق العميل الطلب للحصول على رمز دخول باستخدام مفتاح خاص تم تنزيله من وحدة التحكم في واجهة Google API. بعد إنشاء معرّف عميل جديد، عليك اختيار نوع التطبيق "حساب الخدمة" وبعد ذلك يمكنك تنزيل المفتاح الخاص. اطّلِع على نموذج حساب الخدمة باستخدام واجهة برمجة التطبيقات Google Plus API.

using System;
using System.Security.Cryptography.X509Certificates;

using Google.Apis.Auth.OAuth2;
using Google.Apis.Plus.v1;
using Google.Apis.Plus.v1.Data;
using Google.Apis.Services;

namespace Google.Apis.Samples.PlusServiceAccount
{
    /// <summary>
    /// This sample demonstrates the simplest use case for a Service Account service.
    /// The certificate needs to be downloaded from the Google API Console
    /// <see cref="https://console.cloud.google.com/">
    ///   "Create another client ID..." -> "Service Account" -> Download the certificate,
    ///   rename it as "key.p12" and add it to the project. Don't forget to change the Build action
    ///   to "Content" and the Copy to Output Directory to "Copy if newer".
    /// </summary>
    public class Program
    {
        // A known public activity.
        private static String ACTIVITY_ID = "z12gtjhq3qn2xxl2o224exwiqruvtda0i";

        public static void Main(string[] args)
        {
            Console.WriteLine("Plus API - Service Account");
            Console.WriteLine("==========================");

            String serviceAccountEmail = "SERVICE_ACCOUNT_EMAIL_HERE";

            var certificate = new X509Certificate2(@"key.p12", "notasecret", X509KeyStorageFlags.Exportable);

            ServiceAccountCredential credential = new ServiceAccountCredential(
               new ServiceAccountCredential.Initializer(serviceAccountEmail)
               {
                   Scopes = new[] { PlusService.Scope.PlusMe }
               }.FromCertificate(certificate));

            // Create the service.
            var service = new PlusService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credential,
                ApplicationName = "Plus API Sample",
            });

            Activity activity = service.Activities.Get(ACTIVITY_ID).Execute();
            Console.WriteLine("  Activity: " + activity.Object.Content);
            Console.WriteLine("  Video: " + activity.Object.Attachments[0].Url);

            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
        }
    }
}

ينشئ الرمز النموذجي الوارد أعلاه ServiceAccountCredential. تم ضبط النطاقات المطلوبة وهناك طلب بتاريخ FromCertificate، ما يؤدي إلى تحميل المفتاح الخاص من X509Certificate2 المحدَّد. وكما هي الحال في جميع نماذج الرموز الأخرى، يتم ضبط بيانات الاعتماد على HttpClientInitializer.