کاربر را وارد کنید

این دومین راهنمای گام به گام از مجموعه راهنمای افزونه‌های Classroom است.

در این راهنما، شما ورود به سیستم با گوگل (Google Sign-in) را به برنامه وب اضافه می‌کنید. این یک رفتار الزامی برای افزونه‌های Classroom است. از اعتبارنامه‌های این جریان مجوز برای همه فراخوانی‌های بعدی به API استفاده کنید.

در طول این راهنمای گام به گام، موارد زیر را تکمیل می‌کنید:

  • برنامه وب خود را طوری پیکربندی کنید که داده‌های جلسه را در یک iframe نگهداری کند.
  • جریان ورود به سیستم سرور به سرور Google OAuth 2.0 را پیاده‌سازی کنید.
  • یک فراخوانی به API مربوط به OAuth 2.0 صادر کنید.
  • مسیرهای اضافی برای پشتیبانی از احراز هویت، خروج از سیستم و آزمایش فراخوانی‌های API ایجاد کنید.

پس از اتمام، می‌توانید کاربران را در برنامه وب خود به طور کامل مجاز کنید و فراخوانی‌هایی را به APIهای گوگل انجام دهید.

جریان مجوز را درک کنید

APIهای گوگل از پروتکل OAuth 2.0 برای احراز هویت و مجوزدهی استفاده می‌کنند. شرح کامل پیاده‌سازی OAuth گوگل در راهنمای OAuth مربوط به Google Identity موجود است.

اعتبارنامه‌های برنامه شما در Google Cloud مدیریت می‌شوند. پس از ایجاد این اعتبارنامه‌ها، یک فرآیند چهار مرحله‌ای را برای احراز هویت و مجوزدهی به کاربر پیاده‌سازی کنید:

  1. درخواست مجوز. به عنوان بخشی از این درخواست، یک URL بازگشتی ارائه دهید. پس از تکمیل، یک URL مجوز دریافت خواهید کرد.
  2. کاربر را به URL مجوز هدایت کنید. صفحه حاصل، کاربر را از مجوزهای مورد نیاز برنامه شما مطلع می‌کند و از او می‌خواهد که اجازه دسترسی بدهد. پس از اتمام، کاربر به URL فراخوانی هدایت می‌شود.
  3. یک کد مجوز در مسیر فراخوانی خود دریافت کنید. کد مجوز را با یک توکن دسترسی و یک توکن به‌روزرسانی جایگزین کنید.
  4. با استفاده از توکن‌ها، فراخوانی‌هایی را با 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 خود، به بخش تنظیم پروژه در 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 شامل چندین بخش از اطلاعات، مانند محدوده‌های درخواستی، مسیر مقصد برای پس از احراز هویت و شناسه کلاینت برنامه وب است. می‌توانید این موارد را در این URL مجوز نمونه مشاهده کنید.

پایتون

کد زیر را به فایل routes.py خود اضافه کنید.

import google_auth_oauthlib.flow

یک مسیر جدید /authorize ایجاد کنید. یک نمونه از google_auth_oauthlib.flow.Flow ایجاد کنید؛ برای این کار اکیداً توصیه می‌کنیم از متد from_client_secrets_file که در فایل `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 را در session ذخیره کنید؛ از آن برای تأیید صحت پاسخ سرور بعداً استفاده می‌شود. در نهایت، کاربر را به 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 و URI تغییر مسیر برای بازیابی URL احراز هویت استفاده می‌کند. پارامتر state برای تأیید صحت پاسخ از سرور احراز هویت استفاده می‌شود. سپس این متد یک map با 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 را در session ذخیره کرده و کاربران را به 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 ذخیره شده در session مقایسه کنید. اگر مطابقت داشتند، سپس با جریان مجوز ادامه دهید. اگر مطابقت نداشتند، یک خطا برگردانید.

سپس، متد AuthService getAndSaveCredentials را فراخوانی کرده و کد احراز هویت را به عنوان پارامتر ارسال کنید. پس از بازیابی شیء Credentials ، آن را در session ذخیره کنید. سپس، کادر محاوره‌ای را ببندید و کاربر را به صفحه فرود افزونه هدایت کنید.

/** 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

با تکمیل مراحل، اکنون می‌توانید APIهای گوگل را فراخوانی کنید!

به عنوان مثال، اطلاعات پروفایل کاربر را درخواست کنید. می‌توانید اطلاعات کاربر را از API OAuth 2.0 درخواست کنید.

پایتون

مستندات مربوط به API کشف OAuth 2.0 را مطالعه کنید. از آن برای دریافت یک شیء 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"))

جاوا

یک متد در کلاس سرویس ایجاد کنید که با استفاده از Credentials به عنوان پارامتر، یک شیء UserInfo می‌سازد.

/** 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() است، اما اگر مقادیر دیگری در session ذخیره شده باشد، ممکن است اثرات ناخواسته‌ای داشته باشد.

جاوا

در کنترلر، یک نقطه پایانی /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 ، مجوز برنامه شما را لغو کند. این درخواست باید حاوی توکن دسترسی کاربر باشد.

پایتون

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!")

جاوا

یک متد به کلاس سرویس اضافه کنید که نقطه پایانی لغو را فراخوانی کند.

/** 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 مشخص کرده‌اید، بارگذاری می‌کند.

تبریک! شما آماده‌اید تا به مرحله‌ی بعدی بروید: مدیریت بازدیدهای مکرر از افزونه‌تان .