این سند توضیح میدهد که برنامههای وب سرور چگونه از «کتابخانههای کارخواه Google API» یا نقاط پایانی Google OAuth 2.0 برای پیادهسازی مجوز OAuth 2.0 جهت دسترسی به Google API استفاده میکنند.
OAuth 2.0 به کاربران اجازه میدهد دادههای خاصی را با برنامهای همرسانی کنند و درعینحال نامهای کاربری، گذرواژهها، و سایر اطلاعاتشان را خصوصی نگه دارند. برای مثال، یک برنامه میتواند از OAuth 2.0 برای دریافت اجازه از کاربران برای ذخیره فایلها در Google Drive آنها استفاده کند.
این جریان OAuth 2.0 بهطور خاص برای صدور مجوز کاربر است. این جریان برای برنامههایی طراحی شده است که میتوانند اطلاعات محرمانه را ذخیره کنند و وضعیت را حفظ کنند. یک برنامه کارساز وب که بهدرستی مجوز گرفته باشد میتواند درحالیکه کاربر با برنامه تعامل دارد یا پساز اینکه کاربر برنامه را ترک کرد، به میانای برنامهسازی کاربردی دسترسی پیدا کند.
برنامههای سرور وب اغلب از حسابهای سرویس نیز برای صدور مجوز درخواستهای API استفاده میکنند، بهویژه هنگام فراخوانی Cloud API برای دسترسی به دادههای مبتنی بر پروژه بهجای دادههای مختص کاربر. برنامههای وب سرور میتوانند از حسابهای خدمات همراه با مجوز کاربر استفاده کنند.
کتابخانههای مشتری
نمونههای مختص زبان در این صفحه از کتابخانههای کارخواه Google API برای پیادهسازی مجوز OAuth 2.0 استفاده میکنند. برای اجرای نمونه کدها، ابتدا باید کتابخانه مشتری را برای زبان خود نصب کنید.
وقتی از «کتابخانه کارخواه Google API» برای مدیریت جریان OAuth 2.0 برنامهتان استفاده میکنید، کتابخانه کارخواه کنشهای زیادی را انجام میدهد که درغیراینصورت برنامه باید خودش آنها را مدیریت کند. برای مثال، این خطمشی تعیین میکند که برنامه چه زمانی میتواند از کدهای دسترسی ذخیرهشده استفاده کند یا آنها را بازآوری کند و همچنین چه زمانی برنامه باید دوباره رضایت کاربر را کسب کند. کتابخانه کارخواه همچنین نشانیهای وب بازهدایت صحیح تولید میکند و به پیادهسازی گردانندههای بازهدایت که کدهای مجوز را با کدهای دسترسی معاوضه میکنند کمک میکند.
«کتابخانههای کارخواه Google API» برای برنامههای سمت سرور برای زبانهای زیر دردسترس است:
پیشنیازها
فعال کردن میاناهای برنامهسازی کاربردی برای پروژه
هر برنامهای که میاناهای برنامهسازی کاربردی Google را فراخوانی میکند باید آن میاناهای برنامهسازی کاربردی را در «کنسول میانای برنامهسازی کاربردی» فعال کند.
برای فعال کردن میانای برنامهسازی کاربردی برای پروژهتان:
- کتابخانه میانای برنامهسازی کاربردی را در «کنسول Google API» باز کنید.
- درصورت درخواست، پروژهای را انتخاب کنید یا پروژه جدیدی ایجاد کنید.
- «کتابخانه میانای برنامهسازی کاربردی» همه میاناهای برنامهسازی کاربردی دردسترس را براساس خانواده محصول و محبوبیت گروهبندی میکند. اگر API موردنظرتان برای فعال کردن در فهرست دیده نمیشود، از جستجو برای پیدا کردن آن استفاده کنید، یا روی مشاهده همه در خانواده محصولی که به آن تعلق دارد کلیک کنید.
- میانای برنامهسازی کاربردی موردنظرتان را برای فعال کردن انتخاب کنید، سپس روی دکمه فعال کردن کلیک کنید.
- اگر درخواست شد، صدور صورتحساب را فعال کنید.
- درصورت درخواست، «شرایط خدمات» API را بخوانید و بپذیرید.
ایجاد اطلاعات کاربری مجوز
هر برنامهای که از OAuth 2.0 برای دسترسی به Google APIs استفاده میکند باید اعتبارنامه مجوزدهی داشته باشد که برنامه را برای سرور OAuth 2.0 Google شناسایی کند. مراحل زیر نحوه ایجاد اطلاعات کاربری برای پروژه را توضیح میدهد. سپس برنامههایتان میتوانند از این اطلاعات اعتباری برای دسترسی به میاناهای برنامهسازی کاربردیای که برای آن پروژه فعال کردهاید استفاده کنند.
- به صفحه کارخواهان بروید.
- روی ایجاد مشتری کلیک کنید.
- نوع برنامه برنامه وب را انتخاب کنید.
- فرم را پر کنید و روی ایجاد کلیک کنید. برنامههایی که از زبانها و چارچوبهایی
مثل PHP، Java، Python، Ruby، و NET .استفاده میکنند باید URIهای بازهدایت مجاز را مشخص کنند. URIهای
هدایت نقاط پایانی هستند که سرور OAuth 2.0 میتواند پاسخها را به آنها ارسال کند. این
نقطههای پایانی باید از قوانین اعتبارسنجی Google پیروی کنند.
برای آزمایش، میتوانید URIهایی را مشخص کنید که به ماشین محلی ارجاع میدهند، مانند
http://localhost:8080. همه مثالهای این سند ازhttp://localhost:8080بهعنوان URI هدایت استفاده میکنند.توصیه میکنیم پایانههای اصالتسنجی برنامهتان را طوری طراحی کنید که برنامهتان کدهای مجوز را درمعرض منابع دیگر در صفحه قرار ندهد.
پساز ایجاد اطلاعات کاربری، فایل client_secret.json را از «کنسول API» بارگیری کنید. فایل را بهطور ایمن در مکانی ذخیره کنید که فقط برنامه شما بتواند به آن دسترسی داشته باشد.
شناسایی کردن دامنههای دسترسی
گسترهها به برنامه شما امکان میدهند فقط به منابعی که نیاز دارد دسترسی داشته باشد و همچنین به کاربران امکان میدهند میزان دسترسیای را که به برنامه شما اعطا میکنند کنترل کنند. بنابراین، ممکن است بین تعداد گسترههای درخواستی و احتمال دریافت رضایت کاربر رابطه معکوس وجود داشته باشد.
قبلاز شروع پیادهسازی مجوز OAuth 2.0، توصیه میکنیم دامنههایی را که برنامهتان برای دسترسی به آنها به اجازه نیاز دارد شناسایی کنید.
همچنین توصیه میکنیم که برنامهتان ازطریق فرایند مجوزدهی فزاینده برای دسترسی به دامنههای مجوزدهی درخواست کند، که در آن برنامهتان برای دسترسی به دادههای کاربر در بافت درخواست میکند. این روال مطلوب به کاربران کمک میکند راحتتر متوجه شوند چرا برنامهتان به دسترسیای که درخواست میکند نیاز دارد.
سند OAuth 2.0 API Scopes حاوی فهرست کاملی از دامنههایی است که ممکن است برای دسترسی به Google API استفاده کنید.
الزامات مختص زبان
برای اجرای هریک از نمونه کدهای موجود در این سند، به «حساب Google»، دسترسی به اینترنت، و مرورگر وب نیاز دارید. اگر از یکی از کتابخانههای کارخواه API استفاده میکنید، الزامات مختص زبان را نیز در بخشهای زیر ببینید.
PHP
برای اجرای نمونههای کد PHP در این سند، به موارد زیر نیاز دارید:
- PHP 8.0 یا بالاتر با میانای خط فرمان (CLI) و افزونه JSON نصبشده.
- ابزار مدیریت وابستگی Composer.
-
کتابخانه کارخواهان میاناهای برنامهسازی کاربردی Google برای PHP:
composer require google/apiclient:^2.15.0
برای اطلاعات بیشتر، کتابخانه کارخواه Google APIs برای PHP را ببینید.
Python
برای اجرای نمونههای کد Python در این سند، به موارد زیر نیاز دارید:
- پایتون ۳.۷ یا بالاتر
- ابزار مدیریت بسته pip.
- نسخه Google APIs Client Library for Python 2.0:
pip install --upgrade google-api-python-client
google-auth،google-auth-oauthlib، وgoogle-auth-httplib2برای صدور مجوز کاربر.pip install --upgrade google-auth google-auth-oauthlib google-auth-httplib2
- چارچوب برنامه وب Flask Python.
pip install --upgrade flask
- کتابخانه HTTP
requests.pip install --upgrade requests
اگر نمیتوانید Python را ارتقا دهید، یادداشت انتشار کتابخانه کارخواه Python در Google API و راهنمای انتقال مربوطه را مرور کنید.
Ruby
برای اجرای نمونههای کد Ruby در این سند، به موارد زیر نیاز دارید:
- Ruby نسخه ۲.۶ یا بالاتر
-
کتابخانه Google Auth برای Ruby:
gem install googleauth
-
کتابخانههای کارخواه برای Google APIs در Drive و «تقویم»:
gem install google-apis-drive_v3 google-apis-calendar_v3
-
چارچوب برنامه وب Sinatra Ruby.
gem install sinatra
Node.js
برای اجرای نمونه کدهای Node.js در این سند، به موارد زیر نیاز دارید:
- نسخه پشتیبانی بلندمدت نگهداری، نسخه پشتیبانی بلندمدت فعال، یا نسخه فعلی Node.js.
-
کارخواه Node.js میاناهای برنامهسازی کاربردی Google:
npm install googleapis crypto express express-session
HTTP/REST
برای اینکه بتوانید مستقیماً نقاط پایانی OAuth 2.0 را فراخوانی کنید، نیازی به نصب هیچ کتابخانهای ندارید.
دریافت کدهای دسترسی OAuth 2.0
مراحل زیر نشان میدهد که برنامه شما چگونه با سرور OAuth 2.0 Google تعامل میکند تا رضایت کاربر را برای انجام درخواست میانای برنامهسازی کاربردی ازطرف کاربر دریافت کند. برنامه شما باید این رضایت را داشته باشد تا بتواند درخواست Google API را که نیاز به مجوز کاربر دارد اجرا کند.
فهرست زیر این مراحل را بهطور خلاصه نشان میدهد:
- برنامه شما اجازههای موردنیازش را شناسایی میکند.
- برنامه شما کاربر را بههمراه فهرست اجازههای درخواستشده به Google هدایت میکند.
- کاربر تصمیم میگیرد که اجازهها را به برنامه شما اعطا کند یا نه.
- برنامه شما متوجه میشود که کاربر چه تصمیمی گرفته است.
- اگر کاربر اجازههای درخواستشده را اعطا کند، برنامه شما توکنهای موردنیاز برای ارسال درخواستهای میانای برنامهسازی کاربردی ازطرف کاربر را بازیابی میکند.
مرحله ۱: تنظیم پارامترهای مجوز
اولین قدم شما ایجاد درخواست مجوز است. این درخواست پارامترهایی را تنظیم میکند که برنامه شما را شناسایی میکند و اجازههایی را تعریف میکند که از کاربر خواسته میشود به برنامه شما اعطا کند.
- اگر از کتابخانه کارخواه Google برای اصالتسنجی و مجوز OAuth 2.0 استفاده میکنید، شیئی را ایجاد و پیکربندی میکنید که این پارامترها را تعریف میکند.
- اگر مستقیماً نقطه پایانی Google OAuth 2.0 را فراخوانی کنید، نشانی وب تولید خواهید کرد و پارامترها را در آن نشانی وب تنظیم خواهید کرد.
برگههای زیر پارامترهای مجوز پشتیبانیشده را برای برنامههای سرور وب تعریف میکنند. نمونههای مختص زبان همچنین نشان میدهند که چگونه از کتابخانه کارخواه یا کتابخانه مجوز برای پیکربندی شیئی که آن پارامترها را تنظیم میکند استفاده کنید:
PHP
تکهکد زیر شیء Google\Client() را ایجاد میکند که پارامترهای درخواست مجوز را تعریف میکند.
آن شیء از اطلاعات فایل client_secret.json شما برای شناسایی برنامهتان استفاده میکند. (برای اطلاعات بیشتر درباره آن فایل، به ایجاد اعتبارنامه مجوز مراجعه کنید.) این شیء همچنین دامنههایی را که برنامهتان برای دسترسی به آنها درخواست اجازه میکند و نشانی وب نقطه پایانی اصالتسنجی برنامهتان را که پاسخ سرور OAuth 2.0 از Google را مدیریت میکند، شناسایی میکند. درنهایت، کد پارامترهای اختیاری access_type و
include_granted_scopes را تنظیم میکند.
برای مثال، این کد درخواست دسترسی آفلاین و فقط خواندنی به فراداده Google Drive و رویدادهای «تقویم» کاربر را میدهد:
use Google\Client; $client = new Client(); // Required, call the setAuthConfig function to load authorization credentials from // client_secret.json file. $client->setAuthConfig('client_secret.json'); // Required, to set the scope value, call the addScope function $client->addScope([Google\Service\Drive::DRIVE_METADATA_READONLY, Google\Service\Calendar::CALENDAR_READONLY]); // Required, call the setRedirectUri function to specify a valid redirect URI for the // provided client_id $client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php'); // Recommended, offline access will give you both an access and refresh token so that // your app can refresh the access token without user interaction. $client->setAccessType('offline'); // Recommended, call the setState function. Using a state value can increase your assurance that // an incoming connection is the result of an authentication request. $client->setState($sample_passthrough_value); // Optional, if your application knows which user is trying to authenticate, it can use this // parameter to provide a hint to the Google Authentication Server. $client->setLoginHint('hint@example.com'); // Optional, call the setPrompt function to set "consent" will prompt the user for consent $client->setPrompt('consent'); // Optional, call the setIncludeGrantedScopes function with true to enable incremental // authorization $client->setIncludeGrantedScopes(true);
Python
تکهکد زیر از واحد google-auth-oauthlib.flow برای ساختن
درخواست مجوز استفاده میکند.
کد یک شیء Flow میسازد که برنامه شما را بااستفاده از اطلاعات فایل client_secret.json که پساز ایجاد کردن اطلاعات کاربری مجوز بارگیری کردهاید شناسایی میکند. آن شیء همچنین دامنههایی را که برنامه شما برای دسترسی به آنها درخواست اجازه میکند و نشانی وب نقطه پایانی اصالتسنجی برنامهتان را که پاسخ سرور OAuth 2.0 Google را مدیریت میکند شناسایی میکند. درنهایت، کد
پارامترهای اختیاری access_type و include_granted_scopes را تنظیم میکند.
برای مثال، این کد درخواست دسترسی آفلاین و فقط خواندنی به فراداده Google Drive و رویدادهای «تقویم» کاربر را میدهد:
import google.oauth2.credentials import google_auth_oauthlib.flow # Required, call the from_client_secrets_file method to retrieve the client ID from a # client_secret.json file. The client ID (from that file) and access scopes are required. (You can # also use the from_client_config method, which passes the client configuration as it originally # appeared in a client secrets file but doesn't access the file itself.) flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file('client_secret.json', scopes=['https://www.googleapis.com/auth/drive.metadata.readonly', 'https://www.googleapis.com/auth/calendar.readonly']) # Required, indicate where the API server will redirect the user after the user completes # the authorization flow. The redirect URI is required. The value must exactly # match one of the authorized redirect URIs for the OAuth 2.0 client, which you # configured in the API Console. If this value doesn't match an authorized URI, # you will get a 'redirect_uri_mismatch' error. flow.redirect_uri = 'https://www.example.com/oauth2callback' # Generate URL for request to Google's OAuth 2.0 server. # Use kwargs to set optional request parameters. authorization_url, state = flow.authorization_url( # Recommended, enable offline access so that you can refresh an access token without # re-prompting the user for permission. Recommended for web server apps. access_type='offline', # Optional, enable incremental authorization. Recommended as a best practice. include_granted_scopes='true', # Optional, if your application knows which user is trying to authenticate, it can use this # parameter to provide a hint to the Google Authentication Server. login_hint='hint@example.com', # Optional, set prompt to 'consent' will prompt the user for consent prompt='consent')
Ruby
از فایل client_secrets.json که ایجاد کردهاید برای پیکربندی شیء کارخواه در برنامهتان استفاده کنید. وقتی شیء کارخواه را پیکربندی میکنید، دامنههایی را که برنامهتان برای دسترسی نیاز دارد، بههمراه نشانی وب نقطه پایانی اصالتسنجی برنامهتان که پاسخ سرور OAuth 2.0 را مدیریت میکند، مشخص میکنید.
برای مثال، این کد درخواست دسترسی آفلاین و فقط خواندنی به متاداده Google Drive و رویدادهای «تقویم» کاربر را میدهد:
require 'googleauth' require 'googleauth/web_user_authorizer' require 'googleauth/stores/redis_token_store' require 'google/apis/drive_v3' require 'google/apis/calendar_v3' # Required, call the from_file method to retrieve the client ID from a # client_secret.json file. client_id = Google::Auth::ClientId.from_file('/path/to/client_secret.json') # Required, scope value # Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar. scope = ['Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY', 'Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY'] # Required, Authorizers require a storage instance to manage long term persistence of # access and refresh tokens. token_store = Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new) # Required, indicate where the API server will redirect the user after the user completes # the authorization flow. The redirect URI is required. The value must exactly # match one of the authorized redirect URIs for the OAuth 2.0 client, which you # configured in the API Console. If this value doesn't match an authorized URI, # you will get a 'redirect_uri_mismatch' error. callback_uri = '/oauth2callback' # To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI # from the client_secret.json file. To get these credentials for your application, visit # https://console.cloud.google.com/apis/credentials. authorizer = Google::Auth::WebUserAuthorizer.new(client_id, scope, token_store, callback_uri)
برنامه شما از شیء کارخواه برای انجام عملیات OAuth 2.0، مانند تولید نشانیهای وب درخواست مجوز و اعمال کدهای دسترسی به درخواستهای HTTP استفاده میکند.
Node.js
تکهکد زیر شیء google.auth.OAuth2 را ایجاد میکند که پارامترهای درخواست مجوز را تعریف میکند.
آن شیء از اطلاعات فایل client_secret.json شما برای شناسایی برنامهتان استفاده میکند. برای درخواست اجازه از کاربر برای بازیابی کد دسترسی، او را به صفحه رضایت هدایت میکنید. برای ایجاد نشانی وب صفحه رضایت:
const {google} = require('googleapis'); const crypto = require('crypto'); const express = require('express'); const session = require('express-session'); /** * To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI * from the client_secret.json file. To get these credentials for your application, visit * https://console.cloud.google.com/apis/credentials. */ const oauth2Client = new google.auth.OAuth2( YOUR_CLIENT_ID, YOUR_CLIENT_SECRET, YOUR_REDIRECT_URL ); // Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar. const scopes = [ 'https://www.googleapis.com/auth/drive.metadata.readonly', 'https://www.googleapis.com/auth/calendar.readonly' ]; // Generate a secure random state value. const state = crypto.randomBytes(32).toString('hex'); // Store state in the session req.session.state = state; // Generate a url that asks permissions for the Drive activity and Google Calendar scope const authorizationUrl = oauth2Client.generateAuthUrl({ // 'online' (default) or 'offline' (gets refresh_token) access_type: 'offline', /** Pass in the scopes array defined above. * Alternatively, if only one scope is needed, you can pass a scope URL as a string */ scope: scopes, // Enable incremental authorization. Recommended as a best practice. include_granted_scopes: true, // Include the state parameter to reduce the risk of CSRF attacks. state: state });
نکته مهم - refresh_token فقط در اولین صدور مجوز برگردانده میشود. جزئیات بیشتر
اینجا.
HTTP/REST
نقطه پایانی Google OAuth 2.0 در https://accounts.google.com/o/oauth2/v2/auth است. این
نقطه پایانی فقط ازطریق HTTPS قابلدسترسی است. اتصالهای HTTP ساده رد میشوند.
سرور مجوز Google از پارامترهای رشته پُرسمان زیر برای برنامههای سرور وب پشتیبانی میکند:
| پارامترها | |||||||
|---|---|---|---|---|---|---|---|
client_id |
الزامی
شناسه کارخواه برای برنامه شما. این مقدار را میتوانید در صفحه «کارخواهها» در «کنسول Cloud» پیدا کنید. |
||||||
redirect_uri |
الزامی
تعیین میکند که سرور API کاربر را پساز تکمیل جریان مجوزدهی به کجا هدایت کند. این مقدار باید دقیقاً با یکی از URIهای هدایت مجاز برای کارخواه OAuth 2.0 که در صفحه «کارخواهها» در Cloud Console کارخواه پیکربندی کردهاید مطابقت داشته باشد. اگر این مقدار با
URI تغییرمسیر مجاز برای توجه داشته باشید که طرح |
||||||
response_type |
الزامی
تعیین میکند که آیا نقطه پایان Google OAuth 2.0 کد مجوز برمیگرداند یا نه. برای برنامههای کارساز وب، مقدار پارامتر را روی |
||||||
scope |
الزامی
فهرستی از دامنهها که با فاصله از هم جدا شدهاند و منابعی را که برنامه شما میتواند ازطرف کاربر به آنها دسترسی داشته باشد شناسایی میکند. این مقادیر به صفحه رضایت که Google به کاربر نمایش میدهد اطلاعرسانی میکند. گسترهها به برنامه شما امکان میدهند فقط به منابعی که نیاز دارد درخواست دسترسی بدهد و درعینحال به کاربران امکان میدهند میزان دسترسیای را که به برنامه شما اعطا میکنند کنترل کنند. بنابراین، رابطهای معکوس بین تعداد دامنههای درخواستی و احتمال کسب رضایت کاربر وجود دارد. توصیه میکنیم برنامهتان هر زمان که ممکن بود دسترسی به گسترههای مجوز را در بافت درخواست کند. با درخواست دسترسی به دادههای کاربر در بافت، بااستفاده از احراز هویت فزاینده، به کاربران کمک میکنید متوجه شوند چرا برنامهتان به دسترسیای که درخواست میکند نیاز دارد. |
||||||
access_type |
توصیهشده
نشان میدهد که آیا برنامه شما میتواند کد دسترسی را وقتی کاربر در مرورگر حضور ندارد بازآوری کند یا نه. مقادیر پارامتر معتبر عبارتند از اگر برنامه شما نیاز دارد کد دسترسی را وقتی کاربر در مرورگر حضور ندارد بازآوری کند،
مقدار را روی |
||||||
state |
توصیهشده
هر مقدار رشتهای را که برنامهتان برای حفظ وضعیت بین درخواست مجوز شما و پاسخ سرور مجوز استفاده میکند مشخص میکند.
سرور مقدار دقیقی را که بهعنوان جفت میتوانید از این پارامتر برای اهداف مختلفی استفاده کنید، ازجمله هدایت کاربر به
منبع صحیح در برنامهتان، ارسال عدد یکبارمصرف، و کاهش جعل درخواست
بینسایتی. ازآنجاییکه |
||||||
include_granted_scopes |
اختیاری
برنامهها را قادر میسازد تا از مجوز افزایشی برای درخواست دسترسی به دامنههای اضافی در بافت استفاده کنند. اگر مقدار این پارامتر را روی |
||||||
enable_granular_consent |
اختیاری
پیشفرضها به وقتی Google اجازههای ریزدانه را برای برنامهای فعال میکند، این پارامتر دیگر تأثیری نخواهد داشت. |
||||||
login_hint |
اختیاری
اگر برنامه شما میداند کدام کاربر درحال تلاش برای اصالتسنجی است، میتواند از این پارامتر برای ارائه راهنمایی به «سرور اصالتسنجی Google» استفاده کند. سرور از این راهنمایی برای ساده کردن جریان ورود به سیستم استفاده میکند، یا با پیشپر کردن فیلد ایمیل در فرم ورود به سیستم یا با انتخاب جلسه چندورودی مناسب. مقدار پارامتر را روی نشانی ایمیل یا شناسه |
||||||
prompt |
اختیاری
فهرست پیاموارههای حساس به حروف بزرگ و کوچک که با فاصله از هم جدا شدهاند تا به کاربر ارائه شوند. اگر این پارامتر را مشخص نکنید، فقط اولین باری که پروژه شما درخواست دسترسی میکند، از کاربر درخواست میشود. برای اطلاعات بیشتر، درخواست مجدد رضایت را ببینید. مقادیر ممکن عبارتاند از:
|
||||||
مرحله ۲: هدایت کردن به سرور OAuth 2.0 در Google
کاربر را به سرور OAuth 2.0 Google هدایت کنید تا فرایند اصالتسنجی و صدور مجوز را آغاز کند. معمولاً این اتفاق زمانی میافتد که برنامه شما برای اولینبار نیاز به دسترسی به دادههای کاربر دارد. درصورت مجوز افزایشی، این مرحله زمانی نیز رخ میدهد که برنامه شما برای اولینبار نیاز به دسترسی به منابع اضافی دارد که اجازه دسترسی به آنها را ندارد.
PHP
- نشانی وبی برای درخواست دسترسی از سرور Google OAuth 2.0 ایجاد کنید:
$auth_url = $client->createAuthUrl(); - هدایت کاربر به
$auth_url:header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
Python
این مثال نشان میدهد که چگونه میتوان کاربر را بااستفاده از چارچوب برنامه وب Flask به نشانی وب اصالتسنجی هدایت کرد:
return flask.redirect(authorization_url)
Ruby
- نشانی وبی برای درخواست دسترسی از سرور Google OAuth 2.0 ایجاد کنید:
auth_uri = authorizer.get_authorization_url(request: request)
- کاربر را به
auth_uriهدایت کنید.
Node.js
-
از نشانی وب تولیدشده
authorizationUrlاز روش مرحله ۱generateAuthUrlبرای درخواست دسترسی از سرور Google OAuth 2.0 استفاده کنید. -
کاربر را به
authorizationUrlهدایت کنید.res.redirect(authorizationUrl);
HTTP/REST
نمونه هدایت به سرور مجوز Google
نمونه نشانی وب در زیر نشان داده شده است، با شکست خط و فاصله برای خوانایی.
https://accounts.google.com/o/oauth2/v2/auth? scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly%20https%3A//www.googleapis.com/auth/calendar.readonly& access_type=offline& include_granted_scopes=true& response_type=code& state=state_parameter_passthrough_value& redirect_uri=https%3A//developers.google.com/oauthplayground& client_id=client_id
پساز ایجاد نشانی وب درخواست، کاربر را به آن هدایت کنید.
سرور OAuth 2.0 در Google کاربر را اصالتسنجی میکند و موافقت کاربر را برای دسترسی برنامه شما به دامنههای درخواستی دریافت میکند. پاسخ بااستفاده از نشانی وب هدایت مجددی که مشخص کردهاید به برنامهتان ارسال میشود.
مرحله ۳: Google از کاربر درخواست رضایت میکند
در این مرحله، کاربر تصمیم میگیرد که دسترسی درخواستی را به برنامه شما اعطا کند یا نه. در این مرحله، Google پنجره رضایتی را نمایش میدهد که نام برنامه شما و سرویسهای Google API را که برنامه برای دسترسی به آنها با اطلاعات کاربری مجاز کاربر درخواست اجازه میکند و خلاصهای از دامنههای دسترسی که باید اعطا شود نشان میدهد. سپس کاربر میتواند با اعطای دسترسی به یک یا چند دامنه درخواستشده توسط برنامه شما موافقت کند یا درخواست را رد کند.
برنامه شما در این مرحله نیازی به انجام کاری ندارد زیرا منتظر پاسخ از سرور OAuth 2.0 Google است که نشان میدهد آیا دسترسی اعطا شده است یا خیر. آن پاسخ در مرحله زیر توضیح داده شده است.
خطاها
درخواستهای ارسالشده به نقطه پایانی مجوز OAuth 2.0 Google ممکن است بهجای جریانهای اصالتسنجی و مجوز موردانتظار، پیامهای خطای سَمت کاربر نمایش دهند. کدهای خطای رایج و راهحلهای پیشنهادی عبارتاند از:
admin_policy_enforced
«حساب Google» بهدلیل خطمشیهای سرپرست Google Workspace نمیتواند یک یا چند دامنه درخواستی را مجاز کند. برای کسب اطلاعات بیشتر درباره اینکه سرپرست چگونه میتواند دسترسی به همه دامنهها یا دامنههای حساس و محدودشده را تا زمانی که دسترسی صریحاً به شناسه کارخواه OAuth شما اعطا شود محدود کند، به مقاله راهنمای سرپرست Google Workspace با عنوان کنترل اینکه کدام برنامههای داخلی و طرف سوم به دادههای Google Workspace دسترسی داشته باشند مراجعه کنید.
disallowed_useragent
نقطه پایان مجوز در نماینده کاربر جاسازیشدهای نمایش داده میشود که خطمشیهای OAuth 2.0 Google آن را مجاز نمیداند.
توسعهدهندگان iOS و macOS ممکن است هنگام باز کردن درخواستهای مجوز در
WKWebView با این خطا مواجه شوند.
توسعهدهندگان باید بهجای آن از کتابخانههای iOS مانند
ورود به سیستم با Google برای iOS یا
AppAuth برای iOS
از بنیاد OpenID استفاده کنند.
توسعهدهندگان وب ممکن است با این خطا مواجه شوند وقتی یک برنامه iOS یا macOS یک پیوند وب عمومی را در یک نماینده کاربر جاسازیشده باز میکند و کاربر از سایت شما به نقطه پایانی مجوز OAuth 2.0 Google هدایت میشود. توسعهدهندگان باید اجازه دهند
پیوندهای عمومی در کنترلکننده پیوند پیشفرض سیستمعامل باز شود،
که شامل هر دو
کنترلکننده پیوندهای جامع
یا برنامه مرورگر پیشفرض میشود. کتابخانه SFSafariViewController
نیز گزینهای پشتیبانیشده است.
org_internal
شناسه کارخواه OAuth در درخواست بخشی از پروژهای است که دسترسی به «حسابهای Google» را در سازمان Google Cloud خاصی محدود میکند. برای اطلاعات بیشتر درباره این گزینه پیکربندی، به بخش نوع کاربر در مقاله راهنمای «راهاندازی صفحه موافقت OAuth» مراجعه کنید.
invalid_client
رمز کارخواه OAuth نادرست است. پیکربندی کارخواه OAuth، ازجمله شناسه کارخواه و رمز استفادهشده برای این درخواست را مرور کنید.
deleted_client
کارخواه OAuth که برای درخواست استفاده میشود حذف شده است. حذف میتواند بهصورت دستی یا خودکار درصورت استفاده نشدن از مشتری انجام شود. مشتریان حذفشده را میتوان ظرف ۳۰ روز پساز حذف بازیابی کرد. بیشتر بدانید.
invalid_grant
هنگام بازآوری کد دسترسی یا استفاده از مجوز افزایشی، ممکن است کد منقضی شده باشد یا نامعتبر شده باشد. دوباره کاربر را اصالتسنجی کنید و برای دریافت کردن توکنهای جدید از کاربر رضایت بخواهید. اگر همچنان این خطا را میبینید، مطمئن شوید که برنامهتان بهدرستی پیکربندی شده است و از کدها و پارامترهای صحیح در درخواستتان استفاده میکنید. درغیراینصورت، ممکن است حساب کاربر حذف یا غیرفعال شده باشد.
redirect_uri_mismatch
redirect_uri ارسالشده در درخواست مجوز با نشانی وب هدایت مجاز برای شناسه کارخواه OAuth مطابقت ندارد. URIهای هدایت مجاز را در
صفحه «کارخواهها» در Google Cloud Console
مرور کنید.
پارامتر redirect_uri ممکن است به جریان OAuth خارجاز باند (OOB) اشاره داشته باشد که منسوخ شده است و دیگر پشتیبانی نمیشود. برای بهروزرسانی ادغام، به
راهنمای
انتقال مراجعه کنید.
invalid_request
مشکلی در درخواست شما وجود داشت. این مشکل ممکن است به چند دلیل باشد:
- درخواست بهدرستی قالببندی نشده بود
- درخواست فاقد پارامترهای الزامی بود
- درخواست از روش صدور مجوزی استفاده میکند که Google از آن پشتیبانی نمیکند. تأیید کنید که یکپارچهسازی OAuth شما از روش یکپارچهسازی توصیهشده استفاده میکند
مرحله ۴: رسیدگی به پاسخ سرور OAuth 2.0
سرور OAuth 2.0 بااستفاده از نشانی وب مشخصشده در درخواست، به درخواست دسترسی برنامهتان پاسخ میدهد.
اگر کاربر درخواست دسترسی را تأیید کند، پاسخ حاوی کد مجوز خواهد بود. اگر کاربر درخواست را تأیید نکند، پاسخ حاوی پیام خطا خواهد بود. کد مجوز یا پیام خطایی که به سرور وب برگردانده میشود در رشته پُرسمان نشان داده میشود، همانطور که در مثالهای زیر نشان داده شده است:
پاسخ خطا:
https://oauth2.example.com/auth?error=access_denied
پاسخ کد مجوز:
https://oauth2.example.com/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7
نمونه پاسخ سرور OAuth 2.0
میتوانید این جریان را با کلیک کردن روی نمونه نشانی وب زیر آزمایش کنید، که درخواست دسترسی فقط خواندنی برای مشاهده فراداده فایلها در Google Drive شما و دسترسی فقط خواندنی برای مشاهده رویدادهای «تقویم Google» شما را دارد:
https://accounts.google.com/o/oauth2/v2/auth? scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly%20https%3A//www.googleapis.com/auth/calendar.readonly& access_type=offline& include_granted_scopes=true& response_type=code& state=state_parameter_passthrough_value& redirect_uri=https%3A//developers.google.com/oauthplayground& client_id=client_id
پساز تکمیل جریان OAuth 2.0، مرورگرتان شما را به OAuth 2.0 Playground هدایت میکند که ابزاری برای آزمایش جریانهای OAuth است. خواهید دید که OAuth 2.0 Playground بهطور خودکار کد مجوز را ضبط کرده است.
مرحله ۵: معاوضه کد مجوز با ژتونهای بازآوری و دسترسی
پساز اینکه سرور وب کد مجوز را دریافت کرد، میتواند کد مجوز را با کد دسترسی مبادله کند.
PHP
برای تبدیل کد مجوز به کد دسترسی، از روش
fetchAccessTokenWithAuthCode استفاده کنید:
$access_token = $client->fetchAccessTokenWithAuthCode($_GET['code']);Python
در صفحه بازگشت تماس، از کتابخانه google-auth برای تأیید پاسخ سرور مجوزدهی استفاده کنید. سپس، از روش flow.fetch_token برای مبادله کد مجوز
در آن پاسخ با کد دسترسی استفاده کنید:
state = flask.session['state'] flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file( 'client_secret.json', scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'], state=state) flow.redirect_uri = flask.url_for('oauth2callback', _external=True) authorization_response = flask.request.url flow.fetch_token(authorization_response=authorization_response) # Store the credentials in browser session storage, but for security: client_id, client_secret, # and token_uri are instead stored only on the backend server. credentials = flow.credentials flask.session['credentials'] = { 'token': credentials.token, 'refresh_token': credentials.refresh_token, 'granted_scopes': credentials.granted_scopes}
Ruby
در صفحه callback، از کتابخانه googleauth برای تأیید پاسخ سرور مجوزدهی استفاده کنید. از روش authorizer.handle_auth_callback_deferred برای ذخیره کردن کد مجوز و هدایت مجدد به نشانی وبی که در ابتدا درخواست مجوز کرده بود استفاده کنید. این کار
تبادل کد را با ذخیره موقت نتایج در جلسه کاربر بهتعویق میاندازد.
target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request) redirect target_url
Node.js
برای تبدیل کد مجوز به کد دسترسی، از روش getToken
استفاده کنید:
const url = require('url'); // Receive the callback from Google's OAuth 2.0 server. app.get('/oauth2callback', async (req, res) => { let q = url.parse(req.url, true).query; if (q.error) { // An error response e.g. error=access_denied console.log('Error:' + q.error); } else if (q.state !== req.session.state) { //check state value console.log('State mismatch. Possible CSRF attack'); res.end('State mismatch. Possible CSRF attack'); } else { // Get access and refresh tokens (if access_type is offline) let { tokens } = await oauth2Client.getToken(q.code); oauth2Client.setCredentials(tokens); });
HTTP/REST
برای معاوضه کد مجوز با کد دسترسی، نقطه پایانی
https://oauth2.googleapis.com/token را فراخوانی کنید و پارامترهای زیر را تنظیم کنید:
| فیلدها | |
|---|---|
client_id |
شناسه کارخواه بهدستآمده از صفحه کارخواهها در «کنسول Cloud». |
client_secret |
اختیاری
رمز کارخواه بهدستآمده از صفحه کارخواهها در «کنسول Cloud». |
code |
کد مجوز برگشتی از درخواست اولیه. |
grant_type |
همانطور که در مشخصات OAuth 2.0 تعریف شده است، مقدار این فیلد باید روی authorization_code تنظیم شود. |
redirect_uri |
یکی از URIهای هدایت فهرستشده برای پروژهتان در
صفحه کارخواهها در Cloud Console
برای
client_id دادهشده. |
هرچند استفاده از DPoP اختیاری است، اما برای افزایش امنیت توصیه میشود. امنیت DPoP به محدود بودن کلید خصوصی به یک دستگاه بستگی دارد؛ توصیه میکنیم آن را بهگونهای ذخیره کنید که نتوان آن را از دستگاه کپی کرد، مثلاً بااستفاده از TPM، Secure Enclave، یا دیگر محلهای ذخیره کلید با پشتیبانی سختافزاری. برای استفاده از DPoP، برنامه شما باید برای هر درخواست به نقطه پایانی رمزه، یک JWT اثبات DPoP جدید و منحصربهفرد تولید کند و آن را بهعنوان سرایند درخواست HTTP اضافه کند.
| سرایند | الزامی | شرح |
|---|---|---|
DPoP |
اختیاری | اثبات DPoP یک JWT است که
مالکیت کلید خصوصی را اثبات میکند. این یک سرایند است، نه پارامتر. درصورت ارائه، نشانهای برگرداندهشده
به این کلید محدود میشوند. برای هر درخواست باید مدرک جدید و منحصربهفردی تولید شود و باید شامل ادعاهای htm (روش HTTP) و htu (شناسه منبع یکسان HTTP) باشد که با درخواست مطابقت داشته باشد. |
قطعه کد زیر یک درخواست نمونه را نشان میدهد:
POST /token HTTP/1.1 Host: oauth2.googleapis.com Content-Type: application/x-www-form-urlencoded DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6Ik\ VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR\ nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JE\ QSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiItQndDM0VTYzZhY2MybFRjIiwiaHRtIj\ oiUE9TVCIsImh0dSI6Imh0dHBzOi8vc2VydmVyLmV4YW1wbGUuY29tL3Rva2VuIiwia\ WF0IjoxNTYyMjYyNjE2fQ.2-GxA6T8lP4vfrg8v-FdWP0A0zdrj8igiMLvqRMUvwnQg\ 4PtFLbdLXiOSsX0x7NVY-FNyJK70nfbV37xRZT3Lg code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7& client_id=your_client_id& redirect_uri=https%3A//developers.google.com/oauthplayground& grant_type=authorization_code
ساختن اثبات DPoP
مراحل زیر نحوه ساختن اثبات DPoP بااستفاده از OpenSSL از خط فرمان را نشان میدهد:
- جفت کلید EC P-256 تولید کنید:
openssl ecparam -name prime256v1 -genkey -noout -out dpop_private.pem openssl ec -in dpop_private.pem -pubout -out dpop_public.pem
- ایجاد سرصفحه DPoP:
سرصفحه باید شامل ادعاهای
typ،alg، وjwk(کلید عمومی) باشد. مقادیرxوyمختصات کدبندیشده Base64Url کلید عمومی EC شما هستند. این JSON را با Base64Url کدبندی کنید:{ "typ":"dpop+jwt", "alg":"ES256", "jwk": { "kty":"EC", "x":"YOUR_PUBLIC_KEY_X", "y":"YOUR_PUBLIC_KEY_Y", "crv":"P-256" } } - ایجاد بار داده DPoP:
بار داده باید شامل
jti(شناسه یکتا برای درخواست)،htm(روش HTTP، مثلاًPOST)،htu(HTTP URI، مثلاًhttps://oauth2.googleapis.com/token)، وiat(زمان صدور) باشد. اگر در پاسخ به درخواست قبلی، یک nonce از سرور در سرصفحهDPoP-Nonceدریافت کردهاید، باید آن مقدار nonce را در ادعایnonceاضافه کنید. ادعای nonce برای تبادل کد مجوز اختیاری است و فقط زمانی استفاده میشود که سرصفحه DPoP-Nonce قبلاً دریافت شده باشد. این JSON را با Base64Url کدبندی کنید:{ "jti":"JTI_VALUE", "htm":"POST", "htu":"https://oauth2.googleapis.com/token", "iat":YOUR_JWT_ISSUED_TIME, "nonce":"SERVER_PROVIDED_NONCE" }مقدار
jtiبه نوع تبادل بستگی دارد:- برای تبادل کد مجوز،
jtiباید درهمسازی SHA256 کدبندیشده با Base64Url کد مجوز باشد:"jti":"BASE64URL(SHA256(AUTHORIZATION_CODE))". - برای تبادل ژتون بازآوری،
jtiباید یک شناسه یکتا برای هر درخواست باشد:"jti":"YOUR_UNIQUE_PER_REQUEST_IDENTIFIER".
- برای تبادل کد مجوز،
- امضا کردن مدرک:
سرصفحه و بار داده کدگذاریشده را با نقطه (
.) بههم متصل کنید، سپس نتیجه را با کلید خصوصیتان بااستفاده از ES256 امضا کنید. توجه داشته باشید که JWS الزام میکند که امضا در قالب خامR | Sبههمپیوسته باشد (۶۴ بایت برای P-256). اگر مستقیماً از OpenSSL استفاده میکنید، باید امضای پیشفرض ASN.1 DER-encoded را به این قالب خام تبدیل کنید.
تبادل موفق با پاسخ 200 OK حاوی کدها نشان داده میشود. اگر درطول تبادل از اثبات DPoP معتبری استفاده شود، کد بازآوری که Google برمیگرداند به کلید شما محدود به DPoP خواهد بود، اما کدهای دسترسی محدود به DPoP نخواهند بود. کدهای دسترسی بهجای DPoP، token_type مربوط به Bearer را حفظ خواهند کرد.
علاوهبراین، Google سرایند HTTP DPoP-Nonce را در پاسخ برمیگرداند.
کارخواه شما باید این نانس را ذخیره موقت کند و آن را در ادعای nonce اثبات DPoP
در درخواستهای بعدی (مانند هنگام تبادل یک ژتون بازآوری برای یک کد دسترسی جدید، یا هنگام
فراخوانی میاناهای برنامهسازی کاربردی محافظتشده با DPoP) قرار دهد. بااستفاده از این عدد یکبارمصرف زودتر صادرشده، میتوانید از یک خطای رفتوبرگشت اضافی (use_dpop_nonce) در درخواست بعدیتان جلوگیری کنید.
برای درخواستهای تبادل ژتون که با ژتونهای بازآوری محدودشده با DPoP انجام میشود، باید اثباتهای DPoP ارائه شود.
تبادل ناموفق زمانی رخ میدهد که سرایند DPoP
درصورت انتظار وجود نداشته باشد، نامعتبر باشد، یا اگر اثبات از کلیدی متفاوت با کلید
محدودشده به کد استفاده کند. در این موارد، سرور خطای
400 Bad Request را برمیگرداند.
اگر اثبات DPoP دارای ادعاهای htm یا htu نامطابق، iat منقضیشده، jti دوباره استفادهشده، یا امضای نامعتبر باشد، Google کد خطای invalid_dpop_proof را برمیگرداند.
اگر به یک عدد یکباراستفاده DPoP نیاز باشد، مثلاً درطول تبادل ژتون بازآوری، و اثبات DPoP فاقد ادعای nonce باشد، یا مقدار عدد یکباراستفاده برای سرور غیرقابلقبول باشد (مثلاً منقضی شده باشد، قبلاً استفاده شده باشد، یا نادرست باشد)، Google کد خطای use_dpop_nonce را بههمراه سرایند HTTP DPoP-Nonce حاوی عدد یکباراستفاده جدیدی که میتوانید در درخواست بعدی استفاده کنید برمیگرداند.
سایر خطاها ممکن است invalid_grant را برگرداند.
Google با برگرداندن یک شیء JSON که حاوی یک کد دسترسی کوتاهمدت و یک کد بازآوری است، به این درخواست پاسخ میدهد.
توجه داشته باشید که ژتون بازآوری فقط درصورتی برگردانده میشود که برنامهتان پارامتر access_type را در درخواست اولیه به سرور مجوز Google روی offline تنظیم کرده باشد.
پاسخ حاوی فیلدهای زیر است:
| فیلدها | |
|---|---|
access_token |
نشانهای که برنامه شما برای صدور مجوز درخواست Google API ارسال میکند. |
expires_in |
مدتزمان باقیمانده کد دسترسی برحسب ثانیه. |
refresh_token |
نشانهای که میتوانید از آن برای دریافت کد دسترسی جدید استفاده کنید. ژتونهای بازآوری تا زمانی معتبر هستند که
کاربر دسترسی را لغو کند یا ژتون بازآوری منقضی شود. اگر از DPoP استفاده شده باشد،
ژتون بازآوری به کلید خصوصی استفادهشده برای امضای اثبات DPoP محدود میشود.
مجدداً، این فیلد فقط درصورتی در این پاسخ وجود دارد که پارامتر access_type را در درخواست اولیه به سرور مجوزدهی Google روی offline تنظیم کرده باشید.
|
refresh_token_expires_in |
طول عمر باقیمانده ژتون بازآوری به ثانیه. این مقدار فقط زمانی تنظیم میشود که کاربر دسترسی زماندار اعطا کند. |
scope |
دامنههای دسترسی اعطاشده توسط access_token بهصورت فهرستی از رشتههای حساس به حروف بزرگ و کوچک که با فاصله از هم جدا شدهاند بیان میشود. |
token_type |
نوع کد برگرداندهشده. این مقدار همیشه Bearer است، حتی وقتی از DPoP استفاده میشود. |
تکهکد زیر نمونهای از سرایندها و متن پاسخ موفقیتآمیز را هنگام استفاده از DPoP نشان میدهد:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
DPoP-Nonce: AN3XwJjZsjnb0ZuWkRlek8QU7wY-Zhf-5IP6tO0tORz0KgtDT1Bo8FX-w4nz3r5lnepI
{
"access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
"expires_in": 3920,
"token_type": "Bearer",
"scope": "https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/calendar.readonly",
"refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}خطاها
هنگام معاوضه کد مجوز با کد دسترسی، ممکن است بهجای پاسخ موردانتظار با خطای زیر مواجه شوید. کدهای خطای رایج و راهحلهای پیشنهادی در این بخش فهرست شدهاند.
invalid_grant
کد تأییدیه ارائهشده نامعتبر است یا قالب آن نادرست است. با بازراهاندازی فرایند OAuth، کد جدیدی درخواست کنید تا دوباره از کاربر درخواست رضایت شود.
مرحله ۶: بررسی کردن گسترههایی که کاربران اعطا کردهاند
هنگام درخواست چندین اجازه (دامنه)، ممکن است کاربران به برنامه شما اجازه دسترسی به همه آنها را ندهند. برنامه شما باید تأیید کند که کدام دامنهها واقعاً اعطا شدهاند و موقعیتهایی را که برخیاز اجازهها رد شدهاند بهخوبی مدیریت کند، معمولاً با غیرفعال کردن ویژگیهایی که به آن دامنههای ردشده متکی هستند.
بااینحال، چند استثنا وجود دارد. برنامههای Google Workspace Enterprise با واگذاری اختیارات در سراسر دامنه، یا برنامههایی که بهعنوان مورد اعتماد علامتگذاری شدهاند، صفحه رضایت اجازههای ریزدانه را دور میزنند. برای این برنامهها، کاربران صفحه رضایت اجازه جزئی را نخواهند دید. درعوض، برنامهتان یا همه گسترههای درخواستشده را دریافت میکند یا هیچکدام را دریافت نمیکند.
برای اطلاعات دقیقتر، نحوه مدیریت اجازههای ریزدانه را ببینید.
PHP
برای بررسی اینکه کاربر کدام دامنهها را اعطا کرده است، از روش getGrantedScope() استفاده کنید:
// Space-separated string of granted scopes if it exists, otherwise null. $granted_scopes = $client->getOAuth2Service()->getGrantedScope(); // Determine which scopes user granted and build a dictionary $granted_scopes_dict = [ 'Drive' => str_contains($granted_scopes, Google\Service\Drive::DRIVE_METADATA_READONLY), 'Calendar' => str_contains($granted_scopes, Google\Service\Calendar::CALENDAR_READONLY) ];
Python
شیء credentials برگرداندهشده دارای ویژگی granted_scopes است،
که فهرستی از دامنههایی است که کاربر به برنامه شما اعطا کرده است.
credentials = flow.credentials flask.session['credentials'] = { 'token': credentials.token, 'refresh_token': credentials.refresh_token, 'granted_scopes': credentials.granted_scopes}
تابع زیر بررسی میکند که کاربر کدام دامنهها را به برنامه شما اعطا کرده است.
def check_granted_scopes(credentials): features = {} if 'https://www.googleapis.com/auth/drive.metadata.readonly' in credentials['granted_scopes']: features['drive'] = True else: features['drive'] = False if 'https://www.googleapis.com/auth/calendar.readonly' in credentials['granted_scopes']: features['calendar'] = True else: features['calendar'] = False return features
Ruby
هنگام درخواست چند گستره بهطور همزمان، بررسی کنید کدام گسترهها ازطریق
ویژگی scope شیء credentials اعطا شدهاند.
# User authorized the request. Now, check which scopes were granted. if credentials.scope.include?(Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY) # User authorized read-only Drive activity permission. # Calling the APIs, etc else # User didn't authorize read-only Drive activity permission. # Update UX and application accordingly end # Check if user authorized Calendar read permission. if credentials.scope.include?(Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY) # User authorized Calendar read permission. # Calling the APIs, etc. else # User didn't authorize Calendar read permission. # Update UX and application accordingly end
Node.js
هنگام درخواست چند گستره بهطور همزمان، بررسی کنید کدام گسترهها ازطریق
ویژگی scope شیء tokens اعطا شدهاند.
// User authorized the request. Now, check which scopes were granted. if (tokens.scope.includes('https://www.googleapis.com/auth/drive.metadata.readonly')) { // User authorized read-only Drive activity permission. // Calling the APIs, etc. } else { // User didn't authorize read-only Drive activity permission. // Update UX and application accordingly } // Check if user authorized Calendar read permission. if (tokens.scope.includes('https://www.googleapis.com/auth/calendar.readonly')) { // User authorized Calendar read permission. // Calling the APIs, etc. } else { // User didn't authorize Calendar read permission. // Update UX and application accordingly }
HTTP/REST
برای بررسی اینکه آیا کاربر به برنامه شما اجازه دسترسی به دامنه خاصی را داده است یا نه،
فیلد scope را در پاسخ کد دسترسی بررسی کنید. حوزههای دسترسی اعطاشده توسط
access_token که بهصورت فهرستی از رشتههای حساس به حروف بزرگ و کوچک و جداشده با فاصله بیان شده است.
برای مثال، پاسخ کد دسترسی نمونه زیر نشان میدهد که کاربر به برنامه شما اجازه دسترسی به فعالیت Drive فقط خواندنی و اجازههای رویدادهای «تقویم» را داده است:
{ "access_token": "1/fFAGRNJru1FTz70BzhT3Zg", "expires_in": 3920, "token_type": "Bearer", "scope": "https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/calendar.readonly", "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI" }
فراخوانی میاناهای برنامهسازی کاربردی Google
PHP
با تکمیل مراحل زیر، از کد دسترسی برای فراخوانی Google APIs استفاده کنید:
- اگر لازم است کد دسترسی را برای شیء
Google\Clientجدیدی اعمال کنید — برای مثال، اگر کد دسترسی را در جلسه کاربر ذخیره کردهاید — از روشsetAccessTokenاستفاده کنید:$client->setAccessToken($access_token); - یک شیء سرویس برای API که میخواهید فراخوانی کنید بسازید. با ارائه شیء
Google\Clientمجاز به سازنده برای API که میخواهید فراخوانی کنید، شیء سرویس میسازید. برای مثال، برای فراخوانی Drive API:$drive = new Google\Service\Drive($client); - بااستفاده از
میانای ارائهشده توسط شیء سرویس، درخواستهایی به سرویس میانای برنامهسازی کاربردی ارسال کنید.
برای مثال، برای فهرست کردن فایلها در Google Drive کاربر اصالتسنجیشده:
$files = $drive->files->listFiles(array());
Python
پساز دریافت کد دسترسی، برنامهتان میتواند از آن کد برای صدور مجوز درخواستهای API ازطرف حساب کاربری یا حساب سرویس مشخصی استفاده کند. از اطلاعات اعتباری مجوز مختص کاربر برای ساختن شیء سرویس برای API که میخواهید فراخوانی کنید استفاده کنید، و سپس از آن شیء برای ایجاد درخواستهای API مجاز استفاده کنید.
- یک شیء سرویس برای API که میخواهید فراخوانی کنید بسازید. با فراخوانی روش
buildکتابخانهgoogleapiclient.discoveryبا نام و نسخه API و اطلاعات کاربری کاربر، یک شیء سرویس میسازید: برای مثال، برای فراخوانی نسخه ۳ Drive API:from googleapiclient.discovery import build drive = build('drive', 'v2', credentials=credentials)
- بااستفاده از میانای ارائهشده توسط شیء سرویس، درخواستهایی به سرویس میانای برنامهسازی کاربردی ارسال کنید.
برای مثال، برای فهرست کردن فایلها در Google Drive کاربر اصالتسنجیشده:
files = drive.files().list().execute()
Ruby
پساز دریافت کد دسترسی، برنامهتان میتواند از آن کد برای ایجاد درخواستهای میانای برنامهسازی کاربردی ازطرف حساب کاربری یا حساب خدمات مشخصی استفاده کند. از اطلاعات اعتباری مجوز مختص کاربر برای ساختن شیء سرویس برای API که میخواهید فراخوانی کنید استفاده کنید، و سپس از آن شیء برای ایجاد درخواستهای API مجاز استفاده کنید.
- یک شیء سرویس برای API که میخواهید فراخوانی کنید بسازید.
برای مثال، برای فراخوانی نسخه ۳ از Drive API:
drive = Google::Apis::DriveV3::DriveService.new
- اطلاعات اعتباری را در سرویس تنظیم کنید:
drive.authorization = credentials
- بااستفاده از میانای ارائهشده توسط شیء سرویس، درخواستهایی به سرویس میانای برنامهسازی کاربردی ارسال کنید.
برای مثال، برای فهرست کردن فایلها در Google Drive کاربر اصالتسنجیشده:
files = drive.list_files
یا اینکه مجوز میتواند بهصورت روشبهروش با ارائه پارامتر options به روش ارائه شود:
files = drive.list_files(options: { authorization: credentials })
Node.js
پساز دریافت کد دسترسی و تنظیم آن روی شیء OAuth2، از شیء
برای فراخوانی Google APIs استفاده کنید. برنامه شما میتواند از آن کد برای مجاز کردن درخواستهای API ازطرف
حساب کاربری یا حساب سرویس مشخصی استفاده کند. یک شیء سرویس برای API که میخواهید فراخوانی کنید بسازید.
برای مثال، کد زیر از Google Drive API برای فهرست کردن نام فایلها در Drive کاربر استفاده میکند.
const { google } = require('googleapis'); // Example of using Google Drive API to list filenames in user's Drive. const drive = google.drive('v3'); drive.files.list({ auth: oauth2Client, pageSize: 10, fields: 'nextPageToken, files(id, name)', }, (err1, res1) => { if (err1) return console.log('The API returned an error: ' + err1); const files = res1.data.files; if (files.length) { console.log('Files:'); files.map((file) => { console.log(`${file.name} (${file.id})`); }); } else { console.log('No files found.'); } });
HTTP/REST
پساز اینکه برنامهتان کد دسترسی را دریافت کرد، میتوانید از این کد برای برقراری تماس با Google API ازطرف حساب کاربری مشخصی استفاده کنید، بهشرطی که دامنه(های) دسترسی موردنیاز API اعطا شده باشد. برای انجام این کار،
کد دسترسی را با گنجاندن پارامتر پُرسمان access_token یا مقدار سرایند HTTP Authorization Bearer در درخواست به میانای برنامهسازی کاربردی بگنجانید. درصورت امکان،
سرایند HTTP ترجیح داده میشود، زیرا رشتههای پرسمان معمولاً در گزارشهای سرور قابلمشاهده هستند. در اکثر موارد، میتوانید از کتابخانه کارخواه برای راهاندازی تماسهایتان با Google API استفاده کنید (برای مثال، هنگام فراخوانی Drive Files API).
میتوانید همه میاناهای برنامهسازی کاربردی Google را امتحان کنید و دامنههای آنها را در OAuth 2.0 Playground مشاهده کنید.
نمونههای HTTP GET
فراخوانی نقطه پایانی
drive.files
(Drive Files API) بااستفاده از سرایند HTTP
Authorization: Bearer ممکن است شبیه به این باشد. توجه داشته باشید که باید کد دسترسی خودتان را مشخص کنید:
GET /drive/v2/files HTTP/1.1 Host: www.googleapis.com Authorization: Bearer access_token
در اینجا فراخوانی برای همان میانای برنامهسازی کاربردی برای کاربر اصالتسنجیشده بااستفاده از پارامتر رشته پُرسمان access_token ارائه شده است:
GET https://www.googleapis.com/drive/v2/files?access_token=access_token
curl مثال
میتوانید این فرمانها را با برنامه خط فرمان curl آزمایش کنید. در اینجا
نمونهای آورده شده است که از گزینه سرایند HTTP (ترجیحی) استفاده میکند:
curl -H "Authorization: Bearer access_token" https://www.googleapis.com/drive/v2/files
یا، بهعنوان گزینه جایگزین، گزینه پارامتر رشته پُرسمان:
curl https://www.googleapis.com/drive/v2/files?access_token=access_token
نمونه کامل
مثال زیر فهرستی از فایلها را در Google Drive کاربر با قالب JSON چاپ میکند، پساز اینکه کاربر اصالتسنجی میکند و به برنامه اجازه میدهد به فراداده Drive کاربر دسترسی داشته باشد.
PHP
برای اجرای این نمونه:
- در «کنسول API»، نشانی وب دستگاه محلی را به
فهرست نشانیهای وب تغییرمسیر اضافه کنید. برای مثال،
http://localhost:8080را اضافه کنید. - دایرکتوری جدیدی ایجاد کنید و به آن بروید. برای مثال:
mkdir ~/php-oauth2-example cd ~/php-oauth2-example
- کتابخانه کارخواه Google API
برای PHP را بااستفاده از Composer نصب کنید:
composer require google/apiclient:^2.15.0
- فایلهای
index.phpوoauth2callback.phpرا با محتوای زیر بسازید. - نمونه را با سرور وب آزمایشی توکار PHP اجرا کنید:
php -S localhost:8080 ~/php-oauth2-example
index.php
<?php require_once __DIR__.'/vendor/autoload.php'; session_start(); $client = new Google\Client(); $client->setAuthConfig('client_secret.json'); // User granted permission as an access token is in the session. if (isset($_SESSION['access_token']) && $_SESSION['access_token']) { $client->setAccessToken($_SESSION['access_token']); // Check if user granted Drive permission if ($_SESSION['granted_scopes_dict']['Drive']) { echo "Drive feature is enabled."; echo "</br>"; $drive = new Drive($client); $files = array(); $response = $drive->files->listFiles(array()); foreach ($response->files as $file) { echo "File: " . $file->name . " (" . $file->id . ")"; echo "</br>"; } } else { echo "Drive feature is NOT enabled."; echo "</br>"; } // Check if user granted Calendar permission if ($_SESSION['granted_scopes_dict']['Calendar']) { echo "Calendar feature is enabled."; echo "</br>"; } else { echo "Calendar feature is NOT enabled."; echo "</br>"; } } else { // Redirect users to outh2call.php which redirects users to Google OAuth 2.0 $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php'; header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL)); } ?>
oauth2callback.php
<?php require_once __DIR__.'/vendor/autoload.php'; session_start(); $client = new Google\Client(); // Required, call the setAuthConfig function to load authorization credentials from // client_secret.json file. $client->setAuthConfigFile('client_secret.json'); $client->setRedirectUri('http://' . $_SERVER['HTTP_HOST']. $_SERVER['PHP_SELF']); // Required, to set the scope value, call the addScope function. $client->addScope([Google\Service\Drive::DRIVE_METADATA_READONLY, Google\Service\Calendar::CALENDAR_READONLY]); // Enable incremental authorization. Recommended as a best practice. $client->setIncludeGrantedScopes(true); // Recommended, offline access will give you both an access and refresh token so that // your app can refresh the access token without user interaction. $client->setAccessType("offline"); // Generate a URL for authorization as it doesn't contain code and error if (!isset($_GET['code']) && !isset($_GET['error'])) { // Generate and set state value $state = bin2hex(random_bytes(16)); $client->setState($state); $_SESSION['state'] = $state; // Generate a url that asks permissions. $auth_url = $client->createAuthUrl(); header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL)); } // User authorized the request and authorization code is returned to exchange access and // refresh tokens. if (isset($_GET['code'])) { // Check the state value if (!isset($_GET['state']) || $_GET['state'] !== $_SESSION['state']) { die('State mismatch. Possible CSRF attack.'); } // Get access and refresh tokens (if access_type is offline) $token = $client->fetchAccessTokenWithAuthCode($_GET['code']); /** Save access and refresh token to the session variables. * ACTION ITEM: In a production app, you likely want to save the * refresh token in a secure persistent storage instead. */ $_SESSION['access_token'] = $token; $_SESSION['refresh_token'] = $client->getRefreshToken(); // Space-separated string of granted scopes if it exists, otherwise null. $granted_scopes = $client->getOAuth2Service()->getGrantedScope(); // Determine which scopes user granted and build a dictionary $granted_scopes_dict = [ 'Drive' => str_contains($granted_scopes, Google\Service\Drive::DRIVE_METADATA_READONLY), 'Calendar' => str_contains($granted_scopes, Google\Service\Calendar::CALENDAR_READONLY) ]; $_SESSION['granted_scopes_dict'] = $granted_scopes_dict; $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/'; header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL)); } // An error response e.g. error=access_denied if (isset($_GET['error'])) { echo "Error: ". $_GET['error']; } ?>
Python
این نمونه از چارچوب Flask استفاده میکند. این برنامه
یک برنامه وب را در http://localhost:8080 اجرا میکند که به شما امکان میدهد جریان OAuth 2.0 را
آزمایش کنید. اگر به آن نشانی وب بروید، باید پنج پیوند ببینید:
- فراخوانی Drive API: این پیوند به صفحهای اشاره میکند که تلاش میکند نمونه درخواست API را اجرا کند، اگر کاربران اجازه را اعطا کرده باشند. درصورت لزوم، جریان صدور مجوز را شروع میکند. اگر موفقیتآمیز باشد، صفحه پاسخ میانای برنامهسازی کاربردی را نمایش میدهد.
- صفحه ساختگی برای فراخوانی Calendar API: این پیوند به صفحه ساختگیای اشاره میکند که تلاش میکند درخواست نمونه Calendar API را درصورت اعطای اجازه ازسوی کاربران اجرا کند. درصورت لزوم، جریان صدور مجوز را شروع میکند. اگر موفقیتآمیز باشد، صفحه پاسخ میانای برنامهسازی کاربردی را نمایش میدهد.
- آزمایش مستقیم جریان اصالتسنجی: این پیوند به صفحهای اشاره میکند که تلاش میکند کاربر را ازطریق جریان اصالتسنجی ارسال کند. برنامه برای ارسال درخواستهای مجاز API ازطرف کاربر، اجازه درخواست میکند.
- لغو اعتبارنامه فعلی: این پیوند به صفحهای اشاره میکند که اجازههایی را که کاربر قبلاً به برنامه اعطا کرده است لغو میکند.
- پاک کردن اطلاعات اعتباری جلسه Flask: این پیوند اطلاعات اعتباری مجوز را که در جلسه Flask ذخیره شده است پاک میکند. این کار به شما امکان میدهد ببینید اگر کاربری که قبلاً به برنامهتان اجازه داده است بخواهد درخواست میانای برنامهسازی کاربردی را در جلسه جدیدی اجرا کند چه اتفاقی میافتد. همچنین به شما امکان میدهد پاسخ میانای برنامهسازی کاربردی را که برنامهتان درصورت لغو اجازههای اعطاشده به برنامهتان توسط کاربر دریافت میکند ببینید، و برنامهتان همچنان تلاش میکند درخواستی را با کد دسترسی لغوشده مجاز کند.
# -*- coding: utf-8 -*- import os import flask import json import requests import google.oauth2.credentials import google_auth_oauthlib.flow import googleapiclient.discovery # This variable specifies the name of a file that contains the OAuth 2.0 # information for this application, including its client_id and client_secret. CLIENT_SECRETS_FILE = "client_secret.json" # The OAuth 2.0 access scope allows for access to the # authenticated user's account and requires requests to use an SSL connection. SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly', 'https://www.googleapis.com/auth/calendar.readonly'] API_SERVICE_NAME = 'drive' API_VERSION = 'v2' app = flask.Flask(__name__) # Note: A secret key is included in the sample so that it works. # If you use this code in your application, replace this with a truly secret # key. See https://flask.palletsprojects.com/quickstart/#sessions. app.secret_key = 'REPLACE ME - this value is here as a placeholder.' @app.route('/') def index(): return print_index_table() @app.route('/drive') def drive_api_request(): if 'credentials' not in flask.session: return flask.redirect('authorize') features = flask.session['features'] if features['drive']: # Load client secrets from the server-side file. with open(CLIENT_SECRETS_FILE, 'r') as f: client_config = json.load(f)['web'] # Load user-specific credentials from browser session storage. session_credentials = flask.session['credentials'] # Reconstruct the credentials object. credentials = google.oauth2.credentials.Credentials( refresh_token=session_credentials.get('refresh_token'), scopes=session_credentials.get('granted_scopes'), token=session_credentials.get('token'), client_id=client_config.get('client_id'), client_secret=client_config.get('client_secret'), token_uri=client_config.get('token_uri')) drive = googleapiclient.discovery.build( API_SERVICE_NAME, API_VERSION, credentials=credentials) files = drive.files().list().execute() # Save credentials back to session in case access token was refreshed. flask.session['credentials'] = credentials_to_dict(credentials) return flask.jsonify(**files) else: # User didn't authorize read-only Drive activity permission. return '<p>Drive feature is not enabled.</p>' @app.route('/calendar') def calendar_api_request(): if 'credentials' not in flask.session: return flask.redirect('authorize') features = flask.session['features'] if features['calendar']: # User authorized Calendar read permission. # Calling the APIs, etc. return ('<p>User granted the Google Calendar read permission. '+ 'This sample code does not include code to call Calendar</p>') else: # User didn't authorize Calendar read permission. # Update UX and application accordingly return '<p>Calendar feature is not enabled.</p>' @app.route('/authorize') def authorize(): # Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps. flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file( CLIENT_SECRETS_FILE, scopes=SCOPES) # The URI created here must exactly match one of the authorized redirect URIs # for the OAuth 2.0 client, which you configured in the API Console. If this # value doesn't match an authorized URI, you will get a 'redirect_uri_mismatch' # error. flow.redirect_uri = flask.url_for('oauth2callback', _external=True) authorization_url, state = flow.authorization_url( # Enable offline access so that you can refresh an access token without # re-prompting the user for permission. Recommended for web server apps. access_type='offline', # Enable incremental authorization. Recommended as a best practice. include_granted_scopes='true') # Store the state so the callback can verify the auth server response. flask.session['state'] = state return flask.redirect(authorization_url) @app.route('/oauth2callback') def oauth2callback(): # Specify the state when creating the flow in the callback so that it can # verified in the authorization server response. state = flask.session['state'] flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file( CLIENT_SECRETS_FILE, scopes=SCOPES, state=state) flow.redirect_uri = flask.url_for('oauth2callback', _external=True) # Use the authorization server's response to fetch the OAuth 2.0 tokens. authorization_response = flask.request.url flow.fetch_token(authorization_response=authorization_response) # Store credentials in the session. # ACTION ITEM: In a production app, you likely want to save these # credentials in a persistent database instead. credentials = flow.credentials credentials = credentials_to_dict(credentials) flask.session['credentials'] = credentials # Check which scopes user granted features = check_granted_scopes(credentials) flask.session['features'] = features return flask.redirect('/') @app.route('/revoke') def revoke(): if 'credentials' not in flask.session: return ('You need to <a href="/authorize">authorize</a> before ' + 'testing the code to revoke credentials.') # Load client secrets from the server-side file. with open(CLIENT_SECRETS_FILE, 'r') as f: client_config = json.load(f)['web'] # Load user-specific credentials from the session. session_credentials = flask.session['credentials'] # Reconstruct the credentials object. credentials = google.oauth2.credentials.Credentials( refresh_token=session_credentials.get('refresh_token'), scopes=session_credentials.get('granted_scopes'), token=session_credentials.get('token'), client_id=client_config.get('client_id'), client_secret=client_config.get('client_secret'), token_uri=client_config.get('token_uri')) revoke = requests.post('https://oauth2.googleapis.com/revoke', params={'token': credentials.token}, headers = {'content-type': 'application/x-www-form-urlencoded'}) status_code = getattr(revoke, 'status_code') if status_code == 200: # Clear the user's session credentials after successful revocation if 'credentials' in flask.session: del flask.session['credentials'] del flask.session['features'] return('Credentials successfully revoked.' + print_index_table()) else: return('An error occurred.' + print_index_table()) @app.route('/clear') def clear_credentials(): if 'credentials' in flask.session: del flask.session['credentials'] return ('Credentials have been cleared.<br><br>' + print_index_table()) def credentials_to_dict(credentials): return {'token': credentials.token, 'refresh_token': credentials.refresh_token, 'granted_scopes': credentials.granted_scopes} def check_granted_scopes(credentials): features = {} if 'https://www.googleapis.com/auth/drive.metadata.readonly' in credentials['granted_scopes']: features['drive'] = True else: features['drive'] = False if 'https://www.googleapis.com/auth/calendar.readonly' in credentials['granted_scopes']: features['calendar'] = True else: features['calendar'] = False return features def print_index_table(): return ('<table>' + '<tr><td><a href="/authorize">Test the auth flow directly</a></td>' + '<td>Go directly to the authorization flow. If there are stored ' + ' credentials, you still might not be prompted to reauthorize ' + ' the application.</td></tr>' + '<tr><td><a href="/drive">Call Drive API directly</a></td>' + '<td> Use stored credentials to call the API, you still might not be prompted to reauthorize ' + ' the application.</td></tr>' + '<tr><td><a href="/calendar">Call Calendar API directly</a></td>' + '<td> Use stored credentials to call the API, you still might not be prompted to reauthorize ' + ' the application.</td></tr>' + '<tr><td><a href="/revoke">Revoke current credentials</a></td>' + '<td>Revoke the access token associated with the current user ' + ' session. After revoking credentials, if you go to the test ' + ' page, you should see an <code>invalid_grant</code> error.' + '</td></tr>' + '<tr><td><a href="/clear">Clear Flask session credentials</a></td>' + '<td>Clear the access token currently stored in the user session. ' + ' After clearing the token, if you <a href="/authorize">authorize</a> ' + ' again, you should go back to the auth flow.' + '</td></tr></table>') if __name__ == '__main__': # When running locally, disable OAuthlib's HTTPs verification. # ACTION ITEM for developers: # When running in production *do not* leave this option enabled. os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' # This disables the requested scopes and granted scopes check. # If users only grant partial request, the warning would not be thrown. os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = '1' # Specify a hostname and port that are set as a valid redirect URI # for your API project in the Google API Console. app.run('localhost', 8080, debug=True)
Ruby
این نمونه از چارچوب Sinatra استفاده میکند.
require 'googleauth' require 'googleauth/web_user_authorizer' require 'googleauth/stores/redis_token_store' require 'google/apis/drive_v3' require 'google/apis/calendar_v3' require 'sinatra' configure do enable :sessions # Required, call the from_file method to retrieve the client ID from a # client_secret.json file. set :client_id, Google::Auth::ClientId.from_file('/path/to/client_secret.json') # Required, scope value # Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar. scope = ['Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY', 'Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY'] # Required, Authorizers require a storage instance to manage long term persistence of # access and refresh tokens. set :token_store, Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new) # Required, indicate where the API server will redirect the user after the user completes # the authorization flow. The redirect URI is required. The value must exactly # match one of the authorized redirect URIs for the OAuth 2.0 client, which you # configured in the API Console. If this value doesn't match an authorized URI, # you will get a 'redirect_uri_mismatch' error. set :callback_uri, '/oauth2callback' # To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI # from the client_secret.json file. To get these credentials for your application, visit # https://console.cloud.google.com/apis/credentials. set :authorizer, Google::Auth::WebUserAuthorizer.new(settings.client_id, settings.scope, settings.token_store, callback_uri: settings.callback_uri) end get '/' do # NOTE: Assumes the user is already authenticated to the app user_id = request.session['user_id'] # Fetch stored credentials for the user from the given request session. # nil if none present credentials = settings.authorizer.get_credentials(user_id, request) if credentials.nil? # Generate a url that asks the user to authorize requested scope(s). # Then, redirect user to the url. redirect settings.authorizer.get_authorization_url(request: request) end # User authorized the request. Now, check which scopes were granted. if credentials.scope.include?(Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY) # User authorized read-only Drive activity permission. # Example of using Google Drive API to list filenames in user's Drive. drive = Google::Apis::DriveV3::DriveService.new files = drive.list_files(options: { authorization: credentials }) "<pre>#{JSON.pretty_generate(files.to_h)}</pre>" else # User didn't authorize read-only Drive activity permission. # Update UX and application accordingly end # Check if user authorized Calendar read permission. if credentials.scope.include?(Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY) # User authorized Calendar read permission. # Calling the APIs, etc. else # User didn't authorize Calendar read permission. # Update UX and application accordingly end end # Receive the callback from Google's OAuth 2.0 server. get '/oauth2callback' do # Handle the result of the oauth callback. Defers the exchange of the code by # temporarily stashing the results in the user's session. target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request) redirect target_url end
Node.js
برای اجرای این نمونه:
-
در «کنسول API»، نشانی وب دستگاه محلی را به فهرست نشانیهای وب تغییرمسیر اضافه کنید. برای مثال،
http://localhostرا اضافه کنید. - مطمئن شوید که نسخه LTS نگهداری، LTS فعال، یا نسخه فعلی Node.js را نصب کردهاید.
-
دایرکتوری جدیدی ایجاد کنید و به آن بروید. برای مثال:
mkdir ~/nodejs-oauth2-example cd ~/nodejs-oauth2-example
-
کتابخانه کارخواه Google API را برای Node.js بااستفاده از npm نصب کنید:
npm install googleapis
-
فایلهای
main.jsرا با محتوای زیر بسازید. -
نمونه را اجرا کنید:
node .\main.js
main.js
const http = require('http'); const https = require('https'); const url = require('url'); const { google } = require('googleapis'); const crypto = require('crypto'); const express = require('express'); const session = require('express-session'); /** * To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI. * To get these credentials for your application, visit * https://console.cloud.google.com/apis/credentials. */ const oauth2Client = new google.auth.OAuth2( YOUR_CLIENT_ID, YOUR_CLIENT_SECRET, YOUR_REDIRECT_URL ); // Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar. const scopes = [ 'https://www.googleapis.com/auth/drive.metadata.readonly', 'https://www.googleapis.com/auth/calendar.readonly' ]; /* Global variable that stores user credential in this code example. * ACTION ITEM for developers: * Store user's refresh token in your data store if * incorporating this code into your real app. * For more information on handling refresh tokens, * see https://github.com/googleapis/google-api-nodejs-client#handling-refresh-tokens */ let userCredential = null; async function main() { const app = express(); app.use(session({ secret: 'your_secure_secret_key', // Replace with a strong secret resave: false, saveUninitialized: false, })); // Example on redirecting user to Google's OAuth 2.0 server. app.get('/', async (req, res) => { // Generate a secure random state value. const state = crypto.randomBytes(32).toString('hex'); // Store state in the session req.session.state = state; // Generate a url that asks permissions for the Drive activity and Google Calendar scope const authorizationUrl = oauth2Client.generateAuthUrl({ // 'online' (default) or 'offline' (gets refresh_token) access_type: 'offline', /** Pass in the scopes array defined above. * Alternatively, if only one scope is needed, you can pass a scope URL as a string */ scope: scopes, // Enable incremental authorization. Recommended as a best practice. include_granted_scopes: true, // Include the state parameter to reduce the risk of CSRF attacks. state: state }); res.redirect(authorizationUrl); }); // Receive the callback from Google's OAuth 2.0 server. app.get('/oauth2callback', async (req, res) => { // Handle the OAuth 2.0 server response let q = url.parse(req.url, true).query; if (q.error) { // An error response e.g. error=access_denied console.log('Error:' + q.error); } else if (q.state !== req.session.state) { //check state value console.log('State mismatch. Possible CSRF attack'); res.end('State mismatch. Possible CSRF attack'); } else { // Get access and refresh tokens (if access_type is offline) let { tokens } = await oauth2Client.getToken(q.code); oauth2Client.setCredentials(tokens); /** Save credential to the global variable in case access token was refreshed. * ACTION ITEM: In a production app, you likely want to save the refresh token * in a secure persistent database instead. */ userCredential = tokens; // User authorized the request. Now, check which scopes were granted. if (tokens.scope.includes('https://www.googleapis.com/auth/drive.metadata.readonly')) { // User authorized read-only Drive activity permission. // Example of using Google Drive API to list filenames in user's Drive. const drive = google.drive('v3'); drive.files.list({ auth: oauth2Client, pageSize: 10, fields: 'nextPageToken, files(id, name)', }, (err1, res1) => { if (err1) return console.log('The API returned an error: ' + err1); const files = res1.data.files; if (files.length) { console.log('Files:'); files.map((file) => { console.log(`${file.name} (${file.id})`); }); } else { console.log('No files found.'); } }); } else { // User didn't authorize read-only Drive activity permission. // Update UX and application accordingly } // Check if user authorized Calendar read permission. if (tokens.scope.includes('https://www.googleapis.com/auth/calendar.readonly')) { // User authorized Calendar read permission. // Calling the APIs, etc. } else { // User didn't authorize Calendar read permission. // Update UX and application accordingly } } }); // Example on revoking a token app.get('/revoke', async (req, res) => { // Build the string for the POST request let postData = "token=" + userCredential.access_token; // Options for POST request to Google's OAuth 2.0 server to revoke a token let postOptions = { host: 'oauth2.googleapis.com', port: '443', path: '/revoke', method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': Buffer.byteLength(postData) } }; // Set up the request const postReq = https.request(postOptions, function (res) { res.setEncoding('utf8'); res.on('data', d => { console.log('Response: ' + d); }); }); postReq.on('error', error => { console.log(error) }); // Post the request with data postReq.write(postData); postReq.end(); }); const server = http.createServer(app); server.listen(8080); } main().catch(console.error);
HTTP/REST
این نمونه Python از چارچوب Flask و کتابخانه Requests برای نمایش جریان وب OAuth 2.0 استفاده میکند. توصیه میکنیم برای این جریان از «کتابخانه کارخواه Google API» برای Python استفاده کنید. (مثال در برگه Python از کتابخانه مشتری استفاده میکند.)
import json import flask import requests app = flask.Flask(__name__) # To get these credentials (CLIENT_ID CLIENT_SECRET) and for your application, visit # https://console.cloud.google.com/apis/credentials. CLIENT_ID = '123456789.apps.googleusercontent.com' CLIENT_SECRET = 'abc123' # Read from a file or environmental variable in a real app # Access scopes for two non-Sign-In scopes: Read-only Drive activity and Google Calendar. SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/calendar.readonly' # Indicate where the API server will redirect the user after the user completes # the authorization flow. The redirect URI is required. The value must exactly # match one of the authorized redirect URIs for the OAuth 2.0 client, which you # configured in the API Console. If this value doesn't match an authorized URI, # you will get a 'redirect_uri_mismatch' error. REDIRECT_URI = 'http://example.com/oauth2callback' @app.route('/') def index(): if 'credentials' not in flask.session: return flask.redirect(flask.url_for('oauth2callback')) credentials = json.loads(flask.session['credentials']) if credentials['expires_in'] <= 0: return flask.redirect(flask.url_for('oauth2callback')) else: # User authorized the request. Now, check which scopes were granted. if 'https://www.googleapis.com/auth/drive.metadata.readonly' in credentials['scope']: # User authorized read-only Drive activity permission. # Example of using Google Drive API to list filenames in user's Drive. headers = {'Authorization': 'Bearer {}'.format(credentials['access_token'])} req_uri = 'https://www.googleapis.com/drive/v2/files' r = requests.get(req_uri, headers=headers).text else: # User didn't authorize read-only Drive activity permission. # Update UX and application accordingly r = 'User did not authorize Drive permission.' # Check if user authorized Calendar read permission. if 'https://www.googleapis.com/auth/calendar.readonly' in credentials['scope']: # User authorized Calendar read permission. # Calling the APIs, etc. r += 'User authorized Calendar permission.' else: # User didn't authorize Calendar read permission. # Update UX and application accordingly r += 'User did not authorize Calendar permission.' return r @app.route('/oauth2callback') def oauth2callback(): if 'code' not in flask.request.args: state = str(uuid.uuid4()) flask.session['state'] = state # Generate a url that asks permissions for the Drive activity # and Google Calendar scope. Then, redirect user to the url. auth_uri = ('https://accounts.google.com/o/oauth2/v2/auth?response_type=code' '&client_id={}&redirect_uri={}&scope={}&state={}').format(CLIENT_ID, REDIRECT_URI, SCOPE, state) return flask.redirect(auth_uri) else: if 'state' not in flask.request.args or flask.request.args['state'] != flask.session['state']: return 'State mismatch. Possible CSRF attack.', 400 auth_code = flask.request.args.get('code') data = {'code': auth_code, 'client_id': CLIENT_ID, 'client_secret': CLIENT_SECRET, 'redirect_uri': REDIRECT_URI, 'grant_type': 'authorization_code'} # Exchange authorization code for access and refresh tokens (if access_type is offline) r = requests.post('https://oauth2.googleapis.com/token', data=data) flask.session['credentials'] = r.text return flask.redirect(flask.url_for('index')) if __name__ == '__main__': import uuid app.secret_key = str(uuid.uuid4()) app.debug = False app.run()
قوانین درستیسنجی URI هدایت
Google قوانین اعتبارسنجی زیر را برای هدایت شناسههای URI اعمال میکند تا به توسعهدهندگان کمک کند برنامههایشان را ایمن نگه دارند. شناسههای URI هدایت شما باید از این قوانین پیروی کنند. برای تعریف دامنه، میزبان، مسیر، پُرسمان، طرح، و اطلاعات کاربر که در این قوانین استفاده شده است، بخش ۳ RFC 3986 را ببینید.
| قوانین اعتبارسنجی | |
|---|---|
| طرح |
URIهای بازهدایت باید از طرح HTTPS استفاده کنند، نه HTTP ساده. شناسه منبع یکسان Localhost (شامل شناسه منبع یکسان نشانی IP در localhost) از این قانون مستثنی است. |
| میزبان |
میزبانها نمیتوانند نشانیهای IP خام باشند. نشانیهای IP میزبان محلی از این قانون مستثنی هستند. |
| دامنه |
“googleusercontent.com” باشد.goo.gl) باشند، مگراینکه
برنامه مالک دامنه باشد. علاوهبراین، اگر برنامهای که مالک دامنه کوتاهکننده است تصمیم بگیرد
به آن دامنه هدایت کند، آن URI هدایت باید یا حاوی
“/google-callback/” در مسیرش باشد یا به
“/google-callback” ختم شود. |
| Userinfo |
شناسه منبع یکسان تغییرمسیر نمیتواند حاوی زیرمؤلفه userinfo باشد. |
| مسیر |
URI تغییرمسیر نمیتواند حاوی پیمایش مسیر (که به آن بازگشت دایرکتوری نیز میگویند) باشد،
که با |
| پُرسمان |
شناسههای URI هدایت نمیتوانند حاوی هدایتهای باز باشند. |
| Fragment |
شناسههای منبع یکسان تغییرمسیر نمیتوانند حاوی مؤلفه قطعه باشند. |
| شخصیتها |
شناسه منبع یکسان تغییرمسیر نمیتواند حاوی نویسههای خاصی باشد، ازجمله:
|
مجوزدهی افزایشی
در پروتکل OAuth 2.0، برنامه شما برای دسترسی به منابعی که با گسترهها شناسایی میشوند، درخواست مجوز میکند. بهترین روش تجربه کاربری این است که درخواست مجوز برای منابع را در زمانی که به آنها نیاز دارید انجام دهید. برای فعال کردن این روش، سرور مجوز Google از مجوز افزایشی پشتیبانی میکند. این ویژگی به شما امکان میدهد تا دامنهها را درصورت نیاز درخواست کنید و اگر کاربر اجازه دامنه جدید را اعطا کند، کد مجوزی را برمیگرداند که ممکن است با یک کد حاوی همه دامنههایی که کاربر به پروژه اعطا کرده است مبادله شود.
برای مثال، برنامهای که به افراد اجازه میدهد قطعههای موسیقی را نمونهبرداری کنند و میکس بسازند ممکن است در زمان ورود به سیستم به منابع بسیار کمی نیاز داشته باشد، شاید چیزی بیشتر از نام فردی که به سیستم وارد میشود نباشد. بااینحال، ذخیره کردن ترکیب کاملشده مستلزم دسترسی به Google Drive آنها است. اکثر افراد این را طبیعی میدانند که فقط زمانی از آنها درخواست دسترسی به Google Drive شود که برنامه واقعاً به آن نیاز دارد.
در این حالت، برنامه ممکن است در زمان ورود به سیستم، دامنههای openid و profile را برای انجام ورود به سیستم پایه درخواست کند و سپس در زمان اولین درخواست برای ذخیره ترکیب، دامنه https://www.googleapis.com/auth/drive.file را درخواست کند.
برای پیادهسازی مجوز افزایشی، جریان عادی درخواست کد دسترسی را تکمیل میکنید اما مطمئن میشوید که درخواست مجوز شامل دامنههایی است که قبلاً اعطا شده است. این رویکرد به برنامه شما امکان میدهد از مدیریت چندین کد دسترسی اجتناب کند.
قوانین زیر برای کد دسترسی بهدستآمده از مجوز افزایشی اعمال میشود:
- از این توکن میتوان برای دسترسی به منابع مربوط به هریک از دامنههایی که در مجوز ترکیبی جدید گنجانده شدهاند استفاده کرد.
- وقتی از ژتون بازآوری برای مجوز ترکیبی جهت دریافت کد دسترسی استفاده میکنید،
کد دسترسی نشاندهنده مجوز ترکیبی است و میتوان از آن برای هرکدام از
مقادیر
scopeموجود در پاسخ استفاده کرد. - مجوز ترکیبی شامل همه دامنههایی است که کاربر به پروژه API اعطا کرده است، حتی اگر این اعطاها از مشتریان مختلف درخواست شده باشد. برای مثال، اگر کاربری بااستفاده از کارخواه میزکار برنامه به یک دامنه دسترسی اعطا کند و سپس ازطریق کارخواه تلفن همراه به همان برنامه دامنه دیگری اعطا کند، مجوز ترکیبی شامل هر دو دامنه خواهد بود.
- اگر توکنی را که نشاندهنده مجوز ترکیبی است لغو کنید، دسترسی به همه حوزههای آن مجوز ازطرف کاربر مرتبط بهطور همزمان لغو میشود.
نمونههای کد مختص زبان در مرحله ۱: تنظیم مجوز هدایت به سرور OAuth 2.0 از Google همگی از مجوز افزایشی استفاده میکنند. نمونه کدهای زیر همچنین کدی را نشان میدهند که باید برای استفاده از مجوز افزایشی اضافه کنید.
PHP
$client->setIncludeGrantedScopes(true);Python
در Python، آرگومان کلیدواژه include_granted_scopes را روی true تنظیم کنید تا
مطمئن شوید درخواست مجوز شامل گسترههای قبلاً اعطاشده است. بسیار ممکن است که
include_granted_scopes تنها شناسه کلیدواژهای نباشد که تنظیم میکنید، همانطور که
در مثال زیر نشان داده شده است.
authorization_url, state = flow.authorization_url( # Enable offline access so that you can refresh an access token without # re-prompting the user for permission. Recommended for web server apps. access_type='offline', # Enable incremental authorization. Recommended as a best practice. include_granted_scopes='true')
Ruby
auth_client.update!( :additional_parameters => {"include_granted_scopes" => "true"} )
Node.js
const authorizationUrl = oauth2Client.generateAuthUrl({ // 'online' (default) or 'offline' (gets refresh_token) access_type: 'offline', /** Pass in the scopes array defined above. * Alternatively, if only one scope is needed, you can pass a scope URL as a string */ scope: scopes, // Enable incremental authorization. Recommended as a best practice. include_granted_scopes: true });
HTTP/REST
GET https://accounts.google.com/o/oauth2/v2/auth? client_id=your_client_id& response_type=code& state=state_parameter_passthrough_value& scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly%20https%3A//www.googleapis.com/auth/calendar.readonly& redirect_uri=https%3A//developers.google.com/oauthplayground& prompt=consent& include_granted_scopes=true
بازآوری کد دسترسی (دسترسی آفلاین)
کدهای دسترسی بهطور دورهای منقضی میشوند و برای درخواست API مربوطه به اعتبارنامه نامعتبر تبدیل میشوند. اگر برای دامنههای مرتبط با کد دسترسی درخواست دسترسی آفلاین کرده باشید، میتوانید کد دسترسی را بدون درخواست اجازه از کاربر (ازجمله زمانی که کاربر حضور ندارد) بازآوری کنید.
- اگر از «کتابخانه کارخواه میانای برنامهسازی کاربردی Google» استفاده میکنید، شیء کارخواه کد دسترسی را درصورت نیاز بازآوری میکند، بهشرطی که آن شیء را برای دسترسی آفلاین پیکربندی کنید.
- اگر از کتابخانه کارخواه استفاده نمیکنید، باید هنگام هدایت کاربر به سرور OAuth 2.0 Google، پارامتر پُرسمان HTTP
access_typeرا رویofflineتنظیم کنید. در این حالت، وقتی کد مجوز را با کد دسترسی معاوضه میکنید، سرور مجوز Google ژتون بازآوری را برمیگرداند. سپس، اگر کد دسترسی منقضی شود (یا در هر زمان دیگری)، میتوانید از ژتون بازآوری برای دریافت کد دسترسی جدید استفاده کنید.
درخواست دسترسی آفلاین برای هر برنامهای که نیاز به دسترسی به Google API دارد، زمانی که کاربر حضور ندارد، الزامی است. برای مثال، برنامهای که سرویسهای پشتیبانگیری را انجام میدهد یا
کنشها را در زمانهای ازپیش تعیینشده اجرا میکند باید بتواند کد دسترسی خود را وقتی
کاربر حضور ندارد بازآوری کند. سبک پیشفرض دسترسی online نام دارد.
برنامههای وب سمت سرور، برنامههای نصبشده، و دستگاهها همگی درطول فرایند صدور مجوز، ژتون بازآوری دریافت میکنند. ژتونهای بازآوری معمولاً در برنامههای وب سمت کارخواه (جاوا اسکریپت) استفاده نمیشوند.
PHP
اگر برنامه شما به دسترسی آفلاین به میانای برنامهسازی کاربردی Google نیاز دارد، نوع دسترسی کارخواه میانای برنامهسازی کاربردی را روی
offline تنظیم کنید:
$client->setAccessType("offline");پساز اینکه کاربر دسترسی آفلاین به دامنههای درخواستی را اعطا کرد، میتوانید همچنان از کارخواه میانای برنامهسازی کاربردی برای دسترسی به میاناهای برنامهسازی کاربردی Google ازطرف کاربر در زمانی که کاربر آفلاین است استفاده کنید. شیء کارخواه کد دسترسی را درصورت نیاز بازآوری خواهد کرد.
Python
در Python، آرگومان کلیدواژه access_type را روی offline تنظیم کنید تا مطمئن شوید که میتوانید کد دسترسی را بدون نیاز به درخواست مجدد اجازه از کاربر بازآوری کنید. بسیار محتمل است که access_type تنها شناسه کلیدواژهای نباشد که تنظیم میکنید، همانطور که در مثال زیر نشان داده شده است.
authorization_url, state = flow.authorization_url( # Enable offline access so that you can refresh an access token without # re-prompting the user for permission. Recommended for web server apps. access_type='offline', # Enable incremental authorization. Recommended as a best practice. include_granted_scopes='true')
پساز اینکه کاربر دسترسی آفلاین به دامنههای درخواستی را اعطا کرد، میتوانید همچنان از کارخواه میانای برنامهسازی کاربردی برای دسترسی به میاناهای برنامهسازی کاربردی Google ازطرف کاربر در زمانی که کاربر آفلاین است استفاده کنید. شیء کارخواه کد دسترسی را درصورت نیاز بازآوری خواهد کرد.
Ruby
اگر برنامه شما به دسترسی آفلاین به میانای برنامهسازی کاربردی Google نیاز دارد، نوع دسترسی کارخواه میانای برنامهسازی کاربردی را روی
offline تنظیم کنید:
auth_client.update!( :additional_parameters => {"access_type" => "offline"} )
پساز اینکه کاربر دسترسی آفلاین به دامنههای درخواستی را اعطا کرد، میتوانید همچنان از کارخواه میانای برنامهسازی کاربردی برای دسترسی به میاناهای برنامهسازی کاربردی Google ازطرف کاربر در زمانی که کاربر آفلاین است استفاده کنید. شیء کارخواه کد دسترسی را درصورت نیاز بازآوری خواهد کرد.
Node.js
اگر برنامه شما به دسترسی آفلاین به میانای برنامهسازی کاربردی Google نیاز دارد، نوع دسترسی کارخواه میانای برنامهسازی کاربردی را روی
offline تنظیم کنید:
const authorizationUrl = oauth2Client.generateAuthUrl({ // 'online' (default) or 'offline' (gets refresh_token) access_type: 'offline', /** Pass in the scopes array defined above. * Alternatively, if only one scope is needed, you can pass a scope URL as a string */ scope: scopes, // Enable incremental authorization. Recommended as a best practice. include_granted_scopes: true });
پساز اینکه کاربر دسترسی آفلاین به دامنههای درخواستی را اعطا کرد، میتوانید همچنان از کارخواه میانای برنامهسازی کاربردی برای دسترسی به میاناهای برنامهسازی کاربردی Google ازطرف کاربر در زمانی که کاربر آفلاین است استفاده کنید. شیء کارخواه کد دسترسی را درصورت نیاز بازآوری خواهد کرد.
کدهای دسترسی منقضی میشوند. این کتابخانه بهطور خودکار از یک ژتون بازآوری برای دریافت یک کد دسترسی جدید استفاده میکند، اگر کد دسترسی درحال انقضا باشد. یک راه آسان برای اطمینان از اینکه همیشه جدیدترین نشانها را ذخیره میکنید استفاده از رویداد نشانها است:
oauth2Client.on('tokens', (tokens) => { if (tokens.refresh_token) { // store the refresh_token in your secure persistent database console.log(tokens.refresh_token); } console.log(tokens.access_token); });
این رویداد ژتونها فقط در اولین مجوزدهی رخ میدهد و باید
access_type را روی offline تنظیم کرده باشید تا هنگام فراخوانی روش
generateAuthUrl، ژتون بازآوری را دریافت کنید. اگر قبلاً اجازههای لازم را به برنامهتان دادهاید
بدون اینکه محدودیتهای مناسب را برای دریافت ژتون بازآوری تنظیم کنید، باید
برنامه را دوباره مجاز کنید تا ژتون بازآوری جدیدی دریافت کند.
برای تنظیم refresh_token در زمانی دیگر، میتوانید از روش setCredentials استفاده کنید:
oauth2Client.setCredentials({ refresh_token: `STORED_REFRESH_TOKEN` });
وقتی کارخواه ژتون بازآوری داشته باشد، ژتونهای دسترسی بهطور خودکار در تماس بعدی با API دریافت و بازآوری خواهند شد.
HTTP/REST
برای بازآوری کد دسترسی، برنامهتان درخواست HTTPS POST
به سرور صدور مجوز Google (https://oauth2.googleapis.com/token) ارسال میکند که
شامل پارامترهای زیر در بدنه درخواست است:
| نام | مقدار |
|---|---|
client_id |
شناسه کارخواه بهدستآمده از کنسول API. |
client_secret |
اختیاری
رمز کارخواه از کنسول API دریافت شد. |
grant_type |
همانطور که
در
مشخصات OAuth 2.0 تعریف شده است،
مقدار این فیلد باید روی refresh_token تنظیم شود. |
refresh_token |
ژتون بازآوری از تبادل کد مجوز برگردانده شد. |
هرچند استفاده از DPoP اختیاری است، اما برای افزایش امنیت توصیه میشود. برای استفاده از DPoP با ژتون بازآوری، برنامه شما باید برای هر درخواست به نقطه پایانی ژتون، یک JWT اثبات DPoP جدید و منحصربهفرد تولید کند. این مدرک باید با همان کلید خصوصیای امضا شود که درطول تبادل اولیه کد مجوز استفاده شده است. برنامه شما مدرک را بهعنوان سرایند درخواست HTTP اضافه میکند.
| سرایند | الزامی | شرح |
|---|---|---|
DPoP |
اختیاری | اثبات DPoP یک JWT است که
مالکیت کلید خصوصی را اثبات میکند. این یک سرایند است، نه پارامتر. درصورت ارائه، نشانهای برگرداندهشده
به این کلید محدود میشوند. برای هر درخواست باید مدرک جدید و منحصربهفردی تولید شود و باید شامل ادعاهای htm (روش HTTP) و htu (شناسه منبع یکسان HTTP) باشد که با درخواست مطابقت داشته باشد. |
قطعه کد زیر یک درخواست نمونه را نشان میدهد:
POST /token HTTP/1.1 Host: oauth2.googleapis.com Content-Type: application/x-www-form-urlencoded DPoP: DPOP_PROOF_JWT client_id=your_client_id& refresh_token=refresh_token& grant_type=refresh_token
برای استفاده از DPoP با ژتون بازآوری، باید JWT اثبات DPoP جدید و منحصربهفردی برای درخواست تولید کنید. برای دستورالعملهای گامبهگام درباره تولید جفت کلید و ساختن JWT، به ساختن اثبات DPoP مراجعه کنید.
تبادل موفق با پاسخ 200 OK
حاوی کد دسترسی جدید نشان داده میشود. وقتی از DPoP استفاده میشود،
token_type Bearer است. پاسخ موفقیتآمیز تأیید میکند که
اثبات DPoP برای ژتون بازآوری پذیرفته شده است. Google همچنین ممکن است یک سرایند HTTP جدید DPoP-Nonce در پاسخ برگرداند؛ اگر برگردانده شود، کارخواه شما باید این عدد یکبارمصرف را ذخیره کند و آن را در ادعای nonce اثبات DPoP در درخواستهای بعدی قرار دهد.
اگر سرایند DPoP وجود نداشته باشد، نامعتبر باشد، یا از کلید نادرستی استفاده کند، تبادل ناموفق رخ میدهد. برای جزئیات مربوط به کدهای خطای خاص DPoP و مدیریت نانسها، به تبادل ناموفق مراجعه کنید.
تکهکد زیر نمونهای از سرایندها و متن پاسخ موفقیتآمیز را هنگام استفاده از DPoP نشان میدهد:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
DPoP-Nonce: AN3XwJjZsjnb0ZuWkRlek8QU7wY-Zhf-5IP6tO0tORz0KgtDT1Bo8FX-w4nz3r5lnepI
{
"access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
"expires_in": 3920,
"scope": "https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/calendar.readonly",
"token_type": "Bearer"
}توجه داشته باشید که محدودیتهایی برای تعداد ژتونهای بازآوری که صادر میشود وجود دارد؛ یک محدودیت برای هر ترکیب مشتری/کاربر، و محدودیت دیگر برای هر کاربر در همه مشتریان. باید کدهای بازآوری را در فضای ذخیرهسازی بلندمدت ذخیره کنید و تا زمانی که معتبر هستند از آنها استفاده کنید. اگر برنامه شما ژتونهای بازآوری زیادی درخواست کند، ممکن است با این محدودیتها مواجه شود که در این صورت ژتونهای بازآوری قدیمیتر دیگر کار نخواهند کرد.
ابطال کد
در برخی موارد، ممکن است کاربر بخواهد دسترسی اعطاشده به برنامهای را لغو کند. کاربر میتواند با مراجعه به تنظیمات حساب، دسترسی را لغو کند. برای اطلاعات بیشتر، به سند پشتیبانی برداشتن دسترسی سایت یا برنامه در بخش «برنامهها و سایتهای طرف سوم با امکان دسترسی به حساب شما» مراجعه کنید.
همچنین ممکن است برنامهای بهصورت برنامهنویسیشده دسترسی اعطاشده به خود را لغو کند. لغو برنامهای در مواردی که کاربر لغو اشتراک میکند، برنامهای را برمیدارد، یا منابع API موردنیاز برنامه بهطور قابلتوجهی تغییر کرده است مهم است. به عبارت دیگر، بخشی از فرایند برداشتن میتواند شامل درخواست API باشد تا اطمینان حاصل شود اجازههایی که قبلاً به برنامه اعطا شده است برداشته شود.
PHP
برای لغو کردن کد بهصورت برنامهنویسیشده، با revokeToken() تماس بگیرید:
$client->revokeToken();Python
برای لغو کردن برنامهنویسیشده یک کد، درخواستی به
https://oauth2.googleapis.com/revoke ارسال کنید که شامل کد بهعنوان پارامتر باشد و سرصفحه
Content-Type را تنظیم کند:
requests.post('https://oauth2.googleapis.com/revoke', params={'token': credentials.token}, headers = {'content-type': 'application/x-www-form-urlencoded'})
Ruby
برای لغو کردن برنامهنویسیشده یک کد، یک درخواست HTTP به نقطه پایانی oauth2.revoke
ارسال کنید:
uri = URI('https://oauth2.googleapis.com/revoke') response = Net::HTTP.post_form(uri, 'token' => auth_client.access_token)
این ژتون میتواند ژتون دسترسی یا ژتون بازآوری باشد. اگر کد از نوع کد دسترسی باشد و کد بازآوری متناظر داشته باشد، کد بازآوری نیز باطل خواهد شد.
اگر لغو باموفقیت پردازش شود، رمز وضعیت پاسخ
200 است. برای شرایط خطا، رمز وضعیت 400 بههمراه کد خطا برگردانده میشود.
Node.js
برای لغو کردن برنامهنویسیشده یک توکن، یک درخواست HTTPS POST به نقطه پایانی /revoke ارسال کنید:
const https = require('https'); // Build the string for the POST request let postData = "token=" + userCredential.access_token; // Options for POST request to Google's OAuth 2.0 server to revoke a token let postOptions = { host: 'oauth2.googleapis.com', port: '443', path: '/revoke', method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': Buffer.byteLength(postData) } }; // Set up the request const postReq = https.request(postOptions, function (res) { res.setEncoding('utf8'); res.on('data', d => { console.log('Response: ' + d); }); }); postReq.on('error', error => { console.log(error) }); // Post the request with data postReq.write(postData); postReq.end();
پارامتر ژتون میتواند ژتون دسترسی یا ژتون بازآوری باشد. اگر کد از نوع کد دسترسی باشد و کد بازآوری متناظر داشته باشد، کد بازآوری نیز باطل خواهد شد.
اگر لغو باموفقیت پردازش شود، رمز وضعیت پاسخ
200 است. برای شرایط خطا، رمز وضعیت 400 بههمراه کد خطا برگردانده میشود.
HTTP/REST
برای لغو کردن برنامهنویسیشده یک کد، برنامه شما درخواستی به
https://oauth2.googleapis.com/revoke ارسال میکند و کد را بهعنوان پارامتر اضافه میکند:
curl -d -X -POST --header "Content-type:application/x-www-form-urlencoded" \
https://oauth2.googleapis.com/revoke?token={token}این ژتون میتواند ژتون دسترسی یا ژتون بازآوری باشد. اگر کد از نوع کد دسترسی باشد و کد بازآوری متناظر داشته باشد، کد بازآوری نیز باطل خواهد شد.
اگر لغو با موفقیت پردازش شود، رمز وضعیت HTTP پاسخ
200 است. برای شرایط خطا، رمز وضعیت HTTP 400 بههمراه کد خطا برگردانده میشود.
دسترسی زمانمحور
دسترسی زمانمحور به کاربر اجازه میدهد برای مدت محدودی به برنامه شما اجازه دسترسی به دادههایش را بدهد تا کنشی را تکمیل کند. دسترسی زماندار در محصولات منتخب Google درطول جریان رضایت دردسترس است و به کاربران این امکان را میدهد که دسترسی را برای مدت زمان محدودی اعطا کنند. یک نمونه از آن Data Portability API است که امکان انتقال یکباره دادهها را فراهم میکند.
وقتی کاربری به برنامه شما دسترسی زماندار اعطا میکند، ژتون بازآوری پساز مدت مشخصشده منقضی میشود. توجه داشته باشید که ژتونهای بازآوری ممکن است در شرایط خاصی زودتر باطل شوند؛ برای جزئیات بیشتر، این موارد را ببینید. فیلد refresh_token_expires_in که در پاسخ
تبادل کد
مجوز برگردانده میشود، نشاندهنده زمان باقیمانده تا انقضای ژتون بازآوری در چنین مواردی است.
پیادهسازی «محافظت بینحسابی»
اقدام دیگری که باید برای محافظت از حسابهای کاربرانتان انجام دهید، پیادهسازی «محافظت بینحسابی» بااستفاده از «سرویس محافظت بینحسابی» Google است. این سرویس به شما امکان میدهد در اعلانهای رویداد امنیتی مشترک شوید که اطلاعاتی درباره تغییرات عمده در حساب کاربر به برنامهتان ارائه میدهد. سپس میتوانید از این اطلاعات برای اقدام کردن بسته به نحوه تصمیمگیریتان برای پاسخ دادن به رویدادها استفاده کنید.
برخیاز نمونههای انواع رویدادهایی که «سرویس محافظت بینحسابی» Google به برنامهتان ارسال میکند عبارتاند از:
-
https://schemas.openid.net/secevent/risc/event-type/sessions-revoked -
https://schemas.openid.net/secevent/oauth/event-type/token-revoked -
https://schemas.openid.net/secevent/risc/event-type/account-disabled
برای کسب اطلاعات بیشتر درباره نحوه پیادهسازی «محافظت بینحسابی» و فهرست کامل رویدادهای دردسترس، به صفحه «محافظت از حسابهای کاربری با محافظت بینحسابی» مراجعه کنید.