این دومین قدم در مجموعه مروری بر افزونههای Classroom است.
در این راهنما، Google Sign-in را به برنامه وب اضافه میکنید. این یک رفتار ضروری برای افزونههای Classroom است. از اعتبارنامههای این جریان مجوز برای همه تماسهای آینده با API استفاده کنید.
در طول این راهنما، موارد زیر را تکمیل می کنید:
- برنامه وب خود را برای نگهداری داده های جلسه در iframe پیکربندی کنید.
- جریان ورود به سیستم سرور به سرور Google OAuth 2.0 را پیاده سازی کنید.
- با OAuth 2.0 API تماس بگیرید.
- مسیرهای اضافی برای پشتیبانی از مجوز، خروج از سیستم و آزمایش تماسهای API ایجاد کنید.
پس از اتمام، می توانید به طور کامل به کاربران در برنامه وب خود مجوز دهید و با Google API تماس بگیرید.
جریان مجوز را درک کنید
API های Google از پروتکل OAuth 2.0 برای احراز هویت و مجوز استفاده می کنند. شرح کامل اجرای OAuth Google در راهنمای Google Identity OAuth موجود است.
اطلاعات کاربری برنامه شما در Google Cloud مدیریت می شود. پس از ایجاد این موارد، یک فرآیند چهار مرحله ای را برای احراز هویت و مجوز دادن به کاربر پیاده سازی کنید:
- درخواست مجوز. به عنوان بخشی از این درخواست، یک URL بازگشت به تماس ارائه کنید. پس از تکمیل، یک URL مجوز دریافت می کنید.
- کاربر را به URL مجوز هدایت کنید. صفحه به دست آمده کاربر را از مجوزهایی که برنامه شما نیاز دارد مطلع می کند و از آنها می خواهد که اجازه دسترسی را بدهند. پس از تکمیل، کاربر به URL بازگشت به تماس هدایت می شود.
- یک کد مجوز در مسیر برگشت به تماس خود دریافت کنید. کد مجوز را برای یک نشانه دسترسی و یک نشانه تازه سازی مبادله کنید.
- با استفاده از توکن ها با Google API تماس بگیرید.
اعتبارنامه OAuth 2.0 را دریافت کنید
اطمینان حاصل کنید که اعتبارنامه OAuth را همانطور که در صفحه نمای کلی توضیح داده شده است، ایجاد و دانلود کرده اید. پروژه شما باید از این اعتبارنامه ها برای ورود کاربر استفاده کند.
جریان مجوز را اجرا کنید
منطق و مسیرها را به برنامه وب خود اضافه کنید تا جریان توصیف شده را درک کنید، از جمله این ویژگی ها:
- پس از رسیدن به صفحه فرود، جریان مجوز را آغاز کنید.
- درخواست مجوز و رسیدگی به پاسخ سرور مجوز.
- اعتبار ذخیره شده را پاک کنید.
- مجوزهای برنامه را لغو کنید.
- یک تماس API را تست کنید.
مجوز را آغاز کنید
صفحه فرود خود را تغییر دهید تا در صورت لزوم جریان مجوز را آغاز کنید. افزونه می تواند در دو حالت ممکن باشد. یا توکنهای ذخیرهشده در جلسه جاری وجود دارد، یا باید توکنهایی را از سرور OAuth 2.0 دریافت کنید. اگر نشانههایی در جلسه وجود دارد، یک تماس آزمایشی API انجام دهید، یا در غیر این صورت از کاربر بخواهید به سیستم وارد شود.
پایتون
فایل routes.py
خود را باز کنید. ابتدا چند ثابت و پیکربندی کوکی خود را بر اساس توصیههای امنیتی 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",
)
به مسیر فرود افزونه خود بروید (این فایل /classroom-addon
در فایل مثال است). اگر جلسه حاوی کلید "credentials" نباشد ، منطق را برای ارائه یک صفحه ورود به سیستم اضافه کنید.
@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.")
جاوا
کد این راهنما را میتوانید در ماژول 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 خاص پس از تأیید برنامه شما استفاده می شود. برای اطلاعات در مورد محل قرار دادن فایل client_secret.json
به بخش Project Set Up README.md
در کد منبع مراجعه کنید.
@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
) را باز کنید و منطق را به مسیر فرود اضافه کنید تا در صورتی که جلسه حاوی کلید 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 شامل چندین بخش از اطلاعات است، مانند محدوده درخواستی، مسیر مقصد برای پس از مجوز، و شناسه مشتری برنامه وب. میتوانید این موارد را در این نشانی اینترنتی مجوز نمونه ببینید.
پایتون
وارد کردن زیر را به فایل 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)
از شی flow برای ساخت 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)
جاوا
روشهای زیر را به فایل AuthService.java
اضافه کنید تا شی جریان را نمونهسازی کنید و سپس از آن برای بازیابی URL مجوز استفاده کنید:
- متد
getClientSecrets()
فایل مخفی کلاینت را می خواند و یک شیGoogleClientSecrets
می سازد. - متد
getFlow()
نمونه ای ازGoogleAuthorizationCodeFlow
را ایجاد می کند. - متد
authorize()
از شیءGoogleAuthorizationCodeFlow
، پارامترstate
و Redirect 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
را به کلاس کنترلر اضافه کنید. این نقطه پایانی متد authorize()
AuthService را برای بازیابی پارامتر 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
در پاسخ دریافت می کنید. سپس کد را برای دسترسی و رفرش توکن ها مبادله کنید:
پایتون
واردات زیر را به فایل سرور 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)
شما اکنون اعتبار کامل دارید! آنها را در جلسه ذخیره کنید تا بتوان آنها را در روش ها یا مسیرهای دیگر بازیابی کرد، سپس به صفحه فرود افزودنی هدایت کنید.
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")
جاوا
روشی را به کلاس سرویس خود اضافه کنید که با ارسال کد مجوز بازیابی شده از تغییر مسیر انجام شده توسط URL مجوز، شی Credentials
برمی گرداند. این شیء 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
، آن را در جلسه ذخیره کنید. سپس، دیالوگ را ببندید و کاربر را به صفحه فرود افزونه هدایت کنید.
/** 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 API تماس بگیرید!
به عنوان مثال، اطلاعات پروفایل کاربر را درخواست کنید. می توانید اطلاعات کاربر را از API OAuth 2.0 درخواست کنید.
پایتون
خواندن اسناد مربوط به OAuth 2.0 Discovery 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"))
جاوا
یک متد در کلاس سرویس ایجاد کنید که یک شی 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);
}
}
اعتبارنامه ها را پاک کنید
شما می توانید اعتبار کاربری را با حذف آنها از جلسه فعلی "پاک کنید". این به شما امکان می دهد مسیریابی را در صفحه فرود افزونه آزمایش کنید.
توصیه میکنیم قبل از هدایت کاربر به صفحه فرود افزونه، نشانهای نشان دهید که از سیستم خارج شده است. برنامه شما باید از طریق جریان مجوز برای دریافت اعتبارنامه جدید عبور کند، اما از کاربران خواسته نمیشود که برنامه شما را مجدداً مجوز دهند.
پایتون
@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()
استفاده کنید، اما اگر مقادیر دیگری در جلسه ذخیره شده باشد، ممکن است اثرات ناخواسته ای داشته باشد.
جاوا
در کنترلر، یک /clear
endpoint اضافه کنید.
/** 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
مجوز برنامه شما را لغو کند. درخواست باید حاوی نشانه دسترسی کاربر باشد.
پایتون
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!")
جاوا
روشی را به کلاس سرویس اضافه کنید که با نقطه پایانی revoke تماس برقرار می کند.
/** 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 وارد شوید. به برگه Classwork بروید و یک تکلیف جدید ایجاد کنید. روی دکمه Add-ons در زیر ناحیه متن کلیک کنید، سپس افزونه خود را انتخاب کنید. iframe باز می شود و افزونه URI تنظیمات پیوست را که در صفحه پیکربندی برنامه GWM SDK مشخص کرده اید بارگیری می کند.
تبریک می گویم! شما آماده هستید تا به مرحله بعدی بروید: مدیریت بازدیدهای مکرر از افزونه خود .
،این دومین قدم در مجموعه مروری بر افزونههای Classroom است.
در این راهنما، Google Sign-in را به برنامه وب اضافه میکنید. این یک رفتار ضروری برای افزونههای Classroom است. از اعتبارنامههای این جریان مجوز برای همه تماسهای آینده با API استفاده کنید.
در طول این راهنما، موارد زیر را تکمیل می کنید:
- برنامه وب خود را برای نگهداری داده های جلسه در iframe پیکربندی کنید.
- جریان ورود به سیستم سرور به سرور Google OAuth 2.0 را پیاده سازی کنید.
- با OAuth 2.0 API تماس بگیرید.
- مسیرهای اضافی برای پشتیبانی از مجوز، خروج از سیستم و آزمایش تماسهای API ایجاد کنید.
پس از اتمام، می توانید به طور کامل به کاربران در برنامه وب خود مجوز دهید و با Google API تماس بگیرید.
جریان مجوز را درک کنید
API های Google از پروتکل OAuth 2.0 برای احراز هویت و مجوز استفاده می کنند. شرح کامل اجرای OAuth Google در راهنمای Google Identity OAuth موجود است.
اطلاعات کاربری برنامه شما در Google Cloud مدیریت می شود. پس از ایجاد این موارد، یک فرآیند چهار مرحله ای را برای احراز هویت و مجوز دادن به کاربر پیاده سازی کنید:
- درخواست مجوز. به عنوان بخشی از این درخواست، یک URL بازگشت به تماس ارائه کنید. پس از تکمیل، یک URL مجوز دریافت می کنید.
- کاربر را به URL مجوز هدایت کنید. صفحه به دست آمده کاربر را از مجوزهایی که برنامه شما نیاز دارد مطلع می کند و از آنها می خواهد که اجازه دسترسی را بدهند. پس از تکمیل، کاربر به URL بازگشت به تماس هدایت می شود.
- یک کد مجوز در مسیر برگشت به تماس خود دریافت کنید. کد مجوز را برای یک نشانه دسترسی و یک نشانه تازه سازی مبادله کنید.
- با استفاده از توکن ها با Google API تماس بگیرید.
اعتبارنامه OAuth 2.0 را دریافت کنید
اطمینان حاصل کنید که اعتبارنامه OAuth را همانطور که در صفحه نمای کلی توضیح داده شده است، ایجاد و دانلود کرده اید. پروژه شما باید از این اعتبارنامه ها برای ورود کاربر استفاده کند.
جریان مجوز را اجرا کنید
منطق و مسیرها را به برنامه وب خود اضافه کنید تا جریان توصیف شده را درک کنید، از جمله این ویژگی ها:
- پس از رسیدن به صفحه فرود، جریان مجوز را آغاز کنید.
- درخواست مجوز و رسیدگی به پاسخ سرور مجوز.
- اعتبار ذخیره شده را پاک کنید.
- مجوزهای برنامه را لغو کنید.
- یک تماس API را تست کنید.
مجوز را آغاز کنید
صفحه فرود خود را تغییر دهید تا در صورت لزوم جریان مجوز را آغاز کنید. افزونه می تواند در دو حالت ممکن باشد. یا توکنهای ذخیرهشده در جلسه جاری وجود دارد، یا باید توکنهایی را از سرور OAuth 2.0 دریافت کنید. اگر نشانههایی در جلسه وجود دارد، یک تماس آزمایشی API انجام دهید، یا در غیر این صورت از کاربر بخواهید به سیستم وارد شود.
پایتون
فایل routes.py
خود را باز کنید. ابتدا چند ثابت و پیکربندی کوکی خود را بر اساس توصیههای امنیتی 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",
)
به مسیر فرود افزونه خود بروید (این فایل /classroom-addon
در فایل مثال است). اگر جلسه حاوی کلید "credentials" نباشد ، منطق را برای ارائه یک صفحه ورود به سیستم اضافه کنید.
@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.")
جاوا
کد این راهنما را میتوانید در ماژول 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 خاص پس از تأیید برنامه شما استفاده می شود. برای اطلاعات در مورد محل قرار دادن فایل client_secret.json
به بخش Project Set Up README.md
در کد منبع مراجعه کنید.
@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
) را باز کنید و منطق را به مسیر فرود اضافه کنید تا در صورتی که جلسه حاوی کلید 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 شامل چندین بخش از اطلاعات است، مانند محدوده درخواستی، مسیر مقصد برای پس از مجوز، و شناسه مشتری برنامه وب. میتوانید این موارد را در این نشانی اینترنتی مجوز نمونه ببینید.
پایتون
وارد کردن زیر را به فایل 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)
از شی flow برای ساخت 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)
جاوا
روشهای زیر را به فایل AuthService.java
اضافه کنید تا شی جریان را نمونهسازی کنید و سپس از آن برای بازیابی URL مجوز استفاده کنید:
- متد
getClientSecrets()
فایل مخفی کلاینت را می خواند و یک شیGoogleClientSecrets
می سازد. - متد
getFlow()
نمونه ای ازGoogleAuthorizationCodeFlow
را ایجاد می کند. - متد
authorize()
از شیءGoogleAuthorizationCodeFlow
، پارامترstate
و Redirect 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
را به کلاس کنترلر اضافه کنید. این نقطه پایانی متد authorize()
AuthService را برای بازیابی پارامتر 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
در پاسخ دریافت می کنید. سپس کد را برای دسترسی و رفرش توکن ها مبادله کنید:
پایتون
واردات زیر را به فایل سرور 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)
شما اکنون اعتبار کامل دارید! آنها را در جلسه ذخیره کنید تا بتوان آنها را در روش ها یا مسیرهای دیگر بازیابی کرد، سپس به صفحه فرود افزودنی هدایت کنید.
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")
جاوا
روشی را به کلاس سرویس خود اضافه کنید که با ارسال کد مجوز بازیابی شده از تغییر مسیر انجام شده توسط URL مجوز، شی Credentials
برمی گرداند. این شیء 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
، آن را در جلسه ذخیره کنید. سپس، دیالوگ را ببندید و کاربر را به صفحه فرود افزونه هدایت کنید.
/** 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 API تماس بگیرید!
به عنوان مثال، اطلاعات پروفایل کاربر را درخواست کنید. می توانید اطلاعات کاربر را از API OAuth 2.0 درخواست کنید.
پایتون
خواندن اسناد مربوط به OAuth 2.0 Discovery 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"))
جاوا
یک متد در کلاس سرویس ایجاد کنید که یک شی 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);
}
}
اعتبارنامه ها را پاک کنید
شما می توانید اعتبار کاربری را با حذف آنها از جلسه فعلی "پاک کنید". این به شما امکان می دهد مسیریابی را در صفحه فرود افزونه آزمایش کنید.
توصیه میکنیم قبل از هدایت کاربر به صفحه فرود افزونه، نشانهای نشان دهید که از سیستم خارج شده است. برنامه شما باید از طریق جریان مجوز برای دریافت اعتبارنامه جدید عبور کند، اما از کاربران خواسته نمیشود که برنامه شما را مجدداً مجوز دهند.
پایتون
@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()
استفاده کنید، اما اگر مقادیر دیگری در جلسه ذخیره شده باشد، ممکن است اثرات ناخواسته ای داشته باشد.
جاوا
در کنترلر، یک /clear
endpoint اضافه کنید.
/** 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
مجوز برنامه شما را لغو کند. درخواست باید حاوی نشانه دسترسی کاربر باشد.
پایتون
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!")
جاوا
روشی را به کلاس سرویس اضافه کنید که با نقطه پایانی revoke تماس برقرار می کند.
/** 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 وارد شوید. به برگه Classwork بروید و یک تکلیف جدید ایجاد کنید. روی دکمه Add-ons در زیر ناحیه متن کلیک کنید، سپس افزونه خود را انتخاب کنید. iframe باز می شود و افزونه URI تنظیمات پیوست را که در صفحه پیکربندی برنامه GWM SDK مشخص کرده اید بارگیری می کند.
تبریک می گویم! شما آماده هستید تا به مرحله بعدی بروید: مدیریت بازدیدهای مکرر از افزونه خود .