این سند توضیح میدهد که برنامههای سرور وب چگونه از «کتابخانههای کارخواه Google API» یا نقطههای پایانی Google OAuth 2.0 برای پیادهسازی مجوز OAuth 2.0 برای دسترسی به Google APIs استفاده میکنند.
OAuth 2.0 به کاربران اجازه میدهد دادههای خاصی را با برنامهای همرسانی کنند و درعینحال نامهای کاربری، گذرواژهها، و اطلاعات دیگرشان را خصوصی نگه دارند. برای مثال، یک برنامه میتواند از OAuth 2.0 برای دریافت اجازه از کاربران برای ذخیره فایلها در Google Drive آنها استفاده کند.
این جریان OAuth 2.0 بهطور خاص برای صدور مجوز کاربر است. این جریان برای برنامههایی طراحی شده است که میتوانند اطلاعات محرمانه را ذخیره کنند و وضعیت را حفظ کنند. یک برنامه کارساز وب که بهدرستی مجوز گرفته باشد میتواند درحالیکه کاربر با برنامه تعامل دارد یا پساز اینکه کاربر برنامه را ترک کرد، به میانای برنامهسازی کاربردی دسترسی پیدا کند.
برنامههای کارساز وب اغلب از حسابهای سرویس نیز برای مجاز کردن درخواستهای API استفاده میکنند، بهویژه هنگام فراخوانی Cloud APIs برای دسترسی به دادههای مبتنی بر پروژه بهجای دادههای مختص کاربر. برنامههای کارساز وب میتوانند از حسابهای خدمات همراه با مجوز کاربر استفاده کنند.
کتابخانههای مشتری
نمونههای مختص زبان در این صفحه از کتابخانههای کارخواه Google API برای پیادهسازی مجوز OAuth 2.0 استفاده میکنند. برای اجرای نمونه کدها، ابتدا باید کتابخانه مشتری را برای زبان خود نصب کنید.
وقتی از «کتابخانه کارخواه Google API» برای مدیریت جریان OAuth 2.0 برنامهتان استفاده میکنید، کتابخانه کارخواه کنشهای زیادی را انجام میدهد که درغیراینصورت برنامه باید خودش آنها را مدیریت کند. برای مثال، تعیین میکند که برنامه چه زمانی میتواند از نشانهای دسترسی ذخیرهشده استفاده کند یا آنها را بازآوری کند و همچنین چه زمانی برنامه باید رضایت را دوباره کسب کند. کتابخانه کارخواه همچنین نشانیهای وب هدایت مجدد صحیح تولید میکند و به پیادهسازی مدیریتکنندههای هدایت مجدد که کدهای مجوز را با کدهای دسترسی مبادله میکنند کمک میکند.
«کتابخانههای کارخواه Google API» برای برنامههای سمت سرور برای زبانهای زیر دردسترس است:
پیشنیازها
فعال کردن میاناهای برنامهسازی کاربردی برای پروژه
هر برنامهای که میاناهای برنامهسازی کاربردی Google را فراخوانی میکند باید آن میاناهای برنامهسازی کاربردی را در «کنسول میانای برنامهسازی کاربردی» فعال کند.
برای فعال کردن میانای برنامهسازی کاربردی برای پروژه:
- کتابخانه میانای برنامهسازی کاربردی را در «کنسول Google API» باز کنید.
- اگر از شما درخواست شد، پروژهای را انتخاب کنید یا پروژه جدیدی بسازید.
- «کتابخانه میانای برنامهسازی کاربردی» همه میاناهای برنامهسازی کاربردی دردسترس را براساس خانواده محصول و محبوبیت گروهبندی میکند. اگر API موردنظرتان برای فعال کردن در فهرست قابلمشاهده نیست، از جستجو برای یافتن آن استفاده کنید، یا روی مشاهده همه در خانواده محصولی که به آن تعلق دارد کلیک کنید.
- میانای برنامهسازی کاربردی موردنظرتان را برای فعال کردن انتخاب کنید، سپس روی دکمه فعال کردن کلیک کنید.
- اگر درخواست شد، صدور صورتحساب را فعال کنید.
- درصورت درخواست، «شرایط خدمات» API را بخوانید و بپذیرید.
ایجاد اعتبارنامههای مجوز
هر برنامهای که از OAuth 2.0 برای دسترسی به Google API استفاده میکند باید اعتبارنامه مجوز داشته باشد که برنامه را برای سرور OAuth 2.0 Google شناسایی کند. مراحل زیر نحوه ایجاد اعتبارنامه برای پروژهتان را توضیح میدهد. سپس برنامههایتان میتوانند از اطلاعات اعتباری برای دسترسی به میاناهای برنامهسازی کاربردی که برای آن پروژه فعال کردهاید استفاده کنند.
- به صفحه کارخواهان بروید.
- روی ایجاد مشتری کلیک کنید.
- نوع برنامه برنامه وب را انتخاب کنید.
- فرم را تکمیل کنید و روی ایجاد کلیک کنید. برنامههایی که از زبانها و چارچوبهایی
مثل PHP، Java، Python، Ruby، و NET .استفاده میکنند باید URIهای بازهدایت مجاز را مشخص کنند. URIهای
هدایت نقاط پایانی هستند که سرور OAuth 2.0 میتواند پاسخها را به آنها ارسال کند. این
نقاط پایانی باید از قوانین اعتبارسنجی Google پیروی کنند.
برای آزمایش، میتوانید نشانیهای وب را که به ماشین محلی ارجاع میدهند مشخص کنید، برای نمونه
http://localhost:8080. همه مثالهای این سند ازhttp://localhost:8080بهعنوان URI هدایت استفاده میکنند.توصیه میکنیم پایانههای اصالتسنجی برنامهتان را بهگونهای طراحی کنید که برنامهتان کدهای مجوز را برای منابع دیگر در صفحه فاش نکند.
پساز ایجاد اطلاعات اعتباری، فایل client_secret.json را از «کنسول API» بارگیری کنید. فایل را بهطور ایمن در مکانی ذخیره کنید که فقط برنامه شما بتواند به آن دسترسی داشته باشد.
شناسایی کردن دامنههای دسترسی
محدودهها به برنامه شما امکان میدهند فقط به منابعی که نیاز دارد دسترسی پیدا کند و درعینحال به کاربران امکان میدهند میزان دسترسیای را که به برنامه شما میدهند کنترل کنند. بنابراین، ممکن است بین تعداد گسترههای درخواستی و احتمال دریافت رضایت کاربر رابطه معکوس وجود داشته باشد.
پیشاز اینکه پیادهسازی مجوز OAuth 2.0 را شروع کنید، توصیه میکنیم محدودههایی را که برنامهتان برای دسترسی به آنها به اجازه نیاز دارد شناسایی کنید.
همچنین توصیه میکنیم که برنامهتان ازطریق فرایند احراز هویت فزاینده برای دسترسی به دامنههای احراز هویت درخواست دهد. در این فرایند، برنامهتان برای دسترسی به دادههای کاربر در بافت درخواست میدهد. این رویه مطلوب به کاربران کمک میکند راحتتر متوجه شوند چرا برنامه شما به دسترسیای که درخواست میکند نیاز دارد.
سند OAuth 2.0 API Scopes حاوی فهرست کاملی از دامنههایی است که ممکن است برای دسترسی به Google API استفاده کنید.
الزامات مختص زبان
برای اجرای هرکدام از نمونه کدهای موجود در این سند، به «حساب Google»، دسترسی به اینترنت، و مرورگر وب نیاز دارید. اگر از یکی از کتابخانههای کارخواه میانای برنامهسازی کاربردی استفاده میکنید، الزامات مختص زبان را نیز در بخشهای زیر ببینید.
PHP
برای اجرای نمونههای کد PHP در این سند، به موارد زیر نیاز دارید:
- PHP نسخه ۸.۰ یا بالاتر با میانای خط فرمان (CLI) و افزونه JSON نصبشده.
- ابزار مدیریت وابستگی Composer.
-
کتابخانه کارخواهان Google APIs برای PHP:
composer require google/apiclient:^2.15.0
برای اطلاعات بیشتر، کتابخانه مشتری Google APIs برای PHP را ببینید.
Python
برای اجرای نمونههای کد Python در این سند، به موارد زیر نیاز دارید:
- Python نسخه ۳.۷ یا بالاتر
- ابزار مدیریت بسته pip.
- نسخه ۲.۰ «کتابخانه کارخواه Google APIs» برای Python:
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 را ارتقا دهید، یادداشت انتشار کتابخانه کارخواه Google API Python و راهنمای انتقال مربوطه را مرور کنید.
Ruby
برای اجرای نمونههای کد Ruby در این سند، به موارد زیر نیاز دارید:
- Ruby نسخه ۲.۶ یا بالاتر
-
کتابخانه Google Auth برای Ruby:
gem install googleauth
-
کتابخانههای کارخواه برای میاناهای برنامهسازی کاربردی Google Drive و «تقویم»:
gem install google-apis-drive_v3 google-apis-calendar_v3
-
چارچوب برنامه وب Sinatra Ruby.
gem install sinatra
Node.js
برای اجرای نمونههای کد Node.js در این سند، به موارد زیر نیاز دارید:
- نسخه LTS نگهداری، LTS فعال، یا نسخه فعلی Node.js.
-
کارخواه Google APIs Node.js:
npm install googleapis crypto express express-session
HTTP/REST
برای اینکه بتوانید مستقیماً نقطههای پایانی OAuth 2.0 را فراخوانی کنید، نیازی به نصب هیچ کتابخانهای ندارید.
دریافت کدهای دسترسی OAuth 2.0
مراحل زیر نشان میدهد که برنامه شما چگونه با سرور OAuth 2.0 Google تعامل میکند تا رضایت کاربر را برای انجام درخواست API ازطرف کاربر دریافت کند. برنامه شما باید قبلاز اجرای درخواست 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 کارخواه پیکربندی کردهاید مطابقت داشته باشد. اگر این مقدار با شناسه منبع یکسان هدایت مجاز برای توجه داشته باشید که طرح |
||||||
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
- نشانی وبی برای درخواست دسترسی از سرور OAuth 2.0 متعلق به Google ایجاد کنید:
$auth_url = $client->createAuthUrl(); - کاربر را به
$auth_urlهدایت کنید:header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
Python
این مثال نشان میدهد که چگونه میتوان کاربر را بااستفاده از چارچوب برنامه وب Flask به نشانی وب اصالتسنجی هدایت کرد:
return flask.redirect(authorization_url)
Ruby
- نشانی وبی برای درخواست دسترسی از سرور OAuth 2.0 Google تولید کنید:
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 Foundation استفاده کنند.
توسعهدهندگان وب ممکن است زمانی با این خطا مواجه شوند که برنامه 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 nonce لازم باشد، مثلاً درطول تبادل ژتون بازآوری، و اثبات DPoP فاقد ادعای nonce باشد، یا مقدار nonce برای سرور غیرقابلقبول باشد (مثلاً منقضی شده باشد، قبلاً استفاده شده باشد، یا نادرست باشد)، Google کد خطای use_dpop_nonce را بههمراه سرصفحه HTTP DPoP-Nonce حاوی یک 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 مجاز استفاده کنید.
- یک شیء سرویس برای 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 پُرسمان
یا مقدار Authorization سرصفحه HTTP Bearer اضافه کنید. درصورت امکان،
سرصفحه HTTP ترجیح داده میشود، زیرا رشتههای پُرسمان معمولاً در گزارشهای سرور قابلمشاهده هستند. در بیشتر موارد میتوانید از کتابخانه کارخواه برای راهاندازی فراخوانیهایتان به Google APIs استفاده کنید (برای مثال، هنگام فراخوانی Drive Files API).
میتوانید همه «میاناهای برنامهسازی کاربردی Google» را امتحان کنید و دامنههای آنها را در OAuth 2.0 Playground مشاهده کنید.
نمونههای HTTP GET
فراخوانی نقطه پایانی
drive.files (میانای برنامهسازی کاربردی «فایلهای Drive») بااستفاده از سرایند Authorization: Bearer HTTP
ممکن است بهشکل زیر باشد. توجه داشته باشید که باید کد دسترسی خودتان را مشخص کنید:
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 ذخیره شده است پاک میکند. این ویژگی به شما امکان میدهد ببینید اگر کاربری که قبلاً به برنامه شما اجازه داده است در جلسه جدیدی درخواست API اجرا کند چه اتفاقی میافتد. همچنین به شما امکان میدهد پاسخ میانای برنامهسازی کاربردی را که برنامهتان درصورت لغو اجازههای اعطاشده به برنامهتان توسط کاربر دریافت میکند ببینید، و برنامهتان همچنان تلاش میکند درخواستی را با کد دسترسی لغوشده مجاز کند.
# -*- 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
-
بااستفاده از npm،
Google API Client
Library
برای Node.js را نصب کنید:
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) باشند، مگراینکه
برنامه مالک دامنه باشد. علاوهبراین، اگر برنامهای که مالک دامنه کوتاه کننده است تصمیم بگیرد به آن دامنه هدایت کند، آن نشانی وب هدایت باید یا حاوی “/google-callback/” در مسیر خود باشد یا با “/google-callback” پایان یابد. |
| Userinfo |
شناسه منبع یکسان تغییرمسیر نمیتواند حاوی زیرمؤلفه userinfo باشد. |
| مسیر |
شناسه منبع یکسان (URI) تغییرمسیر نمیتواند حاوی پیمایش مسیر (که به آن بازگشت دایرکتوری نیز میگویند) باشد،
که با |
| پُرسمان |
نشانیهای وب هدایت نباید حاوی هدایتهای باز باشند. |
| Fragment |
شناسههای منبع یکسان تغییرمسیر نمیتوانند حاوی مؤلفه قطعه باشند. |
| شخصیتها |
شناسه منبع یکسان تغییرمسیر نمیتواند حاوی نویسههای خاصی باشد، ازجمله:
|
مجوزدهی افزایشی
در پروتکل OAuth 2.0، برنامه شما برای دسترسی به منابعی که با گسترهها شناسایی میشوند، درخواست مجوز میکند. درخواست مجوز برای منابع در زمانی که به آنها نیاز دارید، بهعنوان بهترین رویه تجربه کاربری درنظر گرفته میشود. برای فعال کردن این روش، سرور مجوز Google از مجوز افزایشی پشتیبانی میکند. این ویژگی به شما امکان میدهد تا دامنهها را درصورت نیاز درخواست کنید و، اگر کاربر اجازه را برای دامنه جدید اعطا کند، یک کد مجوز برمیگرداند که ممکن است با یک کد حاوی همه دامنههایی که کاربر به پروژه اعطا کرده است مبادله شود.
برای مثال، برنامهای که به افراد امکان میدهد قطعههای موسیقی را نمونهبرداری کنند و میکس بسازند ممکن است در زمان ورود به سیستم به منابع بسیار کمی نیاز داشته باشد، شاید فقط نام فردی که به سیستم وارد میشود. بااینحال، ذخیره کردن یک ترکیب کامل نیاز به دسترسی به Google Drive آنها دارد. اکثر افراد اگر فقط زمانی که برنامه واقعاً به Google Drive نیاز دارد از آنها درخواست دسترسی به آن شود، این کار را طبیعی میدانند.
در این مورد، برنامه ممکن است در زمان ورود به سیستم، دامنههای openid و
profile را برای انجام ورود به سیستم پایه درخواست کند، و سپس در زمان اولین درخواست برای ذخیره کردن
ترکیب، دامنه https://www.googleapis.com/auth/drive.file را درخواست کند.
برای پیادهسازی مجوز افزایشی، جریان عادی درخواست کد دسترسی را تکمیل میکنید اما مطمئن شوید که درخواست مجوز شامل محدودههایی باشد که قبلاً اعطا شده است. این رویکرد به برنامه شما امکان میدهد از مدیریت چندین کد دسترسی اجتناب کند.
قوانین زیر برای کد دسترسی بهدستآمده از مجوز افزایشی اعمال میشود:
- از این کد میتوان برای دسترسی به منابع مربوط به هریک از دامنههایی که در مجوز ترکیبی جدید گنجانده شدهاند استفاده کرد.
- وقتی از کد نوسازی برای مجوز ترکیبی استفاده میکنید تا کد دسترسی دریافت کنید، کد دسترسی نشاندهنده مجوز ترکیبی است و میتواند برای هریک از مقادیر
scopeموجود در پاسخ استفاده شود. - مجوز ترکیبی شامل همه دامنههایی است که کاربر به پروژه میانای برنامهسازی کاربردی اعطا کرده است، حتی اگر این اعطاها از کارخواههای مختلف درخواست شده باشد. برای مثال، اگر کاربری بااستفاده از کلاینت رایانه برنامه به یک حوزه دسترسی اعطا کند و سپس حوزه دیگری را ازطریق کلاینت تلفن همراه به همان برنامه اعطا کند، مجوز ترکیبی شامل هر دو حوزه خواهد بود.
- اگر توکنی را که نشاندهنده مجوز ترکیبی است لغو کنید، دسترسی به همه حوزههای آن مجوز ازطرف کاربر مرتبط بهطور همزمان لغو میشود.
نمونههای کد مختص زبان در مرحله ۱: تنظیم کردن مجوز هدایت کردن به سرور 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 API» استفاده میکنید، تا زمانی که شیء کارخواه را برای دسترسی آفلاین پیکربندی کنید، این شیء کد دسترسی را درصورت نیاز بازآوری میکند.
- اگر از کتابخانه کارخواه استفاده نمیکنید، باید هنگام هدایت کاربر به سرور 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 });
پساز اینکه کاربر دسترسی آفلاین به دامنههای درخواستی اعطا کرد، میتوانید همچنان از کارخواه API برای دسترسی به «میاناهای برنامهسازی کاربردی 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 با کد بازآوری، باید یک مدرک DPoP جدید و منحصربهفرد JWT برای درخواست تولید کنید. برای دریافت دستورالعملهای گامبهگام درباره تولید جفت کلید و ساختن JWT، به ساختن مدرک DPoP مراجعه کنید.
تبادل موفق با پاسخ 200 OK
حاوی یک کد دسترسی جدید نشان داده میشود. وقتی از DPoP استفاده میشود،
token_type Bearer است. پاسخ موفقیتآمیز تأیید میکند که
اثبات DPoP برای ژتون بازآوری پذیرفته شده است. Google همچنین ممکن است سرصفحه HTTP جدید DPoP-Nonce را در پاسخ برگرداند؛ درصورت برگردانده شدن، کارخواه شما باید این 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
برای کسب اطلاعات بیشتر درباره نحوه پیادهسازی «محافظت بینحسابی» و فهرست کامل رویدادهای دردسترس، به صفحه «محافظت از حسابهای کاربری با محافظت بینحسابی» مراجعه کنید.