Ten dokument wyjaśnia, jak aplikacje serwera internetowego korzystają z bibliotek klienta interfejsu API Google lub punktów końcowych OAuth 2.0 Google, aby zaimplementować autoryzację OAuth 2.0 w celu uzyskania dostępu do interfejsów API Google.
OAuth 2.0 umożliwia użytkownikom udostępnianie określonych danych aplikacji przy jednoczesnym zachowaniu poufności nazw, haseł i innych informacji. Aplikacja może na przykład używać OAuth 2.0, aby uzyskać od użytkowników uprawnienia do przechowywania plików na Dysku Google.
Ten proces OAuth 2.0 jest przeznaczony do autoryzacji użytkownika. Jest przeznaczony do aplikacji, które mogą przechowywać poufne informacje i utrzymywać stan. Prawidłowo autoryzowana aplikacja serwera WWW może uzyskać dostęp do interfejsu API, gdy użytkownik wchodzi w interakcję z aplikacją lub gdy ją opuszcza.
Aplikacje serwera WWW często używają też kont usług do autoryzowania żądań interfejsu API, zwłaszcza gdy wywołują interfejsy Cloud API, aby uzyskać dostęp do danych opartych na projekcie, a nie danych dotyczących konkretnego użytkownika. Aplikacje serwera WWW mogą używać kont usługi w połączeniu z autoryzacją użytkownika.
Biblioteki klienta
Przykłady dotyczące poszczególnych języków na tej stronie używają bibliotek klienta interfejsu API Google do implementowania autoryzacji OAuth 2.0. Aby uruchomić przykłady kodu, musisz najpierw zainstalować bibliotekę klienta dla wybranego języka.
Gdy używasz biblioteki klienta interfejsu API Google do obsługi procesu OAuth 2.0 w aplikacji, biblioteka klienta wykonuje wiele działań, które aplikacja musiałaby wykonać samodzielnie. Na przykład określa, kiedy aplikacja może używać lub odświeżać zapisane tokeny dostępu, a także kiedy musi ponownie uzyskać zgodę. Biblioteka klienta generuje też prawidłowe adresy URL przekierowania i pomaga implementować moduły przekierowania, które zamieniają kody autoryzacji na tokeny dostępu.
Biblioteki klienta interfejsu API Google przeznaczone do aplikacji serwerowych są dostępne w tych językach:
Wymagania wstępne
Włączanie interfejsów API w projekcie
Każda aplikacja, która wywołuje interfejsy API Google, musi włączyć te interfejsy w API Console.
Aby włączyć interfejs API w projekcie:
- Open the API Library w Google API Console.
- If prompted, select a project, or create a new one.
- API Library Wyświetla wszystkie dostępne interfejsy API pogrupowane według rodziny produktów i popularności. Jeśli interfejs API, który chcesz włączyć, nie jest widoczny na liście, wyszukaj go lub kliknij Wyświetl wszystkie w grupie produktów, do której należy.
- Wybierz interfejs API, który chcesz włączyć, a następnie kliknij przycisk Włącz.
- If prompted, enable billing.
- If prompted, read and accept the API's Terms of Service.
Tworzenie danych uwierzytelniających
Każda aplikacja, która używa OAuth 2.0 do uzyskiwania dostępu do interfejsów API Google, musi mieć poświadczenia autoryzacyjne, które identyfikują ją na serwerze OAuth 2.0 Google. Z tych instrukcji dowiesz się, jak utworzyć poświadczenia tożsamości do projektu. Twoje aplikacje mogą wtedy używać tych danych logowania do uzyskiwania dostępu do interfejsów API, które zostały włączone w tym projekcie.
- Go to the Credentials page.
- Kliknij Utwórz dane logowania > Identyfikator klienta OAuth.
- Wybierz typ aplikacji Aplikacja internetowa.
- Wypełnij formularz i kliknij Utwórz. Aplikacje korzystające z języków i frameworków takich jak PHP, Java, Python, Ruby i .NET muszą określać autoryzowane identyfikatory URI przekierowania. URI przekierowania to punkty końcowe, do których serwer OAuth 2.0 może wysyłać odpowiedzi. Te punkty końcowe muszą być zgodne z regułami walidacji Google.
Na potrzeby testowania możesz podać identyfikatory URI odwołujące się do lokalnego komputera, np.
http://localhost:8080
. Pamiętaj, że wszystkie przykłady w tym dokumencie używają jako identyfikatora URI przekierowania wartościhttp://localhost:8080
.Zalecamy zaprojektowanie punktów końcowych autoryzacji aplikacji tak, aby aplikacja nie ujawniała kodów autoryzacji innym zasobom na stronie.
Po utworzeniu danych logowania pobierz plik client_secret.json z API Console. Bezpiecznie przechowuj plik w miejscu, do którego ma dostęp tylko Twoja aplikacja.
Określanie zakresów dostępu
Zakresy umożliwiają aplikacji żądanie dostępu tylko do zasobów, których potrzebuje, a także kontrolowanie przez użytkowników zakresu dostępu przyznawanego aplikacji. Dlatego może istnieć odwrotna zależność między liczbą żądanych zakresów uprawnień a prawdopodobieństwom uzyskania zgody użytkownika.
Zanim zaczniesz wdrażać autoryzację OAuth 2.0, zalecamy określenie zakresów, do których aplikacja będzie potrzebować uprawnień dostępu.
Zalecamy też, aby aplikacja prosiła o dostęp do zakresów autoryzacji za pomocą procesu uwierzytelniania stopniowego, w którym aplikacja prosi o dostęp do danych użytkownika w odpowiednim kontekście. Dzięki temu użytkownicy łatwiej zrozumieją, dlaczego Twoja aplikacja potrzebuje dostępu, o który prosi.
Dokument Zakresy interfejsu API OAuth 2.0 zawiera pełną listę zakresów, których możesz używać do uzyskiwania dostępu do interfejsów API Google.
Wymagania dotyczące poszczególnych języków
Aby uruchomić dowolny z fragmentów kodu w tym dokumencie, musisz mieć konto Google, dostęp do internetu i przeglądarkę internetową. Jeśli używasz jednej z bibliotek klienta interfejsu API, zapoznaj się też z poniżej wymienionymi wymaganiami dotyczącymi poszczególnych języków.
PHP
Aby uruchomić przykłady kodu PHP w tym dokumencie, musisz mieć:
- PHP w wersji 8.0 lub nowszej z zainstalowanym interfejsem wiersza poleceń (CLI) i rozszerzeniem JSON.
- Narzędzie do zarządzania zależnościami Composer.
-
Biblioteka klienta interfejsów Google API dla języka PHP:
composer require google/apiclient:^2.15.0
Więcej informacji znajdziesz w bibliotece klienta interfejsów API Google dla PHP.
Python
Aby uruchomić przykładowy kod Pythona w tym dokumencie, musisz mieć:
- Python w wersji 3.7 lub nowszej
- Narzędzie do zarządzania pakietami pip.
- Biblioteka klienta interfejsów API Google dla języka Python w wersji 2.0:
pip install --upgrade google-api-python-client
google-auth
,google-auth-oauthlib
igoogle-auth-httplib2
do autoryzacji użytkownika.pip install --upgrade google-auth google-auth-oauthlib google-auth-httplib2
- Platforma Flask do tworzenia aplikacji internetowych w Pythonie.
pip install --upgrade flask
- Biblioteka
requests
HTTP.pip install --upgrade requests
Jeśli nie możesz uaktualnić Pythona i powiązanego z nim przewodnika migracyjnego, zapoznaj się z notatkami do wersji biblioteki klienta interfejsu API Google dla języka Python.
Ruby
Aby uruchomić przykłady kodu Ruby w tym dokumencie, musisz mieć:
- Ruby w wersji 2.6 lub nowszej
-
Biblioteka Google Auth Library do Ruby:
gem install googleauth
-
Biblioteki klienta interfejsów API Dysku i Kalendarza Google:
gem install google-apis-drive_v3 google-apis-calendar_v3
-
Platforma do tworzenia aplikacji internetowych w Ruby o nazwie Sinatra.
gem install sinatra
Node.js
Aby uruchomić przykładowy kod Node.js w tym dokumencie, musisz mieć:
- Wersja LTS w ramach konserwacji, aktywna wersja LTS lub aktualna wersja Node.js.
-
Klient Node.js interfejsów API Google:
npm install googleapis crypto express express-session
HTTP/REST
Aby bezpośrednio wywoływać punkty końcowe OAuth 2.0, nie musisz instalować żadnych bibliotek.
Pobieranie tokenów dostępu OAuth 2.0
Te czynności pokazują, jak aplikacja wchodzi w interakcję z serwerem OAuth 2.0 Google, aby uzyskać zgodę użytkownika na wykonanie żądania interfejsu API w imieniu tego użytkownika. Aplikacja musi mieć tę zgodę, zanim będzie mogła wykonać żądanie interfejsu Google API, które wymaga autoryzacji użytkownika.
Poniżej znajdziesz listę podsumowującą te czynności:
- Aplikacja określa, których uprawnień potrzebuje.
- Aplikacja przekierowuje użytkownika do Google wraz z listą żądanych uprawnień.
- Użytkownik decyduje, czy przyznać aplikacji uprawnienia.
- Aplikacja sprawdza, jaką decyzję podjął użytkownik.
- Jeśli użytkownik przyznał wymagane uprawnienia, aplikacja pobiera tokeny potrzebne do wysyłania żądań interfejsu API w imieniu użytkownika.
Krok 1. Ustaw parametry autoryzacji
Pierwszym krokiem jest utworzenie żądania autoryzacji. Żądanie to zawiera parametry, które identyfikują Twoją aplikację i określają uprawnienia, o które użytkownik będzie proszony.
- Jeśli do uwierzytelniania i autoryzacji OAuth 2.0 używasz biblioteki klienta Google, musisz utworzyć i skonfigurować obiekt definiujący te parametry.
- Jeśli wywołasz punkt końcowy OAuth 2.0 Google bezpośrednio, wygenerujesz adres URL i ustawisz parametry tego adresu.
Na kartach poniżej znajdziesz listę obsługiwanych parametrów autoryzacji dla aplikacji serwera WWW. Przykłady w konkretnych językach pokazują też, jak za pomocą biblioteki klienta lub biblioteki autoryzacyjnej skonfigurować obiekt, który ustawia te parametry.
PHP
Poniższy fragment kodu tworzy obiekt Google\Client()
, który definiuje parametry w żądaniu autoryzacji.
Obiekt ten używa informacji z pliku client_secret.json do identyfikowania Twojej aplikacji. (więcej informacji o tym pliku znajdziesz w sekcji Tworzenie danych uwierzytelniających). Obiekt identyfikuje też zakresy, do których aplikacja prosi o dostęp, oraz adres URL punktu końcowego autoryzacji aplikacji, który będzie obsługiwać odpowiedź z serwera OAuth 2.0 Google. Na koniec kod ustawia opcjonalne parametry access_type
i include_granted_scopes
.
Ten kod prosi o dostęp tylko do odczytu do metadanych Dysku Google i wydarzeń w Kalendarzu w trybie offline:
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
Fragment kodu poniżej używa modułu google-auth-oauthlib.flow
do tworzenia żądania autoryzacji.
Kod tworzy obiekt Flow
, który identyfikuje Twoją aplikację za pomocą informacji z pliku client_secret.json pobranego po utworzeniu danych logowania autoryzujących. Obiekt ten identyfikuje zakresy, do których aplikacja prosi o dostęp, oraz adres URL punktu końcowego autoryzacji aplikacji, który będzie obsługiwał odpowiedź z serwera OAuth 2.0 Google. Na koniec kod ustawia opcjonalne parametry access_type
i include_granted_scopes
.
Ten kod prosi o dostęp tylko do odczytu do metadanych Dysku Google i wydarzeń w Kalendarzu w trybie offline:
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
Użyj utworzonego pliku client_secrets.json, aby skonfigurować obiekt klienta w aplikacji. Podczas konfigurowania obiektu klienta określasz zakresy, do których aplikacja musi mieć dostęp, oraz adres URL punktu końcowego autoryzacji aplikacji, który będzie obsługiwać odpowiedź z serwera OAuth 2.0.
Ten kod prosi o dostęp tylko do odczytu do metadanych Dysku Google i wydarzeń w Kalendarzu w trybie offline:
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)
Twoja aplikacja używa obiektu klienta do wykonywania operacji OAuth 2.0, takich jak generowanie adresów URL żądań autoryzacji i stosowanie tokenów dostępu do żądań HTTP.
Node.js
Poniższy fragment kodu tworzy obiekt google.auth.OAuth2
, który definiuje parametry w żądaniu autoryzacji.
Obiekt ten używa informacji z pliku client_secret.json do identyfikowania aplikacji. Aby poprosić użytkownika o uprawnienia do pobrania tokena dostępu, przekieruj go na stronę zgody. Aby utworzyć adres URL strony zgody:
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 });
Ważna uwaga: wartość refresh_token
jest zwracana tylko przy pierwszej autoryzacji. Więcej informacji znajdziesz
tutaj.
HTTP/REST
Punkt końcowy OAuth 2.0 Google znajduje się pod adresem https://accounts.google.com/o/oauth2/v2/auth
. Ten punkt końcowy jest dostępny tylko przez HTTPS. Połączenia HTTP nie są akceptowane.
Serwer autoryzacji Google obsługuje te parametry ciągu zapytania w przypadku aplikacji serwera WWW:
Parametry | |||||||
---|---|---|---|---|---|---|---|
client_id |
Wymagany
Identyfikator klienta Twojej aplikacji. Znajdziesz ją w sekcji API Console: Credentials page. |
||||||
redirect_uri |
Wymagany
Określa, dokąd serwer API przekieruje użytkownika po zakończeniu przez niego procesu autoryzacji. Wartość musi dokładnie pasować do jednego z autoryzowanych identyfikatorów URI przekierowania dla klienta OAuth 2.0 skonfigurowanego w API Console
Credentials page. Jeśli ta wartość nie pasuje do autoryzowanego identyfikatora URI przekierowania dla podanego identyfikatora Pamiętaj, że schemat |
||||||
response_type |
Wymagany
Określa, czy punkt końcowy Google OAuth 2.0 zwraca kod autoryzacji. W przypadku aplikacji serwera WWW ustaw wartość parametru na |
||||||
scope |
Wymagany
Oddzielona spacjami lista zakresów, które identyfikują zasoby, do których aplikacja może uzyskać dostęp w imieniu użytkownika. Te wartości informują o ekranie zgody, który Google wyświetla użytkownikowi. Zakresy umożliwiają aplikacji żądanie dostępu tylko do zasobów, których potrzebuje, a także kontrolowanie przez użytkowników zakresu dostępu przyznawanego aplikacji. W związku z tym istnieje odwrotna zależność między liczbą żądanych zakresów uprawnień a prawdopodobieństwom uzyskania zgody użytkownika. Zalecamy, aby aplikacja zawsze, gdy to możliwe, prosiła o dostęp do zakresów autoryzacji w kontekście. Wyświetlając prośby o dostęp do danych użytkownika w odpowiednim kontekście (stosując uwierzytelnianie stopniowe), pomagasz użytkownikom łatwiej zrozumieć, dlaczego Twoja aplikacja potrzebuje dostępu, o który prosi. |
||||||
access_type |
Zalecane
Wskazuje, czy aplikacja może odświeżać tokeny dostępu, gdy użytkownik nie jest obecny w przeglądarce. Prawidłowe wartości parametru to Jeśli aplikacja musi odświeżać tokeny dostępu, gdy użytkownik nie jest obecny w przeglądarce, ustaw tę wartość na |
||||||
state |
Zalecane
Określa dowolną wartość ciągu znaków, której aplikacja używa do zachowania stanu między żądaniem autoryzacji a odpowiedzią serwera autoryzacji.
Serwer zwraca dokładną wartość, którą wysyłasz jako parę Parametru tego można używać do różnych celów, np. do kierowania użytkownika do odpowiedniego zasobu w aplikacji, wysyłania identyfikatorów jednorazowych i ograniczania fałszowania żądań między witrynami. Ponieważ wartość |
||||||
include_granted_scopes |
Opcjonalny
Umożliwia aplikacjom korzystanie z uwierzytelniania stopniowego do żądania dostępu do dodatkowych zakresów w kontekście. Jeśli wartość tego parametru zostanie ustawiona na |
||||||
enable_granular_consent |
Opcjonalny
Domyślna wartość to Gdy Google włączy szczegółowe uprawnienia dla aplikacji, ten parametr przestanie mieć wpływ. |
||||||
login_hint |
Opcjonalny
Jeśli aplikacja wie, który użytkownik próbuje się uwierzytelnić, może użyć tego parametru, aby przekazać wskazówkę serwerowi uwierzytelniania Google. Serwer używa tego podpowiedzi do uproszczenia procesu logowania, wypełniając wstępnie pole adresu e-mail w formularzu logowania lub wybierając odpowiednią sesję logowania wielokrotnego. Ustaw wartość parametru jako adres e-mail lub identyfikator |
||||||
prompt |
Opcjonalny
Posortowana alfabetycznie lista promptów oddzielonych spacjami, w których wielkość liter ma znaczenie. Jeśli nie określisz tego parametru, użytkownik zobaczy prośbę tylko przy pierwszym żądaniu dostępu przez Twój projekt. Więcej informacji znajdziesz w artykule Prośba o ponowne wyrażenie zgody. Możliwe wartości to:
|
Krok 2. Przekieruj na serwer OAuth 2.0 Google
Przekieruj użytkownika na serwer OAuth 2.0 Google, aby zainicjować proces uwierzytelniania i autoryzacji. Zwykle dzieje się tak, gdy aplikacja musi po raz pierwszy uzyskać dostęp do danych użytkownika. W przypadku autoryzacji stopniowej ten krok występuje również wtedy, gdy aplikacja po raz pierwszy potrzebuje dostępu do dodatkowych zasobów, do których nie ma jeszcze uprawnień.
PHP
- Wygeneruj adres URL, aby poprosić o dostęp do serwera Google OAuth 2.0:
$auth_url = $client->createAuthUrl();
- Przekieruj użytkownika do
$auth_url
:header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
Python
Ten przykład pokazuje, jak przekierować użytkownika do adresu URL autoryzacji za pomocą platformy Flask do tworzenia aplikacji internetowych:
return flask.redirect(authorization_url)
Ruby
- Wygeneruj adres URL, aby poprosić o dostęp do serwera Google OAuth 2.0:
auth_uri = authorizer.get_authorization_url(request: request)
- Przekieruj użytkownika na stronę
auth_uri
.
Node.js
-
Aby poprosić o dostęp do serwera OAuth 2.0 Google, użyj wygenerowanego adresu URL
authorizationUrl
z etapu 1.generateAuthUrl
-
Przekieruj użytkownika na stronę
authorizationUrl
.res.redirect(authorizationUrl);
HTTP/REST
Przykładowe przekierowanie do serwera autoryzacji Google
Poniżej znajduje się przykładowy adres URL z przecinkami wierszy i spacją dla czytelności.
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//oauth2.example.com/code& client_id=client_id
Po utworzeniu adresu URL żądania przekieruj użytkownika na niego.
Serwer OAuth 2.0 Google uwierzytelnia użytkownika i uzyskiwanie od niego zgody na dostęp Twojej aplikacji do żądanych zakresów. Odpowiedź jest wysyłana z powrotem do aplikacji za pomocą podanego przez Ciebie adresu URL przekierowania.
Krok 3. Google prosi użytkownika o zgodę
Na tym etapie użytkownik decyduje, czy przyznać Twojej aplikacji wymagany dostęp. Na tym etapie Google wyświetla okno zgody, w którym podaje nazwę aplikacji i usługi interfejsu API Google, do której chce uzyskać dostęp, wraz z danymi autoryzującymi użytkownika oraz podsumowaniem zakresów dostępu. Użytkownik może wyrazić zgodę na przyznanie dostępu do co najmniej 1 zakresu żądanego przez Twoją aplikację lub odrzucić prośbę.
Na tym etapie aplikacja nie musi nic robić, ponieważ czeka na odpowiedź z serwera OAuth 2.0 Google, która wskazuje, czy przyznano dostęp. Odpowiedź na to pytanie znajdziesz w następnym kroku.
Błędy
Żądania do punktu końcowego autoryzacji OAuth 2.0 Google mogą wyświetlać komunikaty o błędach zamiast oczekiwanych procesów uwierzytelniania i autoryzacji. Poniżej znajdziesz listę typowych kodów błędów i sugerowanych rozwiązań.
admin_policy_enforced
Konto Google nie może autoryzować co najmniej 1 żądanego zakresu uprawnień z powodu zasad administratora Google Workspace. Więcej informacji o tym, jak administrator może ograniczyć dostęp do wszystkich zakresów lub zakresów poufnych i ograniczonych, dopóki nie zostanie wyraźnie przyznany dostęp do Twojego identyfikatora klienta OAuth, znajdziesz w artykule pomocy dla administratorów Google Workspace Control which third-party & internal apps access Google Workspace data.
disallowed_useragent
Punkt końcowy autoryzacji jest wyświetlany w ramach wbudowanego użytkownika-agenta, który jest niedozwolony przez zasady OAuth 2.0 Google.
Android
Deweloperzy aplikacji na Androida mogą zobaczyć ten komunikat o błędzie podczas otwierania żądań autoryzacji w android.webkit.WebView
.
Deweloperzy powinni zamiast tego używać bibliotek Androida, takich jak Logowanie przez Google na Androida czy AppAuth na Androida od OpenID Foundation.
Deweloperzy mogą napotkać ten błąd, gdy aplikacja na Androida otwiera ogólny link internetowy w osadzonym user-agent i użytkownik przechodzi na punkt końcowy autoryzacji OAuth 2 Google z Twojej witryny. Deweloperzy powinni zezwolić na otwieranie ogólnych linków w domyślnym obsłudze linków systemu operacyjnego, co obejmuje zarówno obsługę linków aplikacji na Androida, jak i domyślną aplikację przeglądarki. Biblioteka kart niestandardowych Androida jest też obsługiwaną opcją.
iOS
Deweloperzy iOS i macOS mogą napotkać ten błąd podczas otwierania próśb o autoryzację w WKWebView
.
Deweloperzy powinni zamiast tego używać bibliotek iOS, takich jak Google Sign-In na iOS czy AppAuth na iOS od OpenID Foundation.
Deweloperzy witryn mogą napotkać ten błąd, gdy aplikacja na iOS lub macOS otwiera ogólny link internetowy w osadzonym user-agent i użytkownik przechodzi do punktu autoryzacji OAuth 2.0 Google z Twojej witryny. Deweloperzy powinni zezwolić na otwieranie ogólnych linków w domyślnym obsłudze linków systemu operacyjnego, który obejmuje zarówno obsługę linków uniwersalnych, jak i domyślną aplikację przeglądarki. Biblioteka SFSafariViewController
jest też obsługiwaną opcją.
org_internal
Identyfikator klienta OAuth w żądaniu należy do projektu, który ogranicza dostęp do kont Google w określonej organizacji Google Cloud. Więcej informacji o tej opcji konfiguracji znajdziesz w sekcji Typ użytkownika w artykule pomocy Konfigurowanie ekranu zgody OAuth.
invalid_client
Tajny klucz klienta OAuth jest nieprawidłowy. Sprawdź konfigurację klienta OAuth, w tym identyfikator klienta i klucz tajny użyte w tej prośbie.
invalid_grant
Podczas odświeżania tokena dostępu lub korzystania z autoryzacji stopniowej token może być nieważny lub wygasł. Użytkownik musi się ponownie uwierzytelnić i wyrazić zgodę na uzyskanie nowych tokenów. Jeśli ten błąd będzie się powtarzał, sprawdź, czy aplikacja jest prawidłowo skonfigurowana i czy używasz w żądaniu prawidłowych tokenów i parametrów. W przeciwnym razie konto użytkownika mogło zostać usunięte lub wyłączone.
redirect_uri_mismatch
Wartość redirect_uri
przekazana w żądaniu autoryzacji nie odpowiada autoryzowanemu identyfikatorowi URI przekierowania dla identyfikatora klienta OAuth. Sprawdź autoryzowane identyfikatory URI przekierowania w sekcji Google API Console Credentials page.
Parametr redirect_uri
może odnosić się do przesyłania poza pasmem (OOB) w ramach protokołu OAuth, które zostało wycofane i nie jest już obsługiwane. Aby zaktualizować integrację, zapoznaj się z przewodnikiem po migracji.
invalid_request
Coś poszło nie tak z Twoją prośbą. Może to wynikać z kilku powodów:
- żądanie jest nieprawidłowo sformatowane;
- Brak wymaganych parametrów w prośbie
- Żądanie używa metody autoryzacji, której Google nie obsługuje. Sprawdź, czy integracja OAuth używa zalecanej metody integracji
Krok 4. Przetwórz odpowiedź serwera OAuth 2.0
Serwer OAuth 2.0 odpowiada na żądanie dostępu aplikacji, używając adresu URL podanego w żądaniu.
Jeśli użytkownik zaakceptuje prośbę o dostęp, odpowiedź będzie zawierać kod autoryzacji. Jeśli użytkownik nie zatwierdzi prośby, odpowiedź będzie zawierać komunikat o błędzie. Kod autoryzacji lub komunikat o błędzie zwrócony do serwera WWW jest widoczny w ciagu zapytania, jak pokazano poniżej:
Odpowiedź błędu:
https://oauth2.example.com/auth?error=access_denied
Odpowiedź na kod autoryzacji:
https://oauth2.example.com/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7
Przykładowa odpowiedź serwera OAuth 2.0
Możesz przetestować ten proces, klikając ten przykładowy adres URL, który prosi o dostęp tylko do odczytu w celu wyświetlania metadanych plików na Dysku Google oraz dostęp tylko do odczytu w celu wyświetlania wydarzeń w Kalendarzu 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//oauth2.example.com/code& client_id=client_id
Po zakończeniu procesu OAuth 2.0 powinieneś zostać przekierowany na adres
http://localhost/oauth2callback
, który prawdopodobnie spowoduje błąd
404 NOT FOUND
, chyba że na Twoim komputerze lokalnym znajduje się plik pod tym adresem. Następny krok zapewnia więcej szczegółów o informacjach zwróconych w identyfikatorze URI, gdy użytkownik zostanie przekierowany z powrotem do aplikacji.
Krok 5. Wymień kod autoryzacji na tokeny odświeżania i dostępu
Gdy serwer internetowy otrzyma kod autoryzacji, może go wymienić na token dostępu.
PHP
Aby zamienić kod autoryzacji na token dostępu, użyj metody fetchAccessTokenWithAuthCode
:
$access_token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
Python
Na stronie wywołania zwrotnego użyj biblioteki google-auth
, aby zweryfikować odpowiedź serwera autoryzacji. Następnie użyj metody flow.fetch_token
, aby zamienić kod autoryzacji w tej odpowiedzi na token dostępu:
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 the session. # ACTION ITEM for developers: # Store user's access and refresh tokens in your data store if # incorporating this code into your real app. credentials = flow.credentials flask.session['credentials'] = { 'token': credentials.token, 'refresh_token': credentials.refresh_token, 'token_uri': credentials.token_uri, 'client_id': credentials.client_id, 'client_secret': credentials.client_secret, 'granted_scopes': credentials.granted_scopes}
Ruby
Na stronie wywołania zwrotnego użyj biblioteki googleauth
, aby zweryfikować odpowiedź serwera autoryzacji. Użyj metody authorizer.handle_auth_callback_deferred
, aby zapisać kod autoryzacji i przekierować użytkownika z powrotem do adresu URL, który pierwotnie poprosił o autoryzację. Oznacza to odroczenie wymiany kodu przez tymczasowe przechowywanie wyników w sesji użytkownika.
target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request) redirect target_url
Node.js
Aby zamienić kod autoryzacji na token dostępu, użyj metody 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
Aby wymienić kod autoryzacji na token dostępu, wywołaj punkt końcowy https://oauth2.googleapis.com/token
i ustaw te parametry:
Pola | |
---|---|
client_id |
Identyfikator klienta uzyskany z API Console Credentials page. |
client_secret |
Tajny klucz klienta uzyskany z API Console Credentials page. |
code |
Kod autoryzacji zwrócony w odpowiedzi na początkowe żądanie. |
grant_type |
Zgodnie ze specyfikacją OAuth 2.0 wartość tego pola musi wynosić authorization_code . |
redirect_uri |
Jeden z identyfikatorów URI przekierowania podanych w przypadku Twojego projektu w sekcji API Console
Credentials page w przypadku danego client_id . |
Ten fragment kodu pokazuje przykładowe żądanie:
POST /token HTTP/1.1 Host: oauth2.googleapis.com Content-Type: application/x-www-form-urlencoded code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7& client_id=your_client_id& client_secret=your_client_secret& redirect_uri=https%3A//oauth2.example.com/code& grant_type=authorization_code
W odpowiedzi na to żądanie Google zwraca obiekt JSON zawierający krótkotrwały token dostępu i token odświeżania.
Pamiętaj, że token odświeżania jest zwracany tylko wtedy, gdy Twoja aplikacja ustawia parametr access_type
na offline
w pierwotnym żądaniu do serwera autoryzacji Google.
Odpowiedź zawiera te pola:
Pola | |
---|---|
access_token |
Token wysyłany przez aplikację w celu autoryzacji żądania interfejsu Google API. |
expires_in |
Pozostały czas ważności tokena dostępu w sekundach. |
refresh_token |
Token, którego możesz użyć do uzyskania nowego tokena dostępu. Tokeny odświeżania są ważne do czasu, gdy użytkownik anuluje dostęp.
Ponownie to pole jest obecne w tej odpowiedzi tylko wtedy, gdy w początkowej prośbie do serwera autoryzacji Google ustawisz parametr access_type na offline .
|
scope |
Zakresy dostępu przyznane przez access_token wyrażone jako lista rozróżniających wielkość liter ciągów znaków oddzielonych spacjami. |
token_type |
Typ zwróconego tokena. Obecnie wartość tego pola zawsze wynosiBearer . |
Ten fragment kodu pokazuje przykładową odpowiedź:
{ "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" }
Błędy
Podczas wymiany kodu autoryzacji na token dostępu zamiast oczekiwanej odpowiedzi możesz zobaczyć ten błąd: Poniżej znajdziesz listę typowych kodów błędów i sugerowane rozwiązania.
invalid_grant
Podany kod autoryzacji jest nieprawidłowy lub ma nieprawidłowy format. Poproś o nowy kod, rozpoczynając ponownie proces OAuth, aby ponownie poprosić użytkownika o wyrażenie zgody.
Krok 6. Sprawdź, jakie zakresy przyznali użytkownicy
Gdy żądasz kilku zakresów uprawnień naraz, użytkownicy mogą nie przyznać wszystkich zakresów, których potrzebuje Twoja aplikacja. Aplikacja powinna zawsze sprawdzać, jakie zakresy zostały przyznane przez użytkownika, i reagować na odmowę przyznania zakresów, wyłączając odpowiednie funkcje. Więcej informacji znajdziesz w artykule Zarządzanie szczegółowymi uprawnieniami.
PHP
Aby sprawdzić, jakie zakresy zostały przyznane przez użytkownika, użyj metody 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
Zwrócony obiekt credentials
ma właściwość granted_scopes
, która jest listą zakresów uprawnień przyznanych przez użytkownika Twojej aplikacji.
credentials = flow.credentials flask.session['credentials'] = { 'token': credentials.token, 'refresh_token': credentials.refresh_token, 'token_uri': credentials.token_uri, 'client_id': credentials.client_id, 'client_secret': credentials.client_secret, 'granted_scopes': credentials.granted_scopes}
Poniższa funkcja sprawdza, jakie zakresy użytkownik przyznał Twojej aplikacji.
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
Gdy żądasz kilku zakresów uprawnień jednocześnie, sprawdź, które zakresy zostały przyznane za pomocą właściwości scope
obiektu 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
Gdy żądasz kilku zakresów uprawnień jednocześnie, sprawdź, które zakresy zostały przyznane za pomocą właściwości scope
obiektu 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
Aby sprawdzić, czy użytkownik przyznał aplikacji dostęp do określonego zakresu, sprawdź pole scope
w odpowiedzi na żądanie tokena dostępu. Zakresy dostępu przyznawane przez token dostępu w postaci listy ciągów znaków oddzielonych spacjami, w których rozróżniane są wielkość liter.
Na przykład ta przykładowa odpowiedź na żądanie tokena dostępu wskazuje, że użytkownik przyznał Twojej aplikacji uprawnienia do odczytu aktywności na Dysku i do wydarzeń w Kalendarzu:
{ "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" }
Wywoływanie interfejsów API Google
PHP
Aby użyć tokena dostępu do wywołania interfejsów Google API, wykonaj te czynności:
- Jeśli chcesz zastosować token dostępu do nowego obiektu
Google\Client
(np. jeśli został on zapisany w sesji użytkownika), użyj metodysetAccessToken
:$client->setAccessToken($access_token);
- Utwórz obiekt usługi dla interfejsu API, który chcesz wywołać. Obiekt usługi tworzysz, przekazując autoryzowany obiekt
Google\Client
do konstruktora interfejsu API, który chcesz wywołać. Aby na przykład wywołać interfejs Drive API:$drive = new Google\Service\Drive($client);
- Wysyłać żądania do usługi interfejsu API za pomocą
interfejsu udostępnionego przez obiekt usługi.
Aby na przykład wyświetlić listę plików na Dysku Google uwierzytelnionego użytkownika:
$files = $drive->files->listFiles(array());
Python
Po uzyskaniu tokena dostępu aplikacja może go używać do autoryzowania żądań interfejsu API w imieniu danego konta użytkownika lub konta usługi. Użyj danych autoryzujących konkretnego użytkownika, aby utworzyć obiekt usługi dla interfejsu API, który chcesz wywołać, a potem użyj tego obiektu do autoryzowania żądań interfejsu API.
- Utwórz obiekt usługi dla interfejsu API, który chcesz wywołać. Obiekt usługi tworzysz, wywołując metodę
googleapiclient.discovery
bibliotekibuild
z nazwą i wersją interfejsu API oraz danymi logowania użytkownika: Aby na przykład wywołać wersję 3 interfejsu Drive API:from googleapiclient.discovery import build drive = build('drive', 'v2', credentials=credentials)
- Wysyłać żądania do usługi interfejsu API za pomocą interfejsu udostępnionego przez obiekt usługi.
Aby na przykład wyświetlić listę plików na Dysku Google uwierzytelnionego użytkownika:
files = drive.files().list().execute()
Ruby
Po uzyskaniu tokena dostępu aplikacja może go używać do wysyłania żądań do interfejsu API w imieniu danego konta użytkownika lub konta usługi. Użyj danych autoryzujących konkretnego użytkownika, aby utworzyć obiekt usługi dla interfejsu API, który chcesz wywołać, a potem użyj tego obiektu do autoryzowania żądań interfejsu API.
- Utwórz obiekt usługi dla interfejsu API, który chcesz wywołać.
Aby na przykład wywołać wersję 3 interfejsu Drive API:
drive = Google::Apis::DriveV3::DriveService.new
- Ustaw dane uwierzytelniające w usłudze:
drive.authorization = credentials
- Wysyłać żądania do usługi interfejsu API za pomocą interfejsu udostępnionego przez obiekt usługi.
Aby na przykład wyświetlić listę plików na Dysku Google uwierzytelnionego użytkownika:
files = drive.list_files
Autoryzację można też uzyskać w ramach poszczególnych metod, podając parametr options
:
files = drive.list_files(options: { authorization: credentials })
Node.js
Po uzyskaniu tokena dostępu i przypisaniu go do obiektu OAuth2
możesz używać tego obiektu do wywoływania interfejsów API Google. Aplikacja może używać tego tokena do autoryzowania żądań interfejsu API w imieniu danego konta użytkownika lub konta usługi. Utwórz obiekt usługi dla interfejsu API, który chcesz wywołać.
Na przykład poniższy kod używa interfejsu Google Drive API do wyświetlenia nazw plików na Dysku użytkownika.
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
Gdy aplikacja uzyska token dostępu, możesz używać tego tokena do wywoływania interfejsów API Google w imieniu danego konta użytkownika, jeśli przyznano uprawnienia dostępu wymagane przez interfejs API. Aby to zrobić, dodaj token dostępu do żądania do interfejsu API, podając parametr zapytania access_token
lub wartość nagłówka HTTP Authorization
Bearer
. Jeśli to możliwe, zalecamy użycie nagłówka HTTP, ponieważ ciągi znaków zapytania są zwykle widoczne w dziennikach serwera. W większości przypadków do konfigurowania wywołań interfejsów API Google możesz użyć biblioteki klienta (np. podczas wywołania interfejsu Drive API).
Możesz wypróbować wszystkie interfejsy API Google i wyświetlić ich zakresy na stronie OAuth 2.0 Playground.
Przykłady żądań HTTP GET
Wywołanie punktu końcowego
drive.files
(interfejsu Drive Files API) za pomocą nagłówka HTTP Authorization: Bearer
może wyglądać tak: Pamiętaj, że musisz podać własny token dostępu:
GET /drive/v2/files HTTP/1.1 Host: www.googleapis.com Authorization: Bearer access_token
Oto wywołanie tego samego interfejsu API dla uwierzytelnionego użytkownika za pomocą parametru ciągu zapytania access_token
:
GET https://www.googleapis.com/drive/v2/files?access_token=access_token
curl
przykładu
Te polecenia możesz przetestować za pomocą aplikacji wiersza poleceń curl
. Oto przykład użycia opcji nagłówka HTTP (preferowana):
curl -H "Authorization: Bearer access_token" https://www.googleapis.com/drive/v2/files
Możesz też użyć parametru ciągu zapytania:
curl https://www.googleapis.com/drive/v2/files?access_token=access_token
Pełny przykład
W tym przykładzie wypisuje się lista plików na Dysku Google użytkownika w formacie JSON po jego uwierzytelnieniu i wyrażeniu zgody na dostęp aplikacji do metadanych Dysku.
PHP
Aby uruchomić ten przykład:
- W sekcji API Consoledodaj adres URL lokalnego komputera do listy adresów URL przekierowań. Dodaj na przykład
http://localhost:8080
. - Utwórz nowy katalog i przejdź do niego. Na przykład:
mkdir ~/php-oauth2-example cd ~/php-oauth2-example
- Zainstaluj bibliotekę klienta interfejsu API Google dla języka PHP za pomocą Composera:
composer require google/apiclient:^2.15.0
- Utwórz pliki
index.php
ioauth2callback.php
z podaną niżej treścią. - Uruchom przykład na wbudowanym serwerze WWW 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
W tym przykładzie używamy frameworka Flask. Uruchom aplikację internetową na stronie http://localhost:8080
, aby przetestować przepływ OAuth 2.0. Po kliknięciu tego adresu URL zobaczysz 5 linków:
- Wywołanie interfejsu Drive API: ten link prowadzi do strony, która próbuje wykonać przykładowe żądanie interfejsu API, jeśli użytkownicy udzielili uprawnień. W razie potrzeby rozpoczyna proces autoryzacji. Jeśli operacja się powiedzie, na stronie wyświetli się odpowiedź interfejsu API.
- Strony testowe do wywoływania interfejsu Calendar API: ten link prowadzi do strony testowej, która próbuje wykonać przykładowe żądanie interfejsu Calendar API, jeśli użytkownicy udzielą odpowiedniego uprawnienia. W razie potrzeby rozpoczyna proces autoryzacji. Jeśli operacja się powiedzie, na stronie wyświetli się odpowiedź interfejsu API.
- Testowanie procesu uwierzytelniania bezpośrednio: ten link prowadzi do strony, która próbuje przekierować użytkownika do procesu autoryzacji. Aplikacja prosi o przyznanie uprawnień do przesyłania autoryzowanych żądań interfejsu API w imieniu użytkownika.
- Anuluj bieżące dane logowania: ten link prowadzi do strony, na której unieważniasz uprawnienia, które użytkownik już przyznał aplikacji.
- Wyczyść dane logowania sesji Flask: ten link usuwa dane logowania uwierzytelniające, które są przechowywane w sesji Flask. Dzięki temu możesz sprawdzić, co się stanie, jeśli użytkownik, który już przyznał uprawnienia Twojej aplikacji, spróbuje wykonać w nowej sesji żądanie interfejsu API. Dzięki temu możesz też zobaczyć odpowiedź interfejsu API, którą Twoja aplikacja otrzymałaby, gdyby użytkownik cofnąłby jej uprawnienia, a aplikacja nadal próbowałaby autoryzować żądanie przy użyciu cofniętego tokena dostępu.
# -*- coding: utf-8 -*- import os import flask 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 credentials from the session. credentials = google.oauth2.credentials.Credentials( **flask.session['credentials']) 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. # ACTION ITEM: In a production app, you likely want to save these # credentials in a persistent database instead. flask.session['credentials'] = credentials_to_dict(credentials) return flask.jsonify(**files) else: # User didn't authorize read-only Drive activity permission. # Update UX and application accordingly 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.') credentials = google.oauth2.credentials.Credentials( **flask.session['credentials']) 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: 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, 'token_uri': credentials.token_uri, 'client_id': credentials.client_id, 'client_secret': credentials.client_secret, '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="/test">Test an API request</a></td>' + '<td>Submit an API request and see a formatted JSON response. ' + ' Go through the authorization flow if there are no stored ' + ' credentials for the user.</td></tr>' + '<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="/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="/test">test the ' + ' API request</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
W tym przykładzie użyto frameworka 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
Aby uruchomić ten przykład:
-
W sekcji API Consoledodaj adres URL lokalnego komputera do listy adresów URL przekierowań. Na przykład:
http://localhost
. - Upewnij się, że masz zainstalowaną wersję LTS w ramach konserwacji, aktywną wersję LTS lub najnowszą wersję Node.js.
-
Utwórz nowy katalog i przejdź do niego. Na przykład:
mkdir ~/nodejs-oauth2-example cd ~/nodejs-oauth2-example
-
Zainstaluj bibliotekę klienta interfejsu Google API dla Node.js za pomocą npm:
npm install googleapis
-
Utwórz pliki
main.js
z podaną niżej treścią. -
Uruchom przykład:
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
Ten przykład w języku Python korzysta z platformy Flask i biblioteki Requests, aby zademonstrować proces internetowy OAuth 2.0. W tym przypadku zalecamy użycie biblioteki klienta interfejsu API Google dla języka Python. (Przykład na karcie Python korzysta z biblioteki klienta).
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()
Reguły weryfikacji identyfikatora URI przekierowania
Aby pomóc deweloperom w zapewnieniu bezpieczeństwa ich aplikacji, Google stosuje do identyfikatorów URI przekierowania te reguły sprawdzania. Identyfikatory URI przekierowania muszą być zgodne z tymi zasadami. Definicje wymienionych poniżej terminów: domena, host, ścieżka, zapytanie, schemat i userinfo znajdziesz w sekcji 3 specyfikacji RFC 3986.
Reguły weryfikacji | |
---|---|
Schemat |
Identyfikatory URI przekierowania muszą używać schematu HTTPS, a nie zwykłego HTTP. Identyfikatory URI localhost (w tym identyfikatory URI adresów IP localhost) są wyłączone z zasięgu tej reguły. |
Osoba prowadząca |
Hostami nie mogą być zwykłe adresy IP. Z tej reguły wyłączone są adresy IP lokalnego hosta. |
Domena |
“googleusercontent.com” .goo.gl ), chyba że domena należy do aplikacji. Jeśli aplikacja, która jest właścicielem domeny skróty, zdecyduje się na przekierowanie do tej domeny, identyfikator URI przekierowania musi zawierać “/google-callback/” w ścieżce lub kończyć się na “/google-callback” . |
Informacje o użytkowniku |
Identyfikatory URI przekierowania nie mogą zawierać podelementu userinfo. |
Ścieżka |
Identyfikatory URI przekierowania nie mogą zawierać przemierzania ścieżki (zwanego też cofaniem się do katalogu), które jest reprezentowane przez |
Zapytanie |
Identyfikatory URI przekierowania nie mogą zawierać otwartych przekierowań. |
Fragment |
Identyfikatory URI przekierowania nie mogą zawierać komponentu fragmentu. |
Znaki |
Identyfikatory URI przekierowania nie mogą zawierać pewnych znaków, w tym:
|
Autoryzacja przyrostowa
W protokole OAuth 2.0 aplikacja prosi o autoryzację dostępu do zasobów, które są identyfikowane przez zakresy. W ramach najlepszej praktyki dotyczącej komfortu użytkowników należy poprosić o autoryzację zasobów w chwili, gdy są one potrzebne. Aby umożliwić tę praktykę, serwer autoryzacji Google obsługuje autoryzację przyrostową. Ta funkcja umożliwia żądanie zakresów w miarę potrzeby, a jeśli użytkownik przyzna uprawnienia do nowego zakresu, zwraca kod autoryzacji, który można wymienić na token zawierający wszystkie zakresy przyznane przez użytkownika projektowi.
Na przykład aplikacja, która umożliwia użytkownikom odsłuchiwanie fragmentów utworów muzycznych i tworzenie miksów, może potrzebować bardzo niewielu zasobów w momencie logowania się, być może tylko nazwy logującej się osoby. Zapisanie gotowego miksu wymaga jednak dostępu do Dysku Google. Większość osób uznałaby za naturalne, że aplikacja poprosi o dostęp do Dysku Google tylko wtedy, gdy będzie go potrzebować.
W tym przypadku podczas logowania aplikacja może poprosić o uprawnienia openid
i profile
, aby przeprowadzić podstawowe logowanie, a potem poprosić o uprawnienia https://www.googleapis.com/auth/drive.file
w momencie wysłania pierwszego żądania, aby zaoszczędzić czas.
Aby wdrożyć autoryzację cząstkową, wykonaj normalny proces żądania tokena dostępu, ale upewnij się, że żądanie autoryzacji zawiera wcześniej przyznane zakresy. Dzięki temu nie musisz zarządzać wieloma tokenami dostępu.
W przypadku tokena dostępu uzyskanego z autoryzacji stopniowej obowiązują te reguły:
- Token może służyć do uzyskiwania dostępu do zasobów odpowiadających zakresom włączonym do nowej, połączonej autoryzacji.
- Gdy użyjesz tokena odświeżania do autoryzacji połączonej, aby uzyskać token dostępu, token dostępu będzie reprezentować autoryzację połączoną i może być użyty do dowolnej wartości
scope
zawartej w odpowiedzi. - Połączona autoryzacja obejmuje wszystkie zakresy dostępu przyznane przez użytkownika projektowi interfejsu API, nawet jeśli prośby o te uprawnienia zostały wysłane z różnych klientów. Jeśli na przykład użytkownik przyznał dostęp do jednego zakresu za pomocą klienta aplikacji na komputer, a następnie przyznał inny zakres do tej samej aplikacji za pomocą klienta mobilnego, połączone upoważnienie będzie obejmować oba zakresy.
- Jeśli cofniesz token reprezentujący autoryzację łączoną, dostęp do wszystkich zakresów autoryzacji w imieniu powiązanego użytkownika zostanie cofnięta jednocześnie.
Przykłady kodu w różnych językach w sekcji Krok 1. Ustaw parametry autoryzacji oraz przykładowy adres URL przekierowania HTTP/REST w sekcji Krok 2. Przekieruj na serwer OAuth 2.0 korzystają z autoryzacji stopniowej. Przykłady kodu poniżej zawierają też kod, który musisz dodać, aby korzystać z autoryzacji cząstkowej.
PHP
$client->setIncludeGrantedScopes(true);
Python
W Pythonie ustaw argument include_granted_scopes
na true
, aby zapytanie o autoryzację zawierało wcześniej przyznane zakresy. Jest bardzo prawdopodobne, że include_granted_scopes
nie będzie jedynym ustawionym przez Ciebie argumentem słowa kluczowego, jak pokazano w przykładzie poniżej.
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//oauth2.example.com/code& prompt=consent& include_granted_scopes=true
Odświeżanie tokena dostępu (dostęp offline)
Tokeny dostępu okresowo wygasają i stają się nieprawidłowymi danymi logowania w przypadku powiązanego żądania interfejsu API. Jeśli poprosisz o dostęp offline do zakresów powiązanych z tokenem, możesz odświeżyć token dostępu bez wyświetlania użytkownikowi prośby o pozwolenie (także wtedy, gdy użytkownika nie ma w pobliżu).
- Jeśli używasz biblioteki klienta interfejsu API Google, obiekt klienta odświeża token dostępu w miarę potrzeby, o ile konfigurujesz ten obiekt do dostępu offline.
- Jeśli nie używasz biblioteki klienta, musisz ustawić parametr zapytania HTTP
access_type
naoffline
, gdy przekierowujesz użytkownika na serwer OAuth 2.0 Google. W takim przypadku serwer autoryzacji Google zwraca token odświeżania, gdy wymieniasz kod autoryzacji na token dostępu. Następnie, jeśli token dostępu wygaśnie (lub w dowolnym innym momencie), możesz użyć tokena odświeżania, aby uzyskać nowy token dostępu.
Żądanie dostępu offline jest wymagane w przypadku każdej aplikacji, która potrzebuje dostępu do interfejsu Google API, gdy użytkownika nie ma w pobliżu. Na przykład aplikacja, która wykonuje usługi kopii zapasowej lub wykonuje działania w określonym czasie, musi mieć możliwość odświeżania tokena dostępu, gdy użytkownika nie ma. Domyślny styl dostępu to online
.
Aplikacje internetowe po stronie serwera, zainstalowane aplikacje i urządzenia uzyskują tokeny odświeżania podczas procesu autoryzacji. Tokeny odświeżania nie są zwykle używane w aplikacjach internetowych po stronie klienta (JavaScript).
PHP
Jeśli aplikacja potrzebuje dostępu do interfejsu API Google w trybie offline, ustaw typ dostępu klienta API na:offline
:
$client->setAccessType("offline");
Gdy użytkownik przyzna dostęp offline do żądanych zakresów, możesz nadal używać klienta interfejsu API, aby uzyskiwać dostęp do interfejsów API Google w imieniu użytkownika, gdy ten jest offline. Obiekt klienta odświeży token dostępu w razie potrzeby.
Python
W Pythonie ustaw argument access_type
na offline
, aby mieć możliwość odświeżania tokena dostępu bez konieczności ponownego prośby o pozwolenie od użytkownika. Jest bardzo prawdopodobne, że access_type
nie będzie jedynym argumentem słowa kluczowego, jak w przykładzie poniżej.
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')
Gdy użytkownik przyzna dostęp offline do żądanych zakresów, możesz nadal używać klienta interfejsu API, aby uzyskiwać dostęp do interfejsów API Google w imieniu użytkownika, gdy ten jest offline. Obiekt klienta odświeży token dostępu w razie potrzeby.
Ruby
Jeśli aplikacja potrzebuje dostępu do interfejsu API Google w trybie offline, ustaw typ dostępu klienta API na:offline
:
auth_client.update!( :additional_parameters => {"access_type" => "offline"} )
Gdy użytkownik przyzna dostęp offline do żądanych zakresów, możesz nadal używać klienta interfejsu API, aby uzyskiwać dostęp do interfejsów API Google w imieniu użytkownika, gdy ten jest offline. Obiekt klienta odświeży token dostępu w razie potrzeby.
Node.js
Jeśli aplikacja potrzebuje dostępu do interfejsu API Google w trybie offline, ustaw typ dostępu klienta API na: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 });
Gdy użytkownik przyzna dostęp offline do żądanych zakresów, możesz nadal używać klienta interfejsu API, aby uzyskiwać dostęp do interfejsów API Google w imieniu użytkownika, gdy ten jest offline. Obiekt klienta odświeży token dostępu w razie potrzeby.
Tokeny dostępu wygasają. Jeśli token dostępu ma wygasnąć, biblioteka automatycznie użyje tokenu odświeżania, aby uzyskać nowy token dostępu. Aby zawsze przechowywać najnowsze tokeny, możesz użyć zdarzenia „tokens”:
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); });
To zdarzenie tokena występuje tylko podczas pierwszej autoryzacji. Aby otrzymać token odświeżania, musisz ustawić parametr access_type
na offline
podczas wywoływania metody generateAuthUrl
. Jeśli aplikacja ma już wymagane uprawnienia, ale nie ma ustawionych odpowiednich ograniczeń dotyczących otrzymywania tokena odświeżania, musisz ponownie autoryzować aplikację, aby otrzymać nowy token odświeżania.
Aby ustawić refresh_token
w późniejszym czasie, możesz użyć metody setCredentials
:
oauth2Client.setCredentials({ refresh_token: `STORED_REFRESH_TOKEN` });
Gdy klient otrzyma token odświeżania, tokeny dostępu będą pobierane i odświeżane automatycznie podczas następnego wywołania interfejsu API.
HTTP/REST
Aby odświeżyć token dostępu, aplikacja wysyła żądanie HTTPS POST
do serwera autoryzacji Google (https://oauth2.googleapis.com/token
), które zawiera te parametry:
Pola | |
---|---|
client_id |
Identyfikator klienta uzyskany z API Console. |
client_secret |
Tajny klucz klienta uzyskany z API Console. |
grant_type |
Zgodnie z specyfikacją OAuth 2.0 wartość tego pola musi wynosić refresh_token . |
refresh_token |
Token odświeżania zwrócony z wymiany kodu autoryzacji. |
Ten fragment kodu pokazuje przykładowe żądanie:
POST /token HTTP/1.1 Host: oauth2.googleapis.com Content-Type: application/x-www-form-urlencoded client_id=your_client_id& client_secret=your_client_secret& refresh_token=refresh_token& grant_type=refresh_token
Dopóki użytkownik nie cofnie przyznanego aplikacji dostępu, serwer tokenów zwraca obiekt JSON zawierający nowy token dostępu. Ten fragment kodu pokazuje przykładową odpowiedź:
{ "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" }
Pamiętaj, że liczba wydawanych tokenów odświeżania jest ograniczona. Jeden limit dotyczy kombinacji klient/użytkownik, a drugi – wszystkich klientów. Tokeny odświeżania należy zapisać w długoterminowym magazynie danych i nadal z nich korzystać, dopóki są ważne. Jeśli aplikacja wysyła zbyt dużo żądań dotyczących tokenów odświeżania, może przekroczyć te limity. W takim przypadku starsze tokeny odświeżania przestaną działać.
Unieważnianie tokena
W niektórych przypadkach użytkownik może chcieć cofnąć dostęp aplikacji. Użytkownik może cofnąć dostęp, otwierając Ustawienia konta. Więcej informacji znajdziesz w sekcji Usuwanie dostępu strony lub aplikacji do Twojego konta w dokumentacji pomocy Strony internetowe i aplikacje innych firm z dostępem do Twojego konta.
Aplikacja może też automatycznie cofnąć przyznany dostęp. Automatyczne odwoływanie jest ważne w przypadkach, gdy użytkownik zrezygnuje z subskrypcji, usunie aplikację lub zasoby interfejsu API wymagane przez aplikację ulegną znacznym zmianom. Innymi słowy, część procesu usuwania może obejmować żądanie interfejsu API, aby usunąć uprawnienia wcześniej przyznane aplikacji.
PHP
Aby programowo unieważnić token, wywołaj funkcję revokeToken()
:
$client->revokeToken();
Python
Aby programowo unieważnić token, wyślij żądanie do adresu https://oauth2.googleapis.com/revoke
, dodając token jako parametr i ustawiając nagłówek Content-Type
:
requests.post('https://oauth2.googleapis.com/revoke', params={'token': credentials.token}, headers = {'content-type': 'application/x-www-form-urlencoded'})
Ruby
Aby programowo cofnąć token, wyślij żądanie HTTP do punktu końcowego oauth2.revoke
:
uri = URI('https://oauth2.googleapis.com/revoke') response = Net::HTTP.post_form(uri, 'token' => auth_client.access_token)
Token może być tokenem dostępu lub tokenem odświeżania. Jeśli token jest tokenem dostępu i ma odpowiadający mu token odświeżania, token odświeżania zostanie również cofnięty.
Jeśli odwołanie zostało przetworzone, kod stanu odpowiedzi to 200
. W przypadku błędów zwracany jest kod stanu 400
oraz kod błędu.
Node.js
Aby programowo cofnąć token, wyślij żądanie HTTPS POST do punktu końcowego /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();
Parametr tokena może być tokenem dostępu lub tokenem odświeżania. Jeśli token jest tokenem dostępu i ma odpowiadający mu token odświeżania, token odświeżania zostanie również cofnięty.
Jeśli odwołanie zostało przetworzone, kod stanu odpowiedzi to 200
. W przypadku błędów zwracany jest kod stanu 400
oraz kod błędu.
HTTP/REST
Aby programowo unieważnić token, aplikacja wysyła żądanie do interfejsu https://oauth2.googleapis.com/revoke
, dołączając token jako parametr:
curl -d -X -POST --header "Content-type:application/x-www-form-urlencoded" \ https://oauth2.googleapis.com/revoke?token={token}
Token może być tokenem dostępu lub tokenem odświeżania. Jeśli token jest tokenem dostępu i ma odpowiadający mu token odświeżania, token odświeżania zostanie również cofnięty.
Jeśli odwołanie zostało przetworzone, kod stanu HTTP odpowiedzi to 200
. W przypadku błędów zwracany jest kod stanu HTTP 400
oraz kod błędu.
Wdrażanie Ochrony wszystkich kont
Dodatkowym krokiem, który należy wykonać, aby chronić konta użytkowników, jest wdrożenie ochrony na wielu kontach za pomocą usługi Google Cross-Account Protection. Ta usługa umożliwia subskrybowanie powiadomień o zdarzeniach związanych z bezpieczeństwem, które dostarczają aplikacji informacji o ważnych zmianach na koncie użytkownika. Następnie możesz podjąć odpowiednie działania w zależności od tego, jak chcesz reagować na zdarzenia.
Przykłady typów zdarzeń wysyłanych do Twojej aplikacji przez usługę ochrony na wielu kontach:
-
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
Więcej informacji o wdrażaniu ochrony wszystkich kont oraz pełną listę dostępnych zdarzeń znajdziesz na stronie Ochrona kont użytkowników za pomocą ochrony wszystkich kont .