นี่เป็นคำแนะนำแบบทีละขั้นที่ 2 ในชุดคำแนะนำแบบทีละขั้นเกี่ยวกับส่วนเสริมของ Classroom
ในคำแนะนำแบบทีละขั้นนี้ คุณจะเพิ่ม Google Sign-In ลงในเว็บแอปพลิเคชัน ซึ่งเป็นลักษณะการทำงานที่จำเป็นสำหรับส่วนเสริมของ Classroom ใช้ข้อมูลเข้าสู่ระบบจากขั้นตอนการให้สิทธิ์นี้สำหรับการเรียก API ในอนาคตทั้งหมด
ในคำแนะนำแบบทีละขั้นนี้ คุณจะต้องดำเนินการต่อไปนี้ให้เสร็จสมบูรณ์
- กำหนดค่าเว็บแอปให้เก็บรักษาข้อมูลเซสชันภายใน iframe
- ใช้ขั้นตอนการลงชื่อเข้าใช้แบบเซิร์ฟเวอร์ต่อเซิร์ฟเวอร์ของ Google OAuth 2.0
- เรียกใช้ OAuth 2.0 API
- สร้างเส้นทางเพิ่มเติมเพื่อรองรับการให้สิทธิ์ การออกจากระบบ และทดสอบการเรียก API
เมื่อดำเนินการเสร็จแล้ว คุณจะให้สิทธิ์ผู้ใช้ในเว็บแอปได้อย่างเต็มที่และออกการเรียกไปยัง Google APIs
ทำความเข้าใจขั้นตอนการให้สิทธิ์
Google APIs ใช้โปรโตคอล OAuth 2.0 สำหรับการตรวจสอบสิทธิ์และการให้สิทธิ์ ดูคำอธิบายการใช้ OAuth ของ Google ฉบับเต็มได้ในคู่มือ Google Identity OAuth
ข้อมูลเข้าสู่ระบบของแอปพลิเคชันได้รับการจัดการใน Google Cloud เมื่อสร้างขั้นตอนเหล่านี้แล้ว ให้ใช้กระบวนการ 4 ขั้นตอนในการตรวจสอบสิทธิ์และให้สิทธิ์ผู้ใช้ ดังนี้
- ส่งคำขอการให้สิทธิ์ ระบุ URL เรียกกลับเป็นส่วนหนึ่งของคำขอนี้ เมื่อดำเนินการเสร็จแล้ว คุณจะได้รับ URL การให้สิทธิ์
- เปลี่ยนเส้นทางผู้ใช้ไปยัง URL การให้สิทธิ์ หน้าผลลัพธ์จะแจ้งให้ผู้ใช้ทราบถึงสิทธิ์ที่แอปของคุณต้องการ และแจ้งให้ผู้ใช้อนุญาตให้เข้าถึง เมื่อดำเนินการเสร็จแล้ว ระบบจะกำหนดเส้นทางผู้ใช้ไปยัง URL เรียกกลับ
- รับรหัสการให้สิทธิ์ในเส้นทางของ Callback แลกเปลี่ยนรหัสการให้สิทธิ์สำหรับโทเค็นเพื่อการเข้าถึงและโทเค็นการรีเฟรช
- เรียก Google API โดยใช้โทเค็น
รับข้อมูลเข้าสู่ระบบ OAuth 2.0
โปรดตรวจสอบว่าได้สร้างและดาวน์โหลดข้อมูลเข้าสู่ระบบ OAuth แล้วตามที่อธิบายไว้ในหน้าภาพรวม โปรเจ็กต์ต้องใช้ข้อมูลเข้าสู่ระบบเหล่านี้เพื่อลงชื่อเข้าใช้ผู้ใช้
ใช้ขั้นตอนการให้สิทธิ์
เพิ่มตรรกะและเส้นทางลงในเว็บแอปเพื่อให้ทราบขั้นตอนที่อธิบายไว้ รวมถึงฟีเจอร์เหล่านี้
- เริ่มขั้นตอนการให้สิทธิ์เมื่อไปถึงหน้า Landing Page
- ส่งคำขอการให้สิทธิ์และจัดการการตอบกลับของเซิร์ฟเวอร์การให้สิทธิ์
- ล้างข้อมูลเข้าสู่ระบบที่จัดเก็บไว้
- เพิกถอนสิทธิ์ของแอป
- ทดสอบการเรียก API
เริ่มการให้สิทธิ์
แก้ไขหน้า Landing Page ของคุณเพื่อเริ่มต้นขั้นตอนการให้สิทธิ์ หากจำเป็น ส่วนเสริมอาจมีสถานะที่เป็นไปได้ 2 สถานะ คือมีโทเค็นที่บันทึกไว้ในเซสชันปัจจุบัน หรือคุณต้องรับโทเค็นจากเซิร์ฟเวอร์ OAuth 2.0 ทดสอบการเรียก API หากมีโทเค็นในเซสชัน หรือแจ้งให้ผู้ใช้ลงชื่อเข้าใช้
Python
เปิดไฟล์ routes.py
ขั้นแรก ให้ตั้งค่าคงที่ 2-3 รายการและการกำหนดค่าคุกกี้ตามคำแนะนำด้านความปลอดภัยของ iframe
# The file that contains the OAuth 2.0 client_id and client_secret.
CLIENT_SECRETS_FILE = "client_secret.json"
# The OAuth 2.0 access scopes to request.
# These scopes must match the scopes in your Google Cloud project's OAuth Consent
# Screen: https://console.cloud.google.com/apis/credentials/consent
SCOPES = [
"openid",
"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/classroom.addons.teacher",
"https://www.googleapis.com/auth/classroom.addons.student"
]
# Flask cookie configurations.
app.config.update(
SESSION_COOKIE_SECURE=True,
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SAMESITE="None",
)
ย้ายไปที่เส้นทาง Landing Page ของส่วนเสริม (นี่คือ /classroom-addon
ในไฟล์ตัวอย่าง) เพิ่มตรรกะเพื่อแสดงหน้าลงชื่อเข้าใช้หากเซสชันไม่มีคีย์ "ข้อมูลเข้าสู่ระบบ"
@app.route("/classroom-addon")
def classroom_addon():
if "credentials" not in flask.session:
return flask.render_template("authorization.html")
return flask.render_template(
"addon-discovery.html",
message="You've reached the addon discovery page.")
Java
โค้ดสำหรับคำแนะนำแบบทีละขั้นนี้จะอยู่ในโมดูล step_02_sign_in
เปิดไฟล์ application.properties
แล้วเพิ่มการกำหนดค่าเซสชันที่เป็นไปตามคำแนะนำด้านความปลอดภัยของ iframe
# iFrame security recommendations call for cookies to have the HttpOnly and
# secure attribute set
server.servlet.session.cookie.http-only=true
server.servlet.session.cookie.secure=true
# Ensures that the session is maintained across the iframe and sign-in pop-up.
server.servlet.session.cookie.same-site=none
สร้างคลาสบริการ (AuthService.java
ในโมดูล step_02_sign_in
) เพื่อจัดการลอจิกที่อยู่เบื้องหลังปลายทางในไฟล์ตัวควบคุมและตั้งค่า URI การเปลี่ยนเส้นทาง ตำแหน่งไฟล์ข้อมูลลับของไคลเอ็นต์ และขอบเขตที่ส่วนเสริมของคุณต้องการ URI การเปลี่ยนเส้นทางใช้เพื่อเปลี่ยนเส้นทางผู้ใช้ไปยัง URI ที่เจาะจงหลังจากที่ผู้ใช้ให้สิทธิ์แอปแล้ว ดูส่วนการตั้งค่าโปรเจ็กต์ของ README.md
ในซอร์สโค้ดสำหรับข้อมูลเกี่ยวกับตำแหน่งที่จะวางไฟล์ client_secret.json
@Service
public class AuthService {
private static final String REDIRECT_URI = "https://localhost:5000/callback";
private static final String CLIENT_SECRET_FILE = "client_secret.json";
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
private static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
private static final String[] REQUIRED_SCOPES = {
"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/classroom.addons.teacher",
"https://www.googleapis.com/auth/classroom.addons.student"
};
/** Creates and returns a Collection object with all requested scopes.
* @return Collection of scopes requested by the application.
*/
public static Collection<String> getScopes() {
return new ArrayList<>(Arrays.asList(REQUIRED_SCOPES));
}
}
เปิดไฟล์ตัวควบคุม (AuthController.java
ในโมดูล step_02_sign_in
) และเพิ่มตรรกะให้กับเส้นทาง Landing Page เพื่อแสดงผลหน้าลงชื่อเข้าใช้หากเซสชันไม่มีคีย์ credentials
@GetMapping(value = {"/start-auth-flow"})
public String startAuthFlow(Model model) {
try {
return "authorization";
} catch (Exception e) {
return onError(e.getMessage(), model);
}
}
@GetMapping(value = {"/addon-discovery"})
public String addon_discovery(HttpSession session, Model model) {
try {
if (session == null || session.getAttribute("credentials") == null) {
return startAuthFlow(model);
}
return "addon-discovery";
} catch (Exception e) {
return onError(e.getMessage(), model);
}
}
หน้าการให้สิทธิ์ของคุณควรมีลิงก์หรือปุ่มสำหรับให้ผู้ใช้ "ลงชื่อเข้าใช้" การคลิกนี้จะเปลี่ยนเส้นทางผู้ใช้ไปยังเส้นทาง authorize
ส่งคำขอการให้สิทธิ์
หากต้องการขอสิทธิ์ โปรดสร้างและเปลี่ยนเส้นทางผู้ใช้ไปยัง URL การตรวจสอบสิทธิ์ URL นี้มีข้อมูลหลายรายการ เช่น ขอบเขตที่ขอ เส้นทางปลายทางสำหรับหลังการให้สิทธิ์ และรหัสไคลเอ็นต์ของเว็บแอป ซึ่งคุณดูได้ในตัวอย่างนี้คือ URL การให้สิทธิ์
Python
เพิ่มการนำเข้าต่อไปนี้ลงในไฟล์ routes.py
import google_auth_oauthlib.flow
สร้างเส้นทางใหม่ /authorize
สร้างอินสแตนซ์ของ google_auth_oauthlib.flow.Flow
เราขอแนะนำอย่างยิ่งให้ใช้เมธอด from_client_secrets_file
ที่รวมอยู่เพื่อดำเนินการดังกล่าว
@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)
ตั้งค่า redirect_uri
ของ flow
นี่คือเส้นทางที่คุณตั้งใจให้ผู้ใช้
เดินทางกลับหลังจากให้สิทธิ์แอปแล้ว นี่คือ /callback
ในตัวอย่างต่อไปนี้
# 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("callback", _external=True)
ใช้ออบเจ็กต์โฟลว์เพื่อสร้าง authorization_url
และ state
จัดเก็บ state
ในเซสชัน ซึ่งจะใช้ในการยืนยันความถูกต้องของการตอบกลับของเซิร์ฟเวอร์ในภายหลัง สุดท้าย ให้เปลี่ยนเส้นทางผู้ใช้ไปยัง 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")
# Store the state so the callback can verify the auth server response.
flask.session["state"] = state
# Redirect the user to the OAuth authorization URL.
return flask.redirect(authorization_url)
Java
เพิ่มเมธอดต่อไปนี้ลงในไฟล์ AuthService.java
เพื่อสร้างอินสแตนซ์ออบเจ็กต์โฟลว์ จากนั้นใช้เพื่อเรียกข้อมูล URL การให้สิทธิ์
- เมธอด
getClientSecrets()
จะอ่านไฟล์รหัสลับไคลเอ็นต์และสร้างออบเจ็กต์GoogleClientSecrets
- เมธอด
getFlow()
จะสร้างอินสแตนซ์ของGoogleAuthorizationCodeFlow
- วิธี
authorize()
ใช้ออบเจ็กต์GoogleAuthorizationCodeFlow
, พารามิเตอร์state
และ URI การเปลี่ยนเส้นทางเพื่อดึงข้อมูล URL การให้สิทธิ์ พารามิเตอร์state
จะใช้เพื่อยืนยันความถูกต้องของการตอบกลับจากเซิร์ฟเวอร์การให้สิทธิ์ จากนั้นเมธอดจะแสดงแผนที่ที่มี URL การให้สิทธิ์และพารามิเตอร์state
/** Reads the client secret file downloaded from Google Cloud.
* @return GoogleClientSecrets read in from client secret file. */
public GoogleClientSecrets getClientSecrets() throws Exception {
try {
InputStream in = SignInApplication.class.getClassLoader()
.getResourceAsStream(CLIENT_SECRET_FILE);
if (in == null) {
throw new FileNotFoundException("Client secret file not found: "
+ CLIENT_SECRET_FILE);
}
GoogleClientSecrets clientSecrets = GoogleClientSecrets
.load(JSON_FACTORY, new InputStreamReader(in));
return clientSecrets;
} catch (Exception e) {
throw e;
}
}
/** Builds and returns authorization code flow.
* @return GoogleAuthorizationCodeFlow object used to retrieve an access
* token and refresh token for the application.
* @throws Exception if reading client secrets or building code flow object
* is unsuccessful.
*/
public GoogleAuthorizationCodeFlow getFlow() throws Exception {
try {
GoogleAuthorizationCodeFlow authorizationCodeFlow =
new GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT,
JSON_FACTORY,
getClientSecrets(),
getScopes())
.setAccessType("offline")
.build();
return authorizationCodeFlow;
} catch (Exception e) {
throw e;
}
}
/** Builds and returns a map with the authorization URL, which allows the
* user to give the app permission to their account, and the state parameter,
* which is used to prevent cross site request forgery.
* @return map with authorization URL and state parameter.
* @throws Exception if building the authorization URL is unsuccessful.
*/
public HashMap authorize() throws Exception {
HashMap<String, String> authDataMap = new HashMap<>();
try {
String state = new BigInteger(130, new SecureRandom()).toString(32);
authDataMap.put("state", state);
GoogleAuthorizationCodeFlow flow = getFlow();
String authUrl = flow
.newAuthorizationUrl()
.setState(state)
.setRedirectUri(REDIRECT_URI)
.build();
String url = authUrl;
authDataMap.put("url", url);
return authDataMap;
} catch (Exception e) {
throw e;
}
}
ใช้การแทรกตัวสร้างเพื่อสร้างอินสแตนซ์ของคลาสบริการในคลาสตัวควบคุม
/** Declare AuthService to be used in the Controller class constructor. */
private final AuthService authService;
/** AuthController constructor. Uses constructor injection to instantiate
* the AuthService and UserRepository classes.
* @param authService the service class that handles the implementation logic
* of requests.
*/
public AuthController(AuthService authService) {
this.authService = authService;
}
เพิ่มปลายทาง /authorize
ลงในคลาสตัวควบคุม ปลายทางนี้จะเรียกใช้เมธอด AuthService authorize()
เพื่อเรียกพารามิเตอร์ state
และ URL การให้สิทธิ์ จากนั้นปลายทางจะจัดเก็บพารามิเตอร์ state
ในเซสชันและเปลี่ยนเส้นทางผู้ใช้ไปยัง URL การให้สิทธิ์
/** Redirects the sign-in pop-up to the authorization URL.
* @param response the current response to pass information to.
* @param session the current session.
* @throws Exception if redirection to the authorization URL is unsuccessful.
*/
@GetMapping(value = {"/authorize"})
public void authorize(HttpServletResponse response, HttpSession session)
throws Exception {
try {
HashMap authDataMap = authService.authorize();
String authUrl = authDataMap.get("url").toString();
String state = authDataMap.get("state").toString();
session.setAttribute("state", state);
response.sendRedirect(authUrl);
} catch (Exception e) {
throw e;
}
}
จัดการการตอบสนองของเซิร์ฟเวอร์
หลังจากให้สิทธิ์แล้ว ผู้ใช้จะกลับไปยังเส้นทาง redirect_uri
จากขั้นตอนก่อนหน้า ในตัวอย่างก่อนหน้านี้ เส้นทางนี้คือ /callback
คุณจะได้รับ code
ในการตอบกลับเมื่อผู้ใช้กลับมาจากหน้าการให้สิทธิ์ จากนั้นแลกเปลี่ยนรหัสเพื่อการเข้าถึงและรีเฟรชโทเค็น ดังนี้
Python
เพิ่มการนำเข้าต่อไปนี้ลงในไฟล์เซิร์ฟเวอร์ Flask
import google.oauth2.credentials
import googleapiclient.discovery
เพิ่มเส้นทางไปยังเซิร์ฟเวอร์ สร้างอินสแตนซ์ google_auth_oauthlib.flow.Flow
อื่น แต่ครั้งนี้นำสถานะที่บันทึกไว้ในขั้นตอนก่อนหน้ามาใช้ซ้ำ
@app.route("/callback")
def callback():
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("callback", _external=True)
ถัดไป ให้ขอสิทธิ์เข้าถึงและรีเฟรชโทเค็น โชคดีที่ออบเจ็กต์ flow
ยังมีเมธอด fetch_token
เพื่อทำสิ่งนี้ด้วย เมธอดนี้ต้องการอาร์กิวเมนต์ code
หรือ authorization_response
ใช้ authorization_response
เนื่องจากเป็น URL แบบเต็มจากคำขอ
authorization_response = flask.request.url
flow.fetch_token(authorization_response=authorization_response)
ตอนนี้คุณมีข้อมูลเข้าสู่ระบบครบถ้วนแล้ว จัดเก็บไว้ในเซสชันเพื่อให้ระบบดึงข้อมูลได้ในวิธีการหรือเส้นทางอื่นๆ จากนั้นเปลี่ยนเส้นทางไปยังหน้า Landing Page ของส่วนเสริม
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,
"scopes": credentials.scopes
}
# Close the pop-up by rendering an HTML page with a script that redirects
# the owner and closes itself. This can be done with a bit of JavaScript:
# <script>
# window.opener.location.href = "{{ url_for('classroom_addon') }}";
# window.close();
# </script>
return flask.render_template("close-me.html")
Java
เพิ่มเมธอดลงในคลาสบริการที่ส่งคืนออบเจ็กต์ Credentials
ด้วยการส่งผ่านรหัสการให้สิทธิ์ที่ดึงมาจากการเปลี่ยนเส้นทางซึ่งดำเนินการโดย URL การให้สิทธิ์ ระบบใช้ออบเจ็กต์ Credentials
นี้ในภายหลังเพื่อเรียกโทเค็นเพื่อการเข้าถึงและโทเค็นการรีเฟรช
/** Returns the required credentials to access Google APIs.
* @param authorizationCode the authorization code provided by the
* authorization URL that's used to obtain credentials.
* @return the credentials that were retrieved from the authorization flow.
* @throws Exception if retrieving credentials is unsuccessful.
*/
public Credential getAndSaveCredentials(String authorizationCode) throws Exception {
try {
GoogleAuthorizationCodeFlow flow = getFlow();
GoogleClientSecrets googleClientSecrets = getClientSecrets();
TokenResponse tokenResponse = flow.newTokenRequest(authorizationCode)
.setClientAuthentication(new ClientParametersAuthentication(
googleClientSecrets.getWeb().getClientId(),
googleClientSecrets.getWeb().getClientSecret()))
.setRedirectUri(REDIRECT_URI)
.execute();
Credential credential = flow.createAndStoreCredential(tokenResponse, null);
return credential;
} catch (Exception e) {
throw e;
}
}
เพิ่มปลายทางสำหรับ URI การเปลี่ยนเส้นทางไปยังตัวควบคุม เรียกดูรหัสการให้สิทธิ์และพารามิเตอร์ state
จากคำขอ เปรียบเทียบพารามิเตอร์ state
นี้กับแอตทริบิวต์ state
ที่จัดเก็บไว้ในเซสชัน หากตรงกัน ให้ดำเนินการต่อด้วยขั้นตอนการให้สิทธิ์ หากไม่ตรงกัน
ให้แสดงข้อผิดพลาด
จากนั้นเรียกใช้เมธอด AuthService
getAndSaveCredentials
และส่งรหัสการให้สิทธิ์เป็นพารามิเตอร์ หลังจากเรียกออบเจ็กต์ Credentials
แล้ว ให้จัดเก็บไว้ในเซสชัน จากนั้นปิดกล่องโต้ตอบและเปลี่ยนเส้นทางผู้ใช้ไปยังหน้า Landing Page ของส่วนเสริม
/** Handles the redirect URL to grant the application access to the user's
* account.
* @param request the current request used to obtain the authorization code
* and state parameter from.
* @param session the current session.
* @param response the current response to pass information to.
* @param model the Model interface to pass error information that's
* displayed on the error page.
* @return the close-pop-up template if authorization is successful, or the
* onError method to handle and display the error message.
*/
@GetMapping(value = {"/callback"})
public String callback(HttpServletRequest request, HttpSession session,
HttpServletResponse response, Model model) {
try {
String authCode = request.getParameter("code");
String requestState = request.getParameter("state");
String sessionState = session.getAttribute("state").toString();
if (!requestState.equals(sessionState)) {
response.setStatus(401);
return onError("Invalid state parameter.", model);
}
Credential credentials = authService.getAndSaveCredentials(authCode);
session.setAttribute("credentials", credentials);
return "close-pop-up";
} catch (Exception e) {
return onError(e.getMessage(), model);
}
}
ทดสอบการเรียก API
เมื่อดำเนินการขั้นตอนนี้เสร็จสมบูรณ์แล้ว คุณจะออกการเรียกไปยัง Google APIs ได้
เช่น ขอข้อมูลโปรไฟล์ของผู้ใช้ คุณขอข้อมูลของผู้ใช้ได้จาก OAuth 2.0 API
Python
โปรดอ่านเอกสารประกอบสำหรับ OAuth 2.0 discovery API ใช้ API ดังกล่าวเพื่อรับออบเจ็กต์ UserInfo ที่มีการป้อนข้อมูล
# Retrieve the credentials from the session data and construct a
# Credentials instance.
credentials = google.oauth2.credentials.Credentials(
**flask.session["credentials"])
# Construct the OAuth 2.0 v2 discovery API library.
user_info_service = googleapiclient.discovery.build(
serviceName="oauth2", version="v2", credentials=credentials)
# Request and store the username in the session.
# This allows it to be used in other methods or in an HTML template.
flask.session["username"] = (
user_info_service.userinfo().get().execute().get("name"))
Java
สร้างเมธอดในคลาสบริการที่สร้างออบเจ็กต์ UserInfo
โดยใช้ Credentials
เป็นพารามิเตอร์
/** Obtains the Userinfo object by passing in the required credentials.
* @param credentials retrieved from the authorization flow.
* @return the Userinfo object for the currently signed-in user.
* @throws IOException if creating UserInfo service or obtaining the
* Userinfo object is unsuccessful.
*/
public Userinfo getUserInfo(Credential credentials) throws IOException {
try {
Oauth2 userInfoService = new Oauth2.Builder(
new NetHttpTransport(),
new GsonFactory(),
credentials).build();
Userinfo userinfo = userInfoService.userinfo().get().execute();
return userinfo;
} catch (Exception e) {
throw e;
}
}
เพิ่มปลายทาง /test
ลงในตัวควบคุมที่แสดงอีเมลของผู้ใช้
/** Returns the test request page with the user's email.
* @param session the current session.
* @param model the Model interface to pass error information that's
* displayed on the error page.
* @return the test page that displays the current user's email or the
* onError method to handle and display the error message.
*/
@GetMapping(value = {"/test"})
public String test(HttpSession session, Model model) {
try {
Credential credentials = (Credential) session.getAttribute("credentials");
Userinfo userInfo = authService.getUserInfo(credentials);
String userInfoEmail = userInfo.getEmail();
if (userInfoEmail != null) {
model.addAttribute("userEmail", userInfoEmail);
} else {
return onError("Could not get user email.", model);
}
return "test";
} catch (Exception e) {
return onError(e.getMessage(), model);
}
}
ล้างข้อมูลเข้าสู่ระบบ
คุณจะ "ล้าง" ข้อมูลเข้าสู่ระบบของผู้ใช้ได้โดยนำผู้ใช้ออกจากเซสชันปัจจุบัน วิธีนี้ช่วยให้คุณทดสอบการกำหนดเส้นทางในหน้า Landing Page ของส่วนเสริมได้
เราขอแนะนำให้แสดงตัวบ่งชี้ว่าผู้ใช้ออกจากระบบแล้วก่อนเปลี่ยนเส้นทางไปยังหน้า Landing Page ของส่วนเสริม แอปของคุณควรผ่านขั้นตอนการให้สิทธิ์เพื่อรับข้อมูลเข้าสู่ระบบใหม่ แต่ผู้ใช้จะไม่ได้รับแจ้งให้ให้สิทธิ์แอปอีกครั้ง
Python
@app.route("/clear")
def clear_credentials():
if "credentials" in flask.session:
del flask.session["credentials"]
del flask.session["username"]
return flask.render_template("signed-out.html")
หรือใช้ flask.session.clear()
แต่อาจส่งผลที่ไม่คาดคิดหากคุณมีค่าอื่นๆ ที่จัดเก็บไว้ในเซสชัน
Java
เพิ่มปลายทาง /clear
ในตัวควบคุม
/** Clears the credentials in the session and returns the sign-out
* confirmation page.
* @param session the current session.
* @return the sign-out confirmation page.
*/
@GetMapping(value = {"/clear"})
public String clear(HttpSession session) {
try {
if (session != null && session.getAttribute("credentials") != null) {
session.removeAttribute("credentials");
}
return "sign-out";
} catch (Exception e) {
return onError(e.getMessage(), model);
}
}
เพิกถอนสิทธิ์ของแอป
ผู้ใช้เพิกถอนสิทธิ์ของแอปได้โดยส่งคำขอPOST
ไปที่ https://oauth2.googleapis.com/revoke
โดยคำขอควรมีโทเค็นเพื่อการเข้าถึงของผู้ใช้
Python
import requests
@app.route("/revoke")
def revoke():
if "credentials" not in flask.session:
return flask.render_template("addon-discovery.html",
message="You need to authorize before " +
"attempting 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"})
if "credentials" in flask.session:
del flask.session["credentials"]
del flask.session["username"]
status_code = getattr(revoke, "status_code")
if status_code == 200:
return flask.render_template("authorization.html")
else:
return flask.render_template(
"index.html", message="An error occurred during revocation!")
Java
เพิ่มเมธอดลงในคลาสบริการที่เรียกใช้ปลายทางการเพิกถอน
/** Revokes the app's permissions to the user's account.
* @param credentials retrieved from the authorization flow.
* @return response entity returned from the HTTP call to obtain response
* information.
* @throws RestClientException if the POST request to the revoke endpoint is
* unsuccessful.
*/
public ResponseEntity<String> revokeCredentials(Credential credentials) throws RestClientException {
try {
String accessToken = credentials.getAccessToken();
String url = "https://oauth2.googleapis.com/revoke?token=" + accessToken;
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE);
HttpEntity<Object> httpEntity = new HttpEntity<Object>(httpHeaders);
ResponseEntity<String> responseEntity = new RestTemplate().exchange(
url,
HttpMethod.POST,
httpEntity,
String.class);
return responseEntity;
} catch (RestClientException e) {
throw e;
}
}
เพิ่มปลายทาง /revoke
ลงในตัวควบคุมที่ล้างเซสชันและเปลี่ยนเส้นทางผู้ใช้ไปยังหน้าการให้สิทธิ์หากการเพิกถอนสำเร็จ
/** Revokes the app's permissions and returns the authorization page.
* @param session the current session.
* @return the authorization page.
* @throws Exception if revoking access is unsuccessful.
*/
@GetMapping(value = {"/revoke"})
public String revoke(HttpSession session) throws Exception {
try {
if (session != null && session.getAttribute("credentials") != null) {
Credential credentials = (Credential) session.getAttribute("credentials");
ResponseEntity responseEntity = authService.revokeCredentials(credentials);
Integer httpStatusCode = responseEntity.getStatusCodeValue();
if (httpStatusCode != 200) {
return onError("There was an issue revoking access: " +
responseEntity.getStatusCode(), model);
}
session.removeAttribute("credentials");
}
return startAuthFlow(model);
} catch (Exception e) {
return onError(e.getMessage(), model);
}
}
ทดสอบส่วนเสริม
ลงชื่อเข้าใช้ Google Classroom ในฐานะผู้ใช้การทดสอบของครู ไปที่แท็บงานของชั้นเรียนและสร้างงานใหม่ คลิกปุ่มส่วนเสริมใต้พื้นที่ข้อความ แล้วเลือกส่วนเสริม iframe จะเปิดขึ้นและส่วนเสริมจะโหลด URI การตั้งค่าไฟล์แนบที่คุณระบุไว้ในหน้าการกำหนดค่าแอปของ GWM SDK
ยินดีด้วย คุณก็พร้อมที่จะทำขั้นตอนถัดไปแล้ว นั่นคือการจัดการการเข้าชมส่วนเสริมซ้ำ