זוהי ההדרכה המפורטת השלישית בנושא תוספים ל-Classroom של הדרכות מפורטות.
בהדרכה המפורטת הזו, תוכלו לטפל בביקורים חוזרים בתוסף שלנו באופן אוטומטי אחזור פרטי כניסה של משתמש שהוענקו בעבר. לאחר מכן אתם מנתבים משתמשים אל שמהם ניתן להפיק בקשות API באופן מיידי. זהו שדה חובה ההתנהגות של תוספים ל-Classroom.
במהלך ההדרכה המפורטת הזו, תצטרכו:
- הטמעת אחסון מתמיד עבור פרטי הכניסה של המשתמשים שלנו.
- מאחזרים ובוחנים את פרמטר השאילתה של התוסף
login_hint
. זהו מספר מזהה Google הייחודי של המשתמש המחובר.
לאחר סיום התהליך, תהיה לך אפשרות לתת הרשאה מלאה למשתמשים באפליקציית האינטרנט שלך ולשלוח שיחות אל ממשקי API של Google.
הסבר על פרמטרים של שאילתות ב-iframe
לאחר מכן, מערכת Classroom טוענת את ה-URI להגדרת קובץ מצורף.
פתיחה. Google Classroom
מצרפת ל-URI כמה פרמטרים של שאילתה GET
; הם מכילים
מידע לפי הקשר. אם, לדוגמה, ה-URI של גילוי קבצים מצורפים הוא
https://example.com/addon
, מערכת Classroom יוצרת את ה-iframe באמצעות
כתובת ה-URL של המקור שהוגדרה
https://example.com/addon?courseId=XXX&itemId=YYY&itemType=courseWork&addOnToken=ZZZ
,
כאשר XXX
, YYY
ו-ZZZ
הם מזהי מחרוזות. במדריך בנושא iframes תוכלו לקרוא
לתיאור מפורט של התרחיש הזה.
בכתובת ה-URL של הגילוי יש חמישה פרמטרים אפשריים של שאילתה:
courseId
: המזהה של הקורס הנוכחי ב-Classroom.itemId
: המזהה של הפריט במקור הנתונים שהמשתמש עורך או יוצר.itemType
: סוג הפריט בעדכונים שהמשתמש יוצר או עורך, אחד מהםcourseWork
,courseWorkMaterial
אוannouncement
.addOnToken
: אסימון שמשמש לאישור היבטים מסוימים פעולות בתוספים ל-Classroom.login_hint
: מזהה Google של המשתמש הנוכחי.
ההדרכה המפורטת הזו מטפלת בנושא login_hint
. המשתמשים ינותבו בהתאם
פרמטר של שאילתה, בתהליך ההרשאה אם חסר, או
דף הגילוי של התוסף, אם הוא קיים.
גישה לפרמטרים של השאילתה
הפרמטרים של השאילתה מועברים לאפליקציית האינטרנט במחרוזת ה-URI. חנות את הערכים האלה בסשן; משתמשים בהם בתהליך ההרשאה לאחסן ולאחזר מידע על המשתמש. הפרמטרים האלה של שאילתות רק עובר כשפותחים את התוסף בפעם הראשונה.
Python
מעבר להגדרות של מסלולי Flask (routes.py
אם נמצאים
לפי הדוגמה שסופקה). בחלק העליון של מסלול הנחיתה של התוסף
(/classroom-addon
בדוגמה שסופקה), מאחזרים ומאחסנים את
פרמטר של שאילתת login_hint
:
# If the login_hint query parameter is available, we'll store it in the session.
if flask.request.args.get("login_hint"):
flask.session["login_hint"] = flask.request.args.get("login_hint")
יש לוודא שה-login_hint
(אם קיים) שמור בסשן. זהו
מקום מתאים לשמירת הערכים האלה; הם זמניים,
ערכים חדשים כשהתוסף נפתח.
# It's possible that we might return to this route later, in which case the
# parameters will not be passed in. Instead, use the values cached in the
# session.
login_hint = flask.session.get("login_hint")
# If there's still no login_hint query parameter, this must be their first
# time signing in, so send the user to the sign in page.
if login_hint is None:
return start_auth_flow()
Java
ניווט למסלול הנחיתה של התוסף במחלקה של נאמן המידע
(/addon-discovery
ב-AuthController.java
בדוגמה שסופקה). בשעה
בתחילת המסלול הזה, מאחזרים ושומרים את השאילתה login_hint
הפרמטר.
/** Retrieve the login_hint query parameter from the request URL if present. */
String login_hint = request.getParameter("login_hint");
יש לוודא שה-login_hint
(אם קיים) שמור בסשן. זהו
מקום מתאים לשמירת הערכים האלה; הם זמניים,
ערכים חדשים כשהתוסף נפתח.
/** If login_hint wasn't sent, use the values in the session. */
if (login_hint == null) {
login_hint = (String) session.getAttribute("login_hint");
}
/** If the there is still no login_hint, route the user to the authorization
* page. */
if (login_hint == null) {
return startAuthFlow(model);
}
/** If the login_hint query parameter is provided, add it to the session. */
else if (login_hint != null) {
session.setAttribute("login_hint", login_hint);
}
הוספת הפרמטרים של השאילתה לתהליך ההרשאה
צריך להעביר את הפרמטר login_hint
לשרתי האימות של Google
וגם. כך אפשר להתחיל בתהליך האימות. אם האפליקציה יודעת
שהמשתמש מנסה לאמת, השרת משתמש ברמז כדי לפשט את
על ידי מילוי מראש של שדה האימייל בטופס הכניסה.
Python
ניווט למסלול ההרשאה בקובץ שרת Flask (/authorize
)
בדוגמה שלמעלה). הוספת הארגומנט login_hint
לקריאה
flow.authorization_url
.
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",
# The user will automatically be selected if we have the login_hint.
login_hint=flask.session.get("login_hint"),
Java
ניווט ל-method authorize()
במחלקה AuthService.java
. הוסף
login_hint
כפרמטר ל-method, ומוסיפים את login_hint
ואת הארגומנט 'לבונה כתובות ה-URL של ההרשאות'.
String authUrl = flow
.newAuthorizationUrl()
.setState(state)
.set("login_hint", login_hint)
.setRedirectUri(REDIRECT_URI)
.build();
הוספת אחסון מתמיד לפרטי הכניסה של המשתמשים
אם קיבלתם את הערך login_hint
כפרמטר של שאילתה כשהתוסף נטען,
אינדיקציה לכך שהמשתמש כבר השלים את תהליך ההרשאה עבור
תרגום מכונה. צריך לאחזר את פרטי הכניסה הקודמים שלהם במקום לאלץ אותם
כדי להיכנס שוב.
תזכורת: קיבלתם אסימון רענון אחרי השלמת התהליך תהליך ההרשאה. שומרים את האסימון הזה. עושים בו שימוש חוזר כדי לקבל אסימון גישה, לטווח קצר והוא נדרש לשימוש ב-Google APIs. שמרת בעבר את פרטי הכניסה האלה בסשן, אבל צריך לאחסן אותם כדי טיפול בביקורים חוזרים.
הגדרת סכימת המשתמש והגדרת מסד הנתונים
צריך להגדיר סכימה של מסד נתונים ל-User
.
Python
הגדרה של סכימת המשתמש
השדה User
מכיל את המאפיינים הבאים:
id
: מזהה Google של המשתמש. הוא צריך להתאים לערכים שצוינו פרמטר של שאילתתlogin_hint
.display_name
: השם הפרטי ושם המשפחה של המשתמש, למשל "אלכס כהן".email
: כתובת האימייל של המשתמש.portrait_url
: כתובת ה-URL של תמונת הפרופיל של המשתמש.refresh_token
: אסימון הרענון שנרכש בעבר.
בדוגמה הזו אנחנו מיישמים אחסון באמצעות SQLite, מה שנתמך במקור על ידי
בשפת Python. הוא משתמש במודול flask_sqlalchemy
כדי להקל על מסד הנתונים שלנו
ניהול.
הגדרת מסד הנתונים
קודם כול, מציינים את מיקום הקובץ עבור מסד הנתונים שלנו. עוברים לשרת שלכם
את קובץ התצורה (config.py
בדוגמה שסופקה) ומוסיפים את הקוד
במעקב.
import os
# Point to a database file in the project root.
DATABASE_FILE_NAME = os.path.join(
os.path.abspath(os.path.dirname(__file__)), 'data.sqlite')
class Config(object):
SQLALCHEMY_DATABASE_URI = f"sqlite:///{DATABASE_FILE_NAME}"
SQLALCHEMY_TRACK_MODIFICATIONS = False
פעולה זו מפנה את Flask לקובץ data.sqlite
ששמור באותה ספרייה כמו
קובץ main.py
.
בשלב הבא, עוברים לספריית המודולים ויוצרים קובץ models.py
חדש.
זהו webapp/models.py
אם פעלת לפי הדוגמה שסופקה. הוסף
את הפקודה הבאה בקובץ החדש כדי להגדיר את הטבלה User
, תוך החלפת הערכים
שם המודול עבור webapp
אם הוא שונה.
from webapp import db
# Database model to represent a user.
class User(db.Model):
# The user's identifying information:
id = db.Column(db.String(120), primary_key=True)
display_name = db.Column(db.String(80))
email = db.Column(db.String(120), unique=True)
portrait_url = db.Column(db.Text())
# The user's refresh token, which will be used to obtain an access token.
# Note that refresh tokens will become invalid if:
# - The refresh token has not been used for six months.
# - The user revokes your app's access permissions.
# - The user changes passwords.
# - The user belongs to a Google Cloud organization
# that has session control policies in effect.
refresh_token = db.Column(db.Text())
לסיום, בקובץ __init__.py
של המודול, יש להוסיף את הפרטים הבאים לייבוא
את המודלים החדשים וליצור את מסד הנתונים.
from webapp import models
from os import path
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy(app)
# Initialize the database file if not created.
if not path.exists(config.DATABASE_FILE_NAME):
db.create_all()
Java
הגדרה של סכימת המשתמשים
השדה User
מכיל את המאפיינים הבאים:
id
: מזהה Google של המשתמש. הוא צריך להתאים לערך שצוין פרמטר של שאילתתlogin_hint
.email
: כתובת האימייל של המשתמש.
יוצרים קובץ schema.sql
בספריית resources
של המודול. קפיץ
קורא את הקובץ ויוצר סכימה למסד הנתונים בהתאם.
מגדירים את הטבלה עם שם טבלה, users
ועמודות שרוצים לייצג
מאפייני User
, id
ו-email
.
CREATE TABLE IF NOT EXISTS users (
id VARCHAR(255) PRIMARY KEY, -- user's unique Google ID
email VARCHAR(255), -- user's email address
);
יוצרים מחלקה של Java כדי להגדיר את המודל User
למסד הנתונים. הדבר
User.java
בדוגמה שצוינה.
צריך להוסיף את ההערה @Entity
כדי לציין שמדובר ב-POJO שיכול להיות
נשמר במסד הנתונים. הוספה של ההערה @Table
עם
שם הטבלה התואם שהגדרתם ב-schema.sql
.
שימו לב שדוגמת הקוד כוללת constructors ו-Seters עבור השניים
. ה-constructor והמגדירים משמשים
AuthController.java
כדי ליצור או לעדכן משתמש במסד הנתונים. שלך
יכול לכלול גם geters ושיטת toString
לפי הצורך, אבל
בהדרכה המפורטת הספציפית הזאת, לא נעשה שימוש בשיטות האלה והן מושמטות
את הקוד לדוגמה בדף הזה כדי לקצר אותו.
/** An entity class that provides a model to store user information. */
@Entity
@Table(name = "users")
public class User {
/** The user's unique Google ID. The @Id annotation specifies that this
* is the primary key. */
@Id
@Column
private String id;
/** The user's email address. */
@Column
private String email;
/** Required User class no args constructor. */
public User() {
}
/** The User class constructor that creates a User object with the
* specified parameters.
* @param id the user's unique Google ID
* @param email the user's email address
*/
public User(String id, String email) {
this.id = id;
this.email = email;
}
public void setId(String id) { this.id = id; }
public void setEmail(String email) { this.email = email; }
}
ליצור ממשק בשם UserRepository.java
כדי לטפל בפעולות CRUD
למסד הנתונים. הממשק הזה מרחיב את הממשק של CrudRepository
.
/** Provides CRUD operations for the User class by extending the
* CrudRepository interface. */
@Repository
public interface UserRepository extends CrudRepository<User, String> {
}
שיעור נאמן המידע מאפשר תקשורת בין הלקוח
של מאגר הנתונים. לכן, עדכן את constructor של מחלקה של בקר כדי להחדיר
הכיתה UserRepository
.
/** Declare UserRepository to be used in the Controller class constructor. */
private final UserRepository userRepository;
/**
* ...
* @param userRepository the class that interacts with User objects stored in
* persistent storage.
*/
public AuthController(AuthService authService, UserRepository userRepository) {
this.authService = authService;
this.userRepository = userRepository;
}
הגדרת מסד הנתונים
כדי לאחסן מידע שקשור למשתמשים, צריך להשתמש במסד נתונים H2 שלמעשה
נתמך ב-Spring Boot. מסד הנתונים הזה משמש גם
הדרכות מפורטות לאחסון תכנים אחרים של Classroom
מידע. כדי להגדיר את מסד הנתונים H2 צריך להוסיף את הרכיבים הבאים:
את התצורה של application.properties
.
# Enable configuration for persistent storage using an H2 database
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:file:./h2/userdb
spring.datasource.username=<USERNAME>
spring.datasource.password=<PASSWORD>
spring.jpa.hibernate.ddl-auto=update
spring.jpa.open-in-view=false
ההגדרה spring.datasource.url
יוצרת ספרייה בשם h2
, עם
הקובץ userdb
שמאוחסן בו. הוספת הנתיב למסד הנתונים H2 אל
.gitignore
. עליך לעדכן את spring.datasource.username
וגם
spring.datasource.password
לפני הרצת האפליקציה כדי להגדיר את
באמצעות שם משתמש וסיסמה לבחירתכם. כדי לעדכן את
שם המשתמש והסיסמה למסד הנתונים, אחרי הרצת האפליקציה,
למחוק את ספריית h2
שנוצרה, לעדכן את ההגדרות האישיות
להפעיל מחדש את האפליקציה.
אם קובעים בהגדרות האישיות של spring.jpa.hibernate.ddl-auto
את הערך update
,
נתונים המאוחסנים במסד הנתונים נשמרים כשהאפליקציה מופעלת מחדש.
כדי לנקות את מסד הנתונים בכל פעם שהאפליקציה מופעלת מחדש, יש להגדיר
הגדרה ל-create
.
קובעים את ההגדרות של spring.jpa.open-in-view
ל-false
. ההגדרה הזו מופעלת
כברירת מחדל, ויכול להיות שזה יגרום לבעיות בביצועים
שקשה לאבחן אותו בסביבת הייצור.
כפי שהוסבר למעלה, צריכה להיות לכם אפשרות לאחזר את פרטי הכניסה של
משתמש חוזר. הפעולה הזו נתמכת על ידי מאגר פרטי הכניסה המובנה
שירות התמיכה של GoogleAuthorizationCodeFlow
.
במחלקה AuthService.java
, מגדירים נתיב לקובץ שבו
מחלקה של פרטי כניסה שמורה. בדוגמה הזאת הקובץ נוצר
ספריית /credentialStore
. מוסיפים את הנתיב למאגר פרטי הכניסה אל
.gitignore
ספרייה זו נוצרת ברגע שהמשתמש מתחיל
תהליך ההרשאה.
private static final File dataDirectory = new File("credentialStore");
בשלב הבא יוצרים שיטה בקובץ AuthService.java
שיוצרת
מחזירה אובייקט FileDataStoreFactory
. זה מאגר הנתונים
שומר את פרטי הכניסה.
/** Creates and returns FileDataStoreFactory object to store credentials.
* @return FileDataStoreFactory dataStore used to save and obtain users ids
* mapped to Credentials.
* @throws IOException if creating the dataStore is unsuccessful.
*/
public FileDataStoreFactory getCredentialDataStore() throws IOException {
FileDataStoreFactory dataStore = new FileDataStoreFactory(dataDirectory);
return dataStore;
}
צריך לעדכן את השיטה getFlow()
ב-AuthService.java
כך שתכלול
setDataStoreFactory
בGoogleAuthorizationCodeFlow Builder()
ותפעילו את הקריאה getCredentialDataStore()
כדי להגדיר את מאגר הנתונים.
GoogleAuthorizationCodeFlow authorizationCodeFlow =
new GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT,
JSON_FACTORY,
getClientSecrets(),
getScopes())
.setAccessType("offline")
.setDataStoreFactory(getCredentialDataStore())
.build();
בשלב הבא, מעדכנים את ה-method getAndSaveCredentials(String authorizationCode)
.
בעבר, השיטה הזו השיגה פרטי כניסה מבלי לאחסן אותם
בכל מקום. עדכון ה-method לאחסון פרטי הכניסה במאגר הנתונים
נוסף לאינדקס על ידי מזהה המשתמש.
אפשר לקבל את מזהה המשתמש מהאובייקט TokenResponse
באמצעות
id_token
, אבל חובה לאמת אותו קודם. אחרת, הלקוח
ייתכן שאפליקציות יוכלו להתחזות למשתמשים על ידי שליחת משתמשים ששונה
המזהים לשרת. מומלץ להשתמש בלקוח Google API
ספריות כדי לאמת את id_token
. לעיון בדף [זהות Google בכתובת
מידע נוסף על האסימון המזהה של Google.
// Obtaining the id_token will help determine which user signed in to the application.
String idTokenString = tokenResponse.get("id_token").toString();
// Validate the id_token using the GoogleIdTokenVerifier object.
GoogleIdTokenVerifier googleIdTokenVerifier = new GoogleIdTokenVerifier.Builder(
HTTP_TRANSPORT,
JSON_FACTORY)
.setAudience(Collections.singletonList(
googleClientSecrets.getWeb().getClientId()))
.build();
GoogleIdToken idToken = googleIdTokenVerifier.verify(idTokenString);
if (idToken == null) {
throw new Exception("Invalid ID token.");
}
לאחר האימות של id_token
, משיגים את ה-userId
לאחסון
עם האישורים שהשגתם.
// Obtain the user id from the id_token.
Payload payload = idToken.getPayload();
String userId = payload.getSubject();
צריך לעדכן את השיחה ל-flow.createAndStoreCredential
כדי לכלול בה את userId
.
// Save the user id and credentials to the configured FileDataStoreFactory.
Credential credential = flow.createAndStoreCredential(tokenResponse, userId);
צריך להוסיף שיטה למחלקה AuthService.java
שמחזירה את פרטי הכניסה
עבור משתמש ספציפי, אם הוא קיים במאגר הנתונים.
/** Find credentials in the datastore based on a specific user id.
* @param userId key to find in the file datastore.
* @return Credential object to be returned if a matching key is found in the datastore. Null if
* the key doesn't exist.
* @throws Exception if building flow object or checking for userId key is unsuccessful. */
public Credential loadFromCredentialDataStore(String userId) throws Exception {
try {
GoogleAuthorizationCodeFlow flow = getFlow();
Credential credential = flow.loadCredential(userId);
return credential;
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
אחזור פרטי הכניסה
הגדרת שיטה לאחזור Users
. קיבלת id
פרמטר של שאילתת login_hint
, שבו אפשר להשתמש כדי לאחזר משתמש ספציפי
רשומה.
Python
def get_credentials_from_storage(id):
"""
Retrieves credentials from the storage and returns them as a dictionary.
"""
return User.query.get(id)
Java
במחלקה AuthController.java
, מגדירים שיטה לאחזור משתמש
את מסד הנתונים על סמך מזהה המשתמש שלהם.
/** Retrieves stored credentials based on the user id.
* @param id the id of the current user
* @return User the database entry corresponding to the current user or null
* if the user doesn't exist in the database.
*/
public User getUser(String id) {
if (id != null) {
Optional<User> user = userRepository.findById(id);
if (user.isPresent()) {
return user.get();
}
}
return null;
}
אחסון פרטי כניסה
יש שני תרחישים לאחסון של פרטי כניסה. אם id
של המשתמש כבר
במסד הנתונים, ולעדכן את הרשומה הקיימת בערכים חדשים. אחרת,
יוצרים רשומת User
חדשה ומוסיפים אותה למסד הנתונים.
Python
ראשית, יש להגדיר שיטת שירות שמטמיעה את האחסון או העדכון או התנהגות המשתמשים.
def save_user_credentials(credentials=None, user_info=None):
"""
Updates or adds a User to the database. A new user is added only if both
credentials and user_info are provided.
Args:
credentials: An optional Credentials object.
user_info: An optional dict containing user info returned by the
OAuth 2.0 API.
"""
existing_user = get_credentials_from_storage(
flask.session.get("login_hint"))
if existing_user:
if user_info:
existing_user.id = user_info.get("id")
existing_user.display_name = user_info.get("name")
existing_user.email = user_info.get("email")
existing_user.portrait_url = user_info.get("picture")
if credentials and credentials.refresh_token is not None:
existing_user.refresh_token = credentials.refresh_token
elif credentials and user_info:
new_user = User(id=user_info.get("id"),
display_name=user_info.get("name"),
email=user_info.get("email"),
portrait_url=user_info.get("picture"),
refresh_token=credentials.refresh_token)
db.session.add(new_user)
db.session.commit()
יש שני מקרים שבהם תוכלו לשמור את פרטי הכניסה
מסד נתונים: כשהמשתמש חוזר לאפליקציה בסוף
תהליך הרשאה ובזמן ביצוע קריאה ל-API. כאן אנחנו
הוגדר בעבר מפתח credentials
של הסשן.
צריך להתקשר אל save_user_credentials
בסוף המסלול callback
. להשאיר את
אובייקט user_info
במקום לחלץ רק את שם המשתמש.
# The flow is complete! We'll use the credentials to fetch the user's info.
user_info_service = googleapiclient.discovery.build(
serviceName="oauth2", version="v2", credentials=credentials)
user_info = user_info_service.userinfo().get().execute()
flask.session["username"] = user_info.get("name")
save_user_credentials(credentials, user_info)
בנוסף, צריך לעדכן את פרטי הכניסה לאחר הקריאות ל-API. כאן
תוכלו לספק את פרטי הכניסה המעודכנים כארגומנטים
אמצעי תשלום אחד (save_user_credentials
).
# Save credentials in case access token was refreshed.
flask.session["credentials"] = credentials_to_dict(credentials)
save_user_credentials(credentials)
Java
קודם צריך להגדיר שיטה שמאחסנת או מעדכנת אובייקט User
ב-H2
מסד נתונים.
/** Adds or updates a user in the database.
* @param credential the credentials object to save or update in the database.
* @param userinfo the userinfo object to save or update in the database.
* @param session the current session.
*/
public void saveUser(Credential credential, Userinfo userinfo, HttpSession session) {
User storedUser = null;
if (session != null && session.getAttribute("login_hint") != null) {
storedUser = getUser(session.getAttribute("login_hint").toString());
}
if (storedUser != null) {
if (userinfo != null) {
storedUser.setId(userinfo.getId());
storedUser.setEmail(userinfo.getEmail());
}
userRepository.save(storedUser);
} else if (credential != null && userinfo != null) {
User newUser = new User(
userinfo.getId(),
userinfo.getEmail(),
);
userRepository.save(newUser);
}
}
יש שני מקרים שבהם תוכלו לשמור את פרטי הכניסה
מסד נתונים: כשהמשתמש חוזר לאפליקציה בסוף
תהליך הרשאה ובזמן ביצוע קריאה ל-API. כאן אנחנו
הגדרת בעבר את מפתח הסשן credentials
.
צריך להתקשר אל saveUser
בסוף המסלול /callback
. עליך להשאיר את
אובייקט user_info
במקום לחלץ רק את כתובת האימייל של המשתמש.
/** This is the end of the auth flow. We should save user info to the database. */
Userinfo userinfo = authService.getUserInfo(credentials);
saveUser(credentials, userinfo, session);
בנוסף, צריך לעדכן את פרטי הכניסה לאחר הקריאות ל-API. כאן
אפשר לספק את פרטי הכניסה המעודכנים כארגומנטים לפונקציה saveUser
.
/** Save credentials in case access token was refreshed. */
saveUser(credentials, null, session);
פרטי כניסה שפג תוקפם
לתשומת ליבכם: יש כמה סיבות אפשריות לכך שאסימוני רענון יהפכו ללא תקפים. האלה כוללים:
- לא נעשה שימוש באסימון הרענון במשך שישה חודשים.
- המשתמש מבטל את הרשאות הגישה של האפליקציה.
- המשתמש מחליף סיסמאות.
- המשתמש שייך לארגון ב-Google Cloud שיש לו בקרת סשנים שבתוקף.
אפשר לקבל אסימונים חדשים על ידי שליחת המשתמש שוב דרך תהליך ההרשאה, אם במקרה שפרטי הכניסה שלהם הופכים ללא תקפים.
ניתוב אוטומטי של המשתמש
צריך לשנות את נתיב הנחיתה של התוסף כדי לזהות אם המשתמש כבר אישר זאת את היישום שלנו. אם כן, תוכלו להעביר אותם לדף הראשי של התוסף. אחרת, צריך להזין הנחיה כדי להיכנס.
Python
מוודאים שקובץ מסד הנתונים נוצר כשהאפליקציה
השקות. מכניסים את השורה הבאה למאתחל של מודול (כמו
webapp/__init__.py
בדוגמה שסופקה) או בשיטה הראשית
מפעיל את השרת.
# Initialize the database file if not created.
if not os.path.exists(DATABASE_FILE_NAME):
db.create_all()
לאחר מכן, השיטה אמורה לטפל בפרמטר השאילתה login_hint
בתור
כמו שהסברנו למעלה. לאחר מכן יש לטעון את פרטי הכניסה לחנות אם מדובר באירוע חוזר
מבקר. ידוע לך שמדובר במבקר חוזר אם קיבלת את login_hint
.
מאחזרים את פרטי הכניסה המאוחסנים של המשתמש הזה וטוענים אותם
סשן.
stored_credentials = get_credentials_from_storage(login_hint)
# If we have stored credentials, store them in the session.
if stored_credentials:
# Load the client secrets file contents.
client_secrets_dict = json.load(
open(CLIENT_SECRETS_FILE)).get("web")
# Update the credentials in the session.
if not flask.session.get("credentials"):
flask.session["credentials"] = {}
flask.session["credentials"] = {
"token": stored_credentials.access_token,
"refresh_token": stored_credentials.refresh_token,
"token_uri": client_secrets_dict["token_uri"],
"client_id": client_secrets_dict["client_id"],
"client_secret": client_secrets_dict["client_secret"],
"scopes": SCOPES
}
# Set the username in the session.
flask.session["username"] = stored_credentials.display_name
לבסוף, נתב את המשתמש אל דף הכניסה אם הוא לא פרטי הכניסה. אם כן, ננתב אותם לדף הראשי של התוסף.
if "credentials" not in flask.session or \
flask.session["credentials"]["refresh_token"] is None:
return flask.render_template("authorization.html")
return flask.render_template(
"addon-discovery.html",
message="You've reached the addon discovery page.")
Java
ניווט אל מסלול הנחיתה של התוסף (/addon-discovery
באפשרויות שצוינו
לדוגמה). כמו שציינו למעלה, כאן טיפלת בlogin_hint
פרמטר של שאילתה.
קודם כול בודקים אם יש פרטי כניסה בסשן. אם לא, נתבו את
משתמש בתהליך האימות על ידי קריאה ל-method startAuthFlow
.
/** Check if the credentials exist in the session. The session could have
* been cleared when the user clicked the Sign-Out button, and the expected
* behavior after sign-out would be to display the sign-in page when the
* iframe is opened again. */
if (session.getAttribute("credentials") == null) {
return startAuthFlow(model);
}
לאחר מכן, טוענים את המשתמש ממסד הנתונים H2 אם מדובר במבקר חוזר. זו
מבקר חוזר אם מקבלים את הפרמטר של השאילתה login_hint
. אם
משתמש קיים במסד הנתונים של H2, צריך לטעון את פרטי הכניסה מפרטי הכניסה
מאגר הנתונים שהוגדר קודם לכן, ואת פרטי הכניסה בסשן. אם
פרטי הכניסה לא התקבלו ממאגר הנתונים של פרטי הכניסה, צריך לנתב את המשתמש
בתהליך האימות באמצעות קריאה ל-startAuthFlow
.
/** At this point, we know that credentials exist in the session, but we
* should update the session credentials with the credentials in persistent
* storage in case they were refreshed. If the credentials in persistent
* storage are null, we should navigate the user to the authorization flow
* to obtain persisted credentials. */
User storedUser = getUser(login_hint);
if (storedUser != null) {
Credential credential = authService.loadFromCredentialDataStore(login_hint);
if (credential != null) {
session.setAttribute("credentials", credential);
} else {
return startAuthFlow(model);
}
}
בשלב האחרון, לנתב את המשתמשים לדף הנחיתה של התוסף.
/** Finally, if there are credentials in the session and in persistent
* storage, direct the user to the addon-discovery page. */
return "addon-discovery";
בדיקת התוסף
נכנסים ל-Google Classroom בתור אחת מהבחינות של המורים משתמשים. עוברים לכרטיסייה עבודות ויוצרים מטלה חדשה. לוחצים על לוחצים על הלחצן תוספים שמתחת לאזור הטקסט ובוחרים את התוסף הרצוי. רכיב ה-iframe והתוסף טוען ה-URI להגדרת קובץ מצורף שציינתם ב הדף הגדרת אפליקציה ב-Google Workspace Marketplace SDK.
מעולה! אפשר להמשיך לשלב הבא: יצירת קבצים מצורפים וזיהוי התפקיד של המשתמש.