OAuth 2.0

يصف هذا المستند بروتوكول OAuth 2.0، ووقت استخدامه، وكيفية الحصول على معرّفات العملاء، وكيفية استخدامه مع مكتبة Google API Client لنظام التشغيل .NET.

بروتوكول OAuth 2.0

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

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

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

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

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

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

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

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

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

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

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

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

تُشبه ServiceAccountCredential UserCredential، ولكنها تؤدي غرضًا مختلفًا. يتوافق Google OAuth 2.0 مع التفاعلات من خادم إلى خادم، مثل التفاعلات بين تطبيق الويب و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 APIs استخدام 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_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 Core.3 Core وتفويض مكوّنات البرمجيات الوسيطة على مسار التعلّم، بالإضافة إلى عمليات إعادة توجيه 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 سيرصد ما إذا كان رمز الدخول قد انتهت صلاحيته أو اقترب من انتهاء صلاحيته وسيعيد تحميله تلقائيًا.

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

تتيح Google APIs استخدام OAuth 2.0 لتطبيقات خادم الويب. لتنفيذ الرمز التالي بنجاح، يجب أولاً إضافة عنوان URL لإعادة التوجيه إلى مشروعك في وحدة التحكم في واجهة Google API. وبما أنّك ستستخدم FlowMetadata وإعداداته التلقائية، اضبط معرّف الموارد المنتظم (URI) الخاص بإعادة التوجيه على your_site/AuthCallback/IndexAsync.

للعثور على معرِّفات الموارد المنتظمة (URI) الخاصة ببيانات إعادة التوجيه لبيانات اعتماد OAuth 2.0، نفِّذ ما يلي:

  1. افتح صفحة بيانات الاعتماد في وحدة تحكّم واجهة برمجة التطبيقات.
  2. أنشِئ بيانات اعتماد OAuth 2.0 من خلال النقر على إنشاء بيانات اعتماد &gt؛ معرّف عميل OAuth، إذا لم تكن قد فعلت ذلك من قبل.
  3. بعد إنشاء بيانات الاعتماد، يمكنك عرض عناوين URL لإعادة التوجيه أو تعديلها من خلال النقر على معرِّف العميل (لتطبيق ويب) في قسم أرقام تعريف برامج OAuth 2.0.

بعد إنشاء مشروع تطبيق ويب جديد في بيئة التطوير المتكاملة (IDE)، أضِف حزمة Google.Apis NuGet المناسبة لـ Drive أو YouTube أو الخدمة الأخرى التي تريد استخدامها. وبعد ذلك، أضِف حزمة Google.Apis.Auth.MVC. يوضح الرمز التالي تطبيق ASP.NET MVC الذي يطلب خدمة من واجهة برمجة تطبيقات Google.

  1. يمكنك إضافة تنفيذ FlowMetadata الخاص بك.
    using System;
    using System.Web.Mvc;
    
    using Google.Apis.Auth.OAuth2;
    using Google.Apis.Auth.OAuth2.Flows;
    using Google.Apis.Auth.OAuth2.Mvc;
    using Google.Apis.Drive.v2;
    using Google.Apis.Util.Store;
    
    namespace Google.Apis.Sample.MVC4
    {
        public class AppFlowMetadata : FlowMetadata
        {
            private static readonly IAuthorizationCodeFlow flow =
                new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
                    {
                        ClientSecrets = new ClientSecrets
                        {
                            ClientId = "PUT_CLIENT_ID_HERE",
                            ClientSecret = "PUT_CLIENT_SECRET_HERE"
                        },
                        Scopes = new[] { DriveService.Scope.Drive },
                        DataStore = new FileDataStore("Drive.Api.Auth.Store")
                    });
    
            public override string GetUserId(Controller controller)
            {
                // In this sample we use the session to store the user identifiers.
                // That's not the best practice, because you should have a logic to identify
                // a user. You might want to use "OpenID Connect".
                // You can read more about the protocol in the following link:
                // https://developers.google.com/accounts/docs/OAuth2Login.
                var user = controller.Session["user"];
                if (user == null)
                {
                    user = Guid.NewGuid();
                    controller.Session["user"] = user;
                }
                return user.ToString();
    
            }
    
            public override IAuthorizationCodeFlow Flow
            {
                get { return flow; }
            }
        }
    }
          

    FlowMetadata هي فئة مجرّدة تتضمّن منطقك الخاص لاسترداد معرّف المستخدم وIAuthorizationCodeFlow الذي تستخدمه.

    في رمز الرمز أعلاه، يتم إنشاء GoogleAuthorizationCodeFlow جديد باستخدام النطاقات المناسبة وأسرار العميل ومخزن البيانات. يمكنك إضافة عملية التنفيذ الخاصة بـ IDataStore، على سبيل المثال، يمكنك كتابة طلب يستخدم EntityFramework.

  2. نفِّذ وحدة التحكُّم الخاصة بك التي تستخدم خدمة Google API. يستخدم النموذج التالي DriveService:
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Web.Mvc;
    
    using Google.Apis.Auth.OAuth2.Mvc;
    using Google.Apis.Drive.v2;
    using Google.Apis.Services;
    
    using Google.Apis.Sample.MVC4;
    
    namespace Google.Apis.Sample.MVC4.Controllers
    {
        public class HomeController : Controller
        {
            public async Task<ActionResult> IndexAsync(CancellationToken cancellationToken)
            {
                var result = await new AuthorizationCodeMvcApp(this, new AppFlowMetadata()).
                    AuthorizeAsync(cancellationToken);
    
                if (result.Credential != null)
                {
                    var service = new DriveService(new BaseClientService.Initializer
                        {
                            HttpClientInitializer = result.Credential,
                            ApplicationName = "ASP.NET MVC Sample"
                        });
    
                    // YOUR CODE SHOULD BE HERE..
                    // SAMPLE CODE:
                    var list = await service.Files.List().ExecuteAsync();
                    ViewBag.Message = "FILE COUNT IS: " + list.Items.Count();
                    return View();
                }
                else
                {
                    return new RedirectResult(result.RedirectUri);
                }
            }
        }
    }
          
  3. نفِّذ وحدة التحكُّم في معاودة الاتصال. يجب أن يكون التنفيذ مشابهًا لما يلي:
    using Google.Apis.Sample.MVC4;
    
    namespace Google.Apis.Sample.MVC4.Controllers
    {
        public class AuthCallbackController : Google.Apis.Auth.OAuth2.Mvc.Controllers.AuthCallbackController
        {
            protected override Google.Apis.Auth.OAuth2.Mvc.FlowMetadata FlowData
            {
                get { return new AppFlowMetadata(); }
            }
        }
    }
          

حساب الخدمة

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

يوقّع تطبيق العميل طلب رمز الدخول باستخدام مفتاح خاص تم تنزيله من وحدة تحكم 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.