מערכת OAuth 2.0 של Google תומכת באינטראקציות בין שרתים, כמו אינטראקציות בין אפליקציית אינטרנט לבין שירות של Google. בתרחיש הזה צריך חשבון שירות, שהוא חשבון ששייך לאפליקציה ולא למשתמש קצה ספציפי. האפליקציה שולחת קריאות ל-Google APIs בשם חשבון השירות, כך שהמשתמשים לא מעורבים באופן ישיר. התרחיש הזה נקרא לפעמים 'OAuth דו-שלבי' או '2LO'. (המונח הקשור 'OAuth משולש' מתייחס לתרחישים שבהם האפליקציה שלכם קוראת לממשקי Google API מטעם משתמשי הקצה, ולפעמים נדרשת הסכמה מהמשתמשים).
בדרך כלל, אפליקציה משתמשת בחשבון שירות כשהיא משתמשת בממשקי Google API כדי לעבוד עם הנתונים שלה ולא עם נתוני המשתמש. לדוגמה, אפליקציה שמשתמשת ב-Google Cloud Datastore לשמירת נתונים תשתמש בחשבון שירות כדי לאמת את הקריאות שלה ל-Google Cloud Datastore API.
אדמינים של דומיינים ב-Google Workspace יכולים גם להעניק לחשבונות שירות הרשאה ברמת הדומיין לגשת לנתוני המשתמשים בשם המשתמשים בדומיין.
במסמך הזה נסביר איך אפליקציה יכולה להשלים את התהליך של OAuth 2.0 משרת-אל-שרת באמצעות ספריית לקוח של Google APIs (מומלץ) או באמצעות HTTP.
סקירה כללית
כדי לתמוך באינטראקציות בין שרתים, קודם צריך ליצור חשבון שירות לפרויקט ב- API Console. אם רוצים לגשת לנתוני משתמשים בחשבון Google Workspace, צריך להעניק לחשבון השירות הרשאת גישה ברמת הדומיין.
לאחר מכן, האפליקציה מתכוננת לבצע קריאות מורשות ל-API באמצעות פרטי הכניסה של חשבון השירות, כדי לבקש אסימון גישה משרת האימות של OAuth 2.0.
לבסוף, האפליקציה יכולה להשתמש באסימון הגישה כדי לבצע קריאות ל-Google APIs.
יצירת חשבון שירות
פרטי הכניסה של חשבון שירות כוללים כתובת אימייל ייחודית שנוצרה, ולפחות זוג מפתחות ציבורי/פרטי אחד. אם הענקת הגישה ברמת הדומיין מופעלת, מזהה לקוח הוא גם חלק מפרטי הכניסה של חשבון השירות.
אם האפליקציה שלכם פועלת ב-Google App Engine, חשבון השירות מוגדר באופן אוטומטי כשיוצרים את הפרויקט.
אם האפליקציה שלכם פועלת ב-Google Compute Engine, חשבון השירות מוגדר גם באופן אוטומטי כשיוצרים את הפרויקט, אבל צריך לציין את ההיקפים שלגביהם האפליקציה צריכה גישה כשיוצרים מכונה של Google Compute Engine. למידע נוסף, ראו הכנת מכונה לשימוש בחשבונות שירות.
אם האפליקציה לא פועלת ב-Google App Engine או ב-Google Compute Engine, צריך לקבל את פרטי הכניסה האלה ב- Google API Console. כדי ליצור פרטי כניסה של חשבון שירות או כדי להציג את פרטי הכניסה הציבוריים שכבר יצרתם:
ראשית, צור חשבון שירות:
- פתח את ה- Service accounts page.
- If prompted, select a project, or create a new one.
- לחץ על צור חשבון שירות .
- תחת פרטי חשבון שירות , הקלד שם, מזהה ותיאור עבור חשבון השירות ולאחר מכן לחץ על צור והמשך .
- אופציונלי: תחת הענק גישה לחשבון שירות זה לפרויקט , בחר את תפקידי IAM להעניק לחשבון השירות.
- לחץ על המשך .
- אופציונלי: תחת הענק למשתמשים גישה לחשבון שירות זה , הוסף את המשתמשים או הקבוצות המורשים להשתמש ולנהל את חשבון השירות.
- לחץ על סיום .
לאחר מכן, צור מפתח חשבון שירות:
- לחץ על כתובת הדוא"ל של חשבון השירות שיצרת.
- לחץ על הכרטיסייה מפתחות .
- ברשימה הנפתחת הוסף מפתח , בחר צור מפתח חדש .
- לחץ על צור .
זוג המפתחות הציבורי/פרטי החדש שלך נוצר ומוריד למחשב שלך; הוא משמש כעותק היחיד של המפתח הפרטי. אתה אחראי לאחסן אותו בצורה מאובטחת. אם תאבד את צמד המפתחות הזה, תצטרך ליצור אחד חדש.
אפשר לחזור אל API Console מתי שרוצים כדי להציג את כתובת האימייל, את טביעות האצבע של המפתחות הציבוריים ומידע נוסף, או כדי ליצור צמדים נוספים של מפתחות ציבוריים/פרטיים. למידע נוסף על פרטי הכניסה של חשבון השירות ב- API Console, ראו חשבונות שירות בקובץ העזרה של API Console.
מציינים את כתובת האימייל של חשבון השירות ושומרים את קובץ המפתח הפרטי של חשבון השירות במיקום שגלוי לאפליקציה. האפליקציה שלכם זקוקה להם כדי לבצע קריאות API מורשות.
הענקת הרשאה ברמת הדומיין לחשבון השירות
באמצעות חשבון Google Workspace, האדמין של Workspace בארגון יכול לתת לאפליקציה הרשאה לגשת לנתוני המשתמשים ב-Workspace בשם המשתמשים בדומיין של Google Workspace. לדוגמה, אפליקציה שמשתמשת ב-Google Calendar API כדי להוסיף אירועים ליומני Google של כל המשתמשים בדומיין של Google Workspace תשתמש בחשבון שירות כדי לגשת ל-Google Calendar API בשם המשתמשים. הענקת הרשאה לחשבון שירות לגשת לנתונים בשם משתמשים בדומיין נקראת לפעמים 'הענקת הרשאה ברמת הדומיין' לחשבון שירות.
כדי להעניק לחשבון שירות הרשאות ברמת הדומיין, סופר-אדמין בדומיין Google Workspace צריך לבצע את השלבים הבאים:
- ב מסוף Admin של הדומיין ב-Google Workspace, עוברים אל תפריט ראשי > אבטחה > שליטה בגישה ובנתונים > אמצעי בקרה ל-API.
- בחלונית הענקת גישה ברמת הדומיין, בוחרים באפשרות ניהול של הענקת גישה ברמת הדומיין.
- לוחצים על הוספת חדש.
- בשדה Client ID, מזינים את Client ID של חשבון השירות. מזהה הלקוח של חשבון השירות מופיע ב- Service accounts page.
- בשדה OAuth scopes (comma-delimited) מזינים את רשימת ההיקפים שאליהן צריך להעניק לאפליקציה גישה. לדוגמה, אם לאפליקציה שלכם דרושה גישה מלאה ברמת הדומיין ל-Google Drive API ול-Google Calendar API, מזינים: https://www.googleapis.com/auth/drive, https://www.googleapis.com/auth/calendar.
- לוחצים על Authorize.
לאפליקציה יש עכשיו הרשאה לבצע קריאות API בתור משתמשים בדומיין Workspace שלכם (כדי "התחזות" למשתמשים). כשאתם מתכוננים לבצע את קריאות ה-API להענקת גישה, עליכם לציין במפורש את המשתמש שרוצים להתחזות אליו.
הכנה לקריאה להענקת גישה ל-API
אחרי שמקבלים את כתובת האימייל והמפתח הפרטי של הלקוח מ- API Console, משתמשים בספריית הלקוח של Google APIs ל-Java כדי ליצור אובייקט GoogleCredential
מפרטי הכניסה של חשבון השירות ומתחומי הגישה שהאפליקציה צריכה גישה אליהם. לדוגמה:
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; import com.google.api.services.sqladmin.SQLAdminScopes; // ... GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json")) .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN));
אם אתם מפתחים אפליקציה בפלטפורמת Google Cloud, תוכלו להשתמש במקום זאת בפרטי הכניסה שמוגדרים כברירת מחדל לאפליקציה, כדי לפשט את התהליך.
הענקת גישה ברמת הדומיין
אם הענקת גישה ברמת הדומיין לחשבון השירות ואתם רוצים להתחזות לחשבון משתמש, צריך לציין את כתובת האימייל של חשבון המשתמש באמצעות השיטה createDelegated
של האובייקט GoogleCredential
. לדוגמה:
GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json")) .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN)) .createDelegated("workspace-user@example.com");
בקוד שלמעלה נעשה שימוש באובייקט GoogleCredential
כדי לקרוא לשיטה createDelegated()
שלו. הארגומנט של השיטה createDelegated()
חייב להיות משתמש ששייך לחשבון Workspace שלכם. הקוד ששולח את הבקשה ישתמש בפרטי הכניסה האלה כדי לקרוא לממשקי Google API באמצעות חשבון השירות שלכם.
אחרי שמקבלים את כתובת האימייל והמפתח הפרטי של הלקוח מ- API Console, משתמשים בספריית הלקוח של Google APIs ל-Python כדי לבצע את השלבים הבאים:
- יוצרים אובייקט
Credentials
מפרטי הכניסה של חשבון השירות ומתחומי ההרשאה שהאפליקציה צריכה גישה אליהם. לדוגמה:from google.oauth2 import service_account SCOPES = ['https://www.googleapis.com/auth/sqlservice.admin'] SERVICE_ACCOUNT_FILE = '/path/to/service.json' credentials = service_account.Credentials.from_service_account_file( SERVICE_ACCOUNT_FILE, scopes=SCOPES)
אם אתם מפתחים אפליקציה בפלטפורמת Google Cloud, תוכלו להשתמש במקום זאת בפרטי הכניסה שמוגדרים כברירת מחדל לאפליקציה, כדי לפשט את התהליך.
- הענקת גישה ברמת הדומיין
אם הענקת גישה ברמת הדומיין לחשבון השירות ואתם רוצים להתחזות לחשבון משתמש, תוכלו להשתמש ב-method
with_subject
של אובייקטServiceAccountCredentials
קיים. לדוגמה:delegated_credentials = credentials.with_subject('user@example.org')
משתמשים באובייקט Credentials כדי לבצע קריאות ל-Google APIs באפליקציה.
אחרי שמקבלים את מזהה הלקוח ואת המפתח הפרטי מ- API Console, האפליקציה צריכה לבצע את השלבים הבאים:
- יוצרים JSON Web Token (JWT, מבוטא 'jot') שכולל כותרת, קבוצת הצהרות וחתימת.
- מבקשים אסימון גישה משרת ההרשאות של Google OAuth 2.0.
- טיפול בתגובת ה-JSON שחוזרת משרת ההרשאות.
בקטעים הבאים מוסבר איך לבצע את השלבים האלה.
אם התגובה כוללת אסימון גישה, אפשר להשתמש באסימון הגישה כדי להפעיל ממשק Google API. (אם התגובה לא כוללת אסימון גישה, יכול להיות שה-JWT ובקשת האסימון לא נוצרו בצורה תקינה, או שלחשבון השירות אין הרשאה לגשת להיקפי הגישה המבוקשים).
כשפג התוקף של אסימון הגישה, האפליקציה יוצרת אסימון JWT נוסף, חותמת עליו ומבקשת אסימון גישה נוסף.
בהמשך הקטע הזה מתוארים הפרטים הספציפיים של יצירת JWT, חתימה על JWT, יצירת הבקשה לאסימון הגישה וטיפול בתגובה.
יצירת JWT
אסימון JWT מורכב משלושה חלקים: כותרת, קבוצת הצהרות וחתימה. הכותרת וקבוצת ההצהרות הן אובייקטים של JSON. אובייקטי ה-JSON האלה עוברים סריאליזציה לבייטים של UTF-8, ולאחר מכן מקודדים באמצעות קידוד Base64url. הקידוד הזה מספק עמידות בשינויי קידוד שנובעים מפעולות קידוד חוזרות. הכותרת, קבוצת ההצהרות והחתימה מקושרים יחד באמצעות תו נקודה (.
).
אסימון JWT מורכב מהחלקים הבאים:
{Base64url encoded header}.{Base64url encoded claim set}.{Base64url encoded signature}
מחרוזת הבסיס לחתימה היא:
{Base64url encoded header}.{Base64url encoded claim set}
יצירת הכותרת של ה-JWT
הכותרת מורכבת משלושה שדות שמציינים את אלגוריתם החתימה, את הפורמט של טענת הנכוֹנוּת ואת [מזהה המפתח של מפתח חשבון השירות](https://cloud.google.com/iam/docs/reference/rest/v1/projects.serviceAccounts.keys) ששימש לחתימה על ה-JWT. חובה לציין את האלגוריתם והפורמט, וכל שדה יכול להכיל רק ערך אחד. ככל שנוסיף אלגוריתמים ופורמטים, הכותרת הזו תשתנה בהתאם. מזהה המפתח הוא אופציונלי. אם יצוין מזהה מפתח שגוי, GCP ינסה את כל המפתחות שמשויכים לחשבון השירות כדי לאמת את הטוקן, ויידחה את הטוקן אם לא יימצא מפתח תקין. Google שומרת לעצמה את הזכות לדחות בעתיד אסימונים עם מזהי מפתחות שגויים.
חשבונות שירות מסתמכים על האלגוריתם RSA SHA-256 ועל פורמט האסימון JWT. כתוצאה מכך, הייצוג של הכותרת ב-JSON הוא:
{"alg":"RS256","typ":"JWT", "kid":"370ab79b4513eb9bad7c9bd16a95cb76b5b2a56a"}
הייצוג של זה ב-Base64url הוא:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsICJraWQiOiIzNzBhYjc5YjQ1MTNlYjliYWQ3YzliZDE2YTk1Y2I3NmI1YjJhNTZhIn0=
יצירת קבוצת ההצהרות של JWT
קבוצת ההצהרות של JWT מכילה מידע על JWT, כולל ההרשאות המבוקשות (היקפי הגישה), היעד של האסימון, המנפיק, המועד שבו האסימון הונפק ומשך החיים של האסימון. רוב השדות הם שדות חובה. בדומה לכותרת של JWT, קבוצת ההצהרות של JWT היא אובייקט JSON שמשמש לחישוב החתימה.
הצהרות נדרשות
הצהרות הטענות הנדרשות בקבוצת ההצהרות של JWT מוצגות בהמשך. הם יכולים להופיע בכל סדר בקבוצת התביעות.
שם | תיאור |
---|---|
iss |
כתובת האימייל של חשבון השירות. |
scope |
רשימה של ההרשאות שהאפליקציה מבקשת, מופרדות בפסיקים. |
aud |
תיאור של היעד המיועד של טענת הנכוֹנוּת. כששולחים בקשה לקבלת אסימון גישה, הערך הזה הוא תמיד https://oauth2.googleapis.com/token . |
exp |
זמן התפוגה של טענת הנכוֹנוּת, שמצוין בשניות מאז 00:00:00 UTC, 1 בינואר 1970. הערך הזה יכול להיות עד שעה אחת אחרי מועד ההנפקה. |
iat |
השעה שבה ההצהרה הונפקה, שצוינה בשניות מאז 00:00:00 UTC, ב-1 בינואר 1970. |
ייצוג ה-JSON של השדות הנדרשים בקבוצת הצהרות של JWT מוצג בהמשך:
{ "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com", "scope": "https://www.googleapis.com/auth/devstorage.read_only", "aud": "https://oauth2.googleapis.com/token", "exp": 1328554385, "iat": 1328550785 }
הצהרות נוספות
במקרים מסוימים בארגון, אפליקציה יכולה להשתמש בהענקת גישה ברמת הדומיין כדי לפעול בשם משתמש מסוים בארגון. כדי שאפליקציה תוכל להתחזות למשתמש, צריך להעניק לה הרשאה לביצוע התחזות מהסוג הזה. בדרך כלל, סופר-אדמין מטפל בכך. מידע נוסף זמין במאמר שליטה בהרשאות הגישה ל-API באמצעות הענקת גישה ברמת הדומיין.
כדי לקבל אסימון גישה שמעניק לאפליקציה גישה משוערת למשאב, צריך לכלול את כתובת האימייל של המשתמש בהצהרה של JWT שמוגדרת כערך של השדה sub
.
שם | תיאור |
---|---|
sub |
כתובת האימייל של המשתמש שעבורו האפליקציה מבקשת גישה מוקנית. |
אם לאפליקציה אין הרשאה להתחזות למשתמש, התשובה לבקשה של אסימון גישה שכוללת את השדה sub
תהיה שגיאה.
דוגמה של קבוצת הצהרות JWT שכוללת את השדה sub
מוצגת בהמשך:
{ "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com", "sub": "some.user@example.com", "scope": "https://www.googleapis.com/auth/prediction", "aud": "https://oauth2.googleapis.com/token", "exp": 1328554385, "iat": 1328550785 }
קידוד של קבוצת ההצהרות של JWT
בדומה לכותרת של JWT, צריך לבצע סריאליזציה של קבוצת ההצהרות של JWT ל-UTF-8 ולקידוד Base64 ללא סיכון לאבטחת ה-URL. בהמשך מוצגת דוגמה לייצוג JSON של קבוצת הצהרות JWT:
{ "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com", "scope": "https://www.googleapis.com/auth/prediction", "aud": "https://oauth2.googleapis.com/token", "exp": 1328554385, "iat": 1328550785 }
חישוב החתימה
JSON Web Signature (JWS) הוא המפרט שמנחה את המנגנונים ליצירת החתימה של ה-JWT. הקלט לחתימה הוא מערך הבייטים של התוכן הבא:
{Base64url encoded header}.{Base64url encoded claim set}
צריך להשתמש באלגוריתום החתימה בכותרת ה-JWT כשמחשבים את החתימה. אלגוריתם החתימה היחיד שנתמך על ידי שרת ההרשאות של Google OAuth 2.0 הוא RSA באמצעות אלגוריתם הגיבוב SHA-256. הוא מופיע כ-RS256
בשדה alg
בכותרת ה-JWT.
חותמים על הייצוג של הקלט ב-UTF-8 באמצעות SHA256withRSA (שנקרא גם RSASSA-PKCS1-V1_5-SIGN עם פונקציית הגיבוב SHA-256) באמצעות המפתח הפרטי שהתקבל מ- Google API Console. הפלט יהיה מערך בייטים.
לאחר מכן, החתימה צריכה לעבור קידוד Base64url. הכותרת, קבוצת ההצהרות והחתימה מקושרים יחד באמצעות תו נקודה (.
). התוצאה היא ה-JWT. הקוד צריך להיות כזה (הפסקות השורות נוספו לצורך הבהרה):
{Base64url encoded header}. {Base64url encoded claim set}. {Base64url encoded signature}
בהמשך מופיעה דוגמה ל-JWT לפני קידוד Base64url:
{"alg":"RS256","typ":"JWT"}. { "iss":"761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com", "scope":"https://www.googleapis.com/auth/prediction", "aud":"https://oauth2.googleapis.com/token", "exp":1328554385, "iat":1328550785 }. [signature bytes]
בהמשך מוצגת דוגמה ל-JWT שנחתם ומוכן להעברה:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL29hdXRoMi92NC90b2tlbiIsImV4cCI6MTMyODU1NDM4NSwiaWF0IjoxMzI4NTUwNzg1fQ.UFUt59SUM2_AW4cRU8Y0BYVQsNTo4n7AFsNrqOpYiICDu37vVt-tw38UKzjmUKtcRsLLjrR3gFW3dNDMx_pL9DVjgVHDdYirtrCekUHOYoa1CMR66nxep5q5cBQ4y4u2kIgSvChCTc9pmLLNoIem-ruCecAJYgI9Ks7pTnW1gkOKs0x3YpiLpzplVHAkkHztaXiJdtpBcY1OXyo6jTQCa3Lk2Q3va1dPkh_d--GU2M5flgd8xNBPYw4vxyt0mP59XZlHMpztZt0soSgObf7G3GXArreF_6tpbFsS3z2t5zkEiHuWJXpzcYr5zWTRPDEHsejeBSG8EgpLDce2380ROQ
שליחת הבקשה לטוקן הגישה
אחרי יצירת ה-JWT החתום, אפליקציה יכולה להשתמש בו כדי לבקש אסימון גישה.
בקשת אסימון הגישה הזו היא בקשת POST
ב-HTTPS, והגוף שלה מקודד ככתובת URL. כתובת ה-URL מוצגת בהמשך:
https://oauth2.googleapis.com/token
הפרמטרים הבאים נדרשים בבקשה POST
ב-HTTPS:
שם | תיאור |
---|---|
grant_type |
משתמשים במחרוזת הבאה, בקידוד URL לפי הצורך:
urn:ietf:params:oauth:grant-type:jwt-bearer |
assertion |
ה-JWT, כולל החתימה. |
בהמשך מופיע דמפ גולמי של בקשת ה-HTTPS POST
ששימשה בבקשה לטוקן גישה:
POST /token HTTP/1.1 Host: oauth2.googleapis.com Content-Type: application/x-www-form-urlencoded grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU3MzM4MSwiaWF0IjoxMzI4NTY5NzgxfQ.ixOUGehweEVX_UKXv5BbbwVEdcz6AYS-6uQV6fGorGKrHf3LIJnyREw9evE-gs2bmMaQI5_UbabvI4k-mQE4kBqtmSpTzxYBL1TCd7Kv5nTZoUC1CmwmWCFqT9RE6D7XSgPUh_jF1qskLa2w0rxMSjwruNKbysgRNctZPln7cqQ
זו אותה הבקשה, עם curl
:
curl -d 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU3MzM4MSwiaWF0IjoxMzI4NTY5NzgxfQ.RZVpzWygMLuL-n3GwjW1_yhQhrqDacyvaXkuf8HcJl8EtXYjGjMaW5oiM5cgAaIorrqgYlp4DPF_GuncFqg9uDZrx7pMmCZ_yHfxhSCXru3gbXrZvAIicNQZMFxrEEn4REVuq7DjkTMyCMGCY1dpMa8aWfTQFt3Eh7smLchaZsU ' https://oauth2.googleapis.com/token
טיפול בתגובה
אם ה-JWT ובקשת אסימון הגישה נוצרו בצורה תקינה וחשבון השירות מורשה לבצע את הפעולה, תגובת ה-JSON משרת ההרשאות תכלול אסימון גישה. דוגמה לתגובה:
{ "access_token": "1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M", "scope": "https://www.googleapis.com/auth/prediction" "token_type": "Bearer", "expires_in": 3600 }
אפשר לעשות שימוש חוזר באסימוני הגישה במהלך חלון משך הזמן שצוין בערך expires_in
.
קריאה ל-Google APIs
כדי להשתמש באובייקט GoogleCredential
כדי לקרוא ל-Google APIs, מבצעים את השלבים הבאים:
- יוצרים אובייקט שירות ל-API שרוצים לקרוא באמצעות אובייקט
GoogleCredential
. לדוגמה:SQLAdmin sqladmin = new SQLAdmin.Builder(httpTransport, JSON_FACTORY, credential).build();
- שולחים בקשות לשירות ה-API באמצעות הממשק שסופק על ידי אובייקט השירות.
לדוגמה, כדי להציג את המכונות של מסדי הנתונים ב-Cloud SQL בפרויקט exciting-example-123:
SQLAdmin.Instances.List instances = sqladmin.instances().list("exciting-example-123").execute();
כדי להשתמש באובייקט Credentials
המורשה כדי לבצע קריאה לממשקי Google API, מבצעים את השלבים הבאים:
- יוצרים אובייקט שירות ל-API שרוצים להפעיל. כדי ליצור אובייקט שירות, צריך לבצע קריאה לפונקציה
build
עם השם והגרסה של ה-API ואובייקטCredentials
המורשה. לדוגמה, כדי לקרוא לגרסה 1beta3 של Cloud SQL Administration API:import googleapiclient.discovery sqladmin = googleapiclient.discovery.build('sqladmin', 'v1beta3', credentials=credentials)
- שולחים בקשות לשירות ה-API באמצעות הממשק שסופק על ידי אובייקט השירות.
לדוגמה, כדי להציג את המכונות של מסדי הנתונים ב-Cloud SQL בפרויקט exciting-example-123:
response = sqladmin.instances().list(project='exciting-example-123').execute()
אחרי שהאפליקציה מקבלת אסימון גישה, אפשר להשתמש באסימון כדי לבצע קריאות ל-Google API מטעם חשבון שירות או חשבון משתמש נתון, אם היקפי הגישה הנדרשים ל-API הוענקו. כדי לעשות זאת, צריך לכלול את אסימון הגישה בבקשה ל-API באמצעות פרמטר של שאילתה access_token
או ערך Bearer
בכותרת Authorization
של HTTP. כשהדבר אפשרי, עדיף להשתמש בכותרת ה-HTTP, כי מחרוזות השאילתות נוטים להיות גלויות ביומנים של השרת. ברוב המקרים אפשר להשתמש בספריית לקוח כדי להגדיר את הקריאות לממשקי Google API (לדוגמה, כשקוראים ל-Drive Files API).
אפשר לנסות את כל ממשקי Google APIs ולראות את היקפי ההרשאות שלהם ב-OAuth 2.0 Playground.
דוגמאות לבקשות HTTP GET
קריאה לנקודת הקצה
drive.files
(Drive Files API) באמצעות הכותרת Authorization: Bearer
של HTTP עשויה להיראות כך: חשוב לשים לב שצריך לציין את טוקן הגישה שלכם:
GET /drive/v2/files HTTP/1.1 Host: www.googleapis.com Authorization: Beareraccess_token
זוהי קריאה לאותו ממשק API עבור המשתמש המאומת באמצעות הפרמטר access_token
של מחרוזת השאילתה:
GET https://www.googleapis.com/drive/v2/files?access_token=access_token
curl
דוגמאות
אפשר לבדוק את הפקודות האלה באמצעות אפליקציית שורת הפקודה curl
. הנה דוגמה שמשתמשת באפשרות של כותרת ה-HTTP (האפשרות המועדפת):
curl -H "Authorization: Beareraccess_token " https://www.googleapis.com/drive/v2/files
לחלופין, אפשר לבחור באפשרות 'פרמטר של מחרוזת שאילתה':
curl https://www.googleapis.com/drive/v2/files?access_token=access_token
מתי יפוג התוקף של אסימוני הגישה
התוקף של אסימוני הגישה שהונפקו על ידי שרת ההרשאות של Google OAuth 2.0 יפוג אחרי משך הזמן שצוין בערך expires_in
. כשפג התוקף של אסימון גישה, האפליקציה צריכה ליצור JWT נוסף, לחתום עליו ולבקש אסימון גישה נוסף.
קודי שגיאה של JWT
השדה error |
השדה error_description |
משמעות | איך פותרים את הבעיה |
---|---|---|---|
unauthorized_client |
Unauthorized client or scope in request. |
אם אתם מנסים להשתמש בהענקת גישה ברמת הדומיין, חשבון השירות לא מורשה במסוף Admin של הדומיין של המשתמש. |
מוודאים שחשבון השירות מורשה בדף
הענקת הרשאות גישה ברמת הדומיין במסוף Admin עבור המשתמש בהצהרה (שדה) בדרך כלל התהליך הזה נמשך כמה דקות, אבל יכול להיות שיחלפו עד 24 שעות עד שההרשאה תופץ לכל המשתמשים בחשבון Google שלכם. |
unauthorized_client |
Client is unauthorized to retrieve access tokens using this method, or client not
authorized for any of the scopes requested. |
חשבון שירות אושר באמצעות כתובת האימייל של הלקוח במקום באמצעות מזהה הלקוח (מספרי) במסוף Admin. | בדף Delegation-wide Domain במסוף Admin, מסירים את הלקוח ומוסיפים אותו מחדש עם המזהה המספרי. |
access_denied |
(כל ערך) | אם אתם משתמשים בהענקת גישה ברמת הדומיין, אחד או יותר מההיקפים המבוקשים לא אושרו במסוף Admin. |
מוודאים שחשבון השירות מורשה בדף
הענקת גישה ברמת הדומיין במסוף Admin עבור המשתמש בהצהרה (שדה) בדרך כלל התהליך הזה נמשך כמה דקות, אבל יכול להיות שיחלפו עד 24 שעות עד שההרשאה תופץ לכל המשתמשים בחשבון Google שלכם. |
admin_policy_enforced |
(כל ערך) | חשבון Google לא יכול להעניק הרשאה להיקף אחד או יותר מהיקפי הגישה המבוקשים בגלל המדיניות של האדמין ב-Google Workspace. |
במאמר העזרה לאדמינים ב-Google Workspace שליטה בגישה של אפליקציות של צד שלישי ואפליקציות פנימיות לנתונים ב-Google Workspace מוסבר איך אדמין יכול להגביל את הגישה לכל ההיקפים או להיקפים רגישים ומוגבלים, עד שתוענק גישה מפורשת למזהה הלקוח של OAuth. |
invalid_client |
(כל ערך) |
לקוח OAuth או טוקן JWT לא תקינים או שהם מוגדרים בצורה שגויה. פרטים נוספים זמינים בתיאור השגיאה. |
מוודאים שטוקן ה-JWT תקף ויש בו הצהרות נכונות. בודקים שלקוח OAuth וחשבון השירות מוגדרים בצורה נכונה ושנעשה שימוש בכתובת האימייל הנכונה. בודקים שהאסימון של JWT תקין ונוצר עבור מספר הלקוח שמופיע בבקשה. |
invalid_grant |
Not a valid email. |
המשתמש לא קיים. | בודקים שכתובת האימייל בטענת הנכונות (שדה) sub נכונה. |
invalid_grant |
|
בדרך כלל, המשמעות היא ששעון המערכת המקומי לא נכון. ייתכן גם אם הערך של exp הוא יותר מ-65 דקות בעתיד מהערך של iat , או שהערך של exp נמוך מהערך של iat . |
מוודאים שהשעון במערכת שבה נוצר ה-JWT מדויק. אם צריך, מסנכרנים את השעון עם Google NTP. |
invalid_grant |
Invalid JWT Signature. |
טענת הנכוֹנוּת (assertion) של JWT חתומה על ידי מפתח פרטי שלא משויך לחשבון השירות שמזוהה באמצעות כתובת האימייל של הלקוח, או שהמפתח שבו נעשה שימוש נמחק, הושבת או שתוקפו פג. לחלופין, יכול להיות שטענת הנכוֹנוּת של JWT לא הוקודה בצורה נכונה – היא חייבת להיות בקידוד Base64, ללא שורות חדשות או סימני שווה למטרות מילוי. |
מפענחים את קבוצת ההצהרות של JWT ומאמתים שהמפתח שעליו נחתם טענת הנכוֹנוּת משויך לחשבון השירות. נסו להשתמש בספריית OAuth שסופקה על ידי Google כדי לוודא שה-JWT נוצר בצורה נכונה. |
invalid_scope |
Invalid OAuth scope or ID token audience provided. |
לא נשלחו בקשות להיקפי הרשאות (רשימת היקפי ההרשאות ריקה), או שאחד מהיקפי ההרשאות המבוקשים לא קיים (כלומר, לא תקף). |
מוודאים שההצהרה (השדה) חשוב לזכור שצריך להפריד את רשימת ההיקפים בהצהרה |
disabled_client |
The OAuth client was disabled. |
המפתח שמשמש לחתימה על טענת הנכוֹנוּת (assertion) של JWT מושבת. |
עוברים אל Google API Console, ובקטע IAM & Admin > Service Accounts מפעילים את חשבון השירות שמכיל את 'מזהה המפתח' שמשמש לחתימה על טענת הנכוֹנוּת. |
org_internal |
This client is restricted to users within its organization. |
מזהה לקוח OAuth בבקשה הוא חלק מפרויקט שמגביל את הגישה לחשבונות Google ב ארגון ספציפי ב-Google Cloud. |
משתמשים בחשבון שירות מהארגון כדי לבצע אימות. מוודאים את הגדרת סוג המשתמש באפליקציית OAuth. |
נספח: הרשאה באמצעות חשבון שירות ללא OAuth
בחלק מממשקי Google APIs, אפשר לבצע קריאות API מורשות באמצעות JWT חתום ישירות בתור אסימון למוכ"ז, במקום אסימון גישה מסוג OAuth 2.0. כשהדבר אפשרי, תוכלו להימנע משיגור בקשה ברשת לשרת האימות של Google לפני ביצוע קריאה ל-API.
אם לממשק ה-API שאתם רוצים להפעיל יש הגדרת שירות שפורסמה במאגר GitHub של Google APIs, תוכלו לבצע קריאות API מורשות באמצעות JWT במקום אסימון גישה. לשם כך:
- יוצרים חשבון שירות כפי שמתואר למעלה. חשוב לשמור את קובץ ה-JSON שמקבלים כשיוצרים את החשבון.
- באמצעות כל ספריית JWT רגילה, כמו זו שזמינה ב-jwt.io, יוצרים JWT עם כותרת ומטען ייעודי (payload), כמו בדוגמה הבאה:
{ "alg": "RS256", "typ": "JWT", "kid": "abcdef1234567890" } . { "iss": "123456-compute@developer.gserviceaccount.com", "sub": "123456-compute@developer.gserviceaccount.com", "aud": "https://firestore.googleapis.com/", "iat": 1511900000, "exp": 1511903600 }
- בשדה
kid
בכותרת, מציינים את המזהה של המפתח הפרטי של חשבון השירות. אפשר למצוא את הערך הזה בשדהprivate_key_id
בקובץ ה-JSON של חשבון השירות. - בשדות
iss
ו-sub
, מציינים את כתובת האימייל של חשבון השירות. אפשר למצוא את הערך הזה בשדהclient_email
בקובץ ה-JSON של חשבון השירות. - בשדה
aud
, מציינים את נקודת הקצה של ה-API. לדוגמה:https://SERVICE.googleapis.com/
. - בשדה
iat
מציינים את שעון Unix הנוכחי, ובשדהexp
מציינים את השעה בדיוק 3600 שניות מאוחר יותר, שבה יפוג תוקף ה-JWT.
חותמים על ה-JWT באמצעות RSA-256 באמצעות המפתח הפרטי שנמצא בקובץ ה-JSON של חשבון השירות.
לדוגמה:
באמצעות google-api-java-client ו-java-jwt:
GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json")); PrivateKey privateKey = credential.getServiceAccountPrivateKey(); String privateKeyId = credential.getServiceAccountPrivateKeyId(); long now = System.currentTimeMillis(); try { Algorithm algorithm = Algorithm.RSA256(null, privateKey); String signedJwt = JWT.create() .withKeyId(privateKeyId) .withIssuer("123456-compute@developer.gserviceaccount.com") .withSubject("123456-compute@developer.gserviceaccount.com") .withAudience("https://firestore.googleapis.com/") .withIssuedAt(new Date(now)) .withExpiresAt(new Date(now + 3600 * 1000L)) .sign(algorithm); } catch ...
באמצעות PyJWT:
iat = time.time() exp = iat + 3600 payload = {'iss': '123456-compute@developer.gserviceaccount.com', 'sub': '123456-compute@developer.gserviceaccount.com', 'aud': 'https://firestore.googleapis.com/', 'iat': iat, 'exp': exp} additional_headers = {'kid': PRIVATE_KEY_ID_FROM_JSON} signed_jwt = jwt.encode(payload, PRIVATE_KEY_FROM_JSON, headers=additional_headers, algorithm='RS256')
- קוראים ל-API, באמצעות ה-JWT החתום כאסימון למוכ"ז:
GET /v1/projects/abc/databases/123/indexes HTTP/1.1 Authorization: Bearer
SIGNED_JWT Host: firestore.googleapis.com
הטמעת ההגנה על כל החשבונות
כדי להגן על חשבונות המשתמשים, כדאי להטמיע הגנה על חשבונות שונים באמצעות שירות ההגנה על חשבונות שונים של 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
במאמר הגנה על חשבונות משתמשים באמצעות הגנה על כל החשבונות מוסבר איך מטמיעים את ההגנה על כל החשבונות ומופיעה רשימה מלאה של האירועים הזמינים.