Nutzer anmelden

Dies ist die zweite Schritt-für-Schritt-Anleitung für die Classroom-Add-ons-Serie.

In dieser Schritt-für-Schritt-Anleitung fügen Sie der Webanwendung Google Log-in hinzu. Dies ist eine Voraussetzung für Classroom-Add-ons. Verwenden Sie die Anmeldedaten aus diesem Autorisierungsablauf für alle zukünftigen API-Aufrufe.

Im Verlauf dieser Schritt-für-Schritt-Anleitung führen Sie Folgendes aus:

  • Konfigurieren Sie Ihre Webanwendung so, dass Sitzungsdaten in einem iFrame aufbewahrt werden.
  • Server-zu-Server-Anmeldevorgang von Google OAuth 2.0 implementieren
  • Rufen Sie die OAuth 2.0 API auf.
  • Erstellen Sie zusätzliche Routen, um API-Aufrufe zu autorisieren, abzumelden und zu testen.

Anschließend können Sie Nutzer in Ihrer Webanwendung vollständig autorisieren und Google APIs aufrufen.

Informationen zum Autorisierungsablauf

Google APIs verwenden zur Authentifizierung und Autorisierung das OAuth 2.0-Protokoll. Die vollständige Beschreibung der OAuth-Implementierung von Google finden Sie im OAuth-Leitfaden für Google Identity.

Die Anmeldedaten Ihrer Anwendung werden in Google Cloud verwaltet. Sobald diese erstellt wurden, implementieren Sie einen vierstufigen Prozess zur Authentifizierung und Autorisierung eines Nutzers:

  1. Fordern Sie die Autorisierung an. Geben Sie als Teil dieser Anfrage eine Callback-URL an. Sobald der Vorgang abgeschlossen ist, erhalten Sie eine Autorisierungs-URL.
  2. Leiten Sie den Nutzer an die Autorisierungs-URL weiter. Auf der daraufhin angezeigten Seite wird der Nutzer über die für Ihre App erforderlichen Berechtigungen informiert und aufgefordert, den Zugriff zu erlauben. Wenn der Vorgang abgeschlossen ist, wird der Nutzer zur Callback-URL weitergeleitet.
  3. Sie erhalten einen Autorisierungscode auf Ihrer Callback-Route. Tauschen Sie den Autorisierungscode gegen ein Zugriffstoken und ein Aktualisierungstoken aus.
  4. Rufen Sie mit den Tokens eine Google API auf.

OAuth 2.0-Anmeldedaten abrufen

Prüfen Sie, ob Sie OAuth-Anmeldedaten erstellt und heruntergeladen haben, wie auf der Übersichtsseite beschrieben. Ihr Projekt muss diese Anmeldedaten verwenden, um den Nutzer anzumelden.

Autorisierungsvorgang implementieren

Fügen Sie unserer Webanwendung Logik und Routen hinzu, um den oben beschriebenen Ablauf zu realisieren, einschließlich der folgenden Funktionen:

  • Initiieren Sie den Autorisierungsvorgang, sobald Sie die Landingpage erreichen.
  • Fordern Sie die Autorisierung an und verarbeiten Sie die Antwort des Autorisierungsservers.
  • Löschen Sie die gespeicherten Anmeldedaten.
  • Widerrufen Sie die Berechtigungen der App.
  • Testen Sie einen API-Aufruf.

Autorisierung einleiten

Passen Sie bei Bedarf die Landingpage so an, dass der Autorisierungsvorgang gestartet wird. Das Add-on kann zwei Status haben: Entweder befinden sich in der aktuellen Sitzung gespeicherte Tokens oder Sie müssen Tokens vom OAuth 2.0-Server abrufen. Führe einen Test-API-Aufruf aus, wenn Tokens in der Sitzung vorhanden sind, oder fordert den Nutzer anderweitig zur Anmeldung auf.

Python

Öffnen Sie Ihre routes.py-Datei. Legen Sie zuerst einige Konstanten und unsere Cookie-Konfiguration gemäß den iFrame-Sicherheitsempfehlungen fest.

# 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",
)

Gehen Sie zur Add-on-Zielroute (in der Beispieldatei ist das /classroom-addon). Fügen Sie eine Logik zum Rendern einer Anmeldeseite hinzu, wenn die Sitzung nicht den Schlüssel „Anmeldedaten“ enthält.

@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

Den Code für diese Schritt-für-Schritt-Anleitung finden Sie im step_02_sign_in-Modul.

Öffnen Sie die Datei application.properties und fügen Sie eine Sitzungskonfiguration gemäß den iFrame-Sicherheitsempfehlungen hinzu.

# 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

Erstellen Sie eine Dienstklasse (AuthService.java im Modul step_02_sign_in), um die Logik hinter den Endpunkten in der Controller-Datei zu verwalten, und richten Sie den Weiterleitungs-URI, den Speicherort der Clientschlüssel-Datei und die für Ihr Add-on erforderlichen Bereiche ein. Der Weiterleitungs-URI wird verwendet, um Nutzer zu einem bestimmten URI weiterzuleiten, nachdem sie Ihre Anwendung autorisiert haben. Im Abschnitt zum Einrichten des Projekts unter README.md im Quellcode erfahren Sie, wo Sie die Datei client_secret.json platzieren müssen.

@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));
    }
}

Öffnen Sie die Controller-Datei (AuthController.java im Modul step_02_sign_in) und fügen Sie der Landingpage Logik hinzu, um die Anmeldeseite zu rendern, wenn die Sitzung nicht den Schlüssel credentials enthält.

@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);
    }
}

Die Autorisierungsseite sollte einen Link oder eine Schaltfläche enthalten, über die sich der Nutzer anmelden kann. Wenn Sie diese Option anklicken, sollte der Nutzer zur authorize-Route weitergeleitet werden.

Autorisierung anfordern

Wenn du die Autorisierung anfordern möchtest, erstelle eine Authentifizierungs-URL und leite den Nutzer an diese weiter. Diese URL enthält verschiedene Informationen wie die angeforderten Bereiche, die Zielroute für nach der Autorisierung und die Client-ID der Webanwendung. Sie können sich diese in dieser Beispiel-Autorisierungs-URL ansehen.

Python

Fügen Sie der Datei routes.py den folgenden Import hinzu.

import google_auth_oauthlib.flow

Neue Route erstellen: /authorize. Erstellen Sie eine Instanz von google_auth_oauthlib.flow.Flow. Wir empfehlen dringend, dafür die enthaltene Methode from_client_secrets_file zu verwenden.

@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)

Legen Sie den redirect_uri von flow fest. Dies ist die Route, zu der Nutzer nach der Autorisierung Ihrer Anwendung zurückkehren sollen. Im folgenden Beispiel ist das /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)

Verwenden Sie das Ablaufobjekt, um authorization_url und state zu erstellen. Speichern Sie state in der Sitzung. Damit wird später die Authentizität der Serverantwort überprüft. Leite den Nutzer schließlich zu authorization_url weiter.

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

Fügen Sie der Datei AuthService.java die folgenden Methoden hinzu, um das Ablaufobjekt zu instanziieren, und verwenden Sie es dann, um die Autorisierungs-URL abzurufen:

  • Die Methode getClientSecrets() liest die Clientschlüsseldatei und erstellt ein GoogleClientSecrets-Objekt.
  • Mit der Methode getFlow() wird eine Instanz von GoogleAuthorizationCodeFlow erstellt.
  • Die Methode authorize() verwendet das GoogleAuthorizationCodeFlow-Objekt, den Parameter state und den Weiterleitungs-URI, um die Autorisierungs-URL abzurufen. Der Parameter state wird verwendet, um die Authentizität der Antwort vom Autorisierungsserver zu prüfen. Die Methode gibt dann eine Karte mit der Autorisierungs-URL und dem Parameter state zurück.
/** 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;
    }
}

Verwenden Sie die Konstruktor-Einschleusung, um eine Instanz der Dienstklasse in der Controller-Klasse zu erstellen.

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

Fügen Sie der Controller-Klasse den Endpunkt /authorize hinzu. Dieser Endpunkt ruft die AuthService-Methode authorize() auf, um den Parameter state und die Autorisierungs-URL abzurufen. Der Endpunkt speichert dann den Parameter state in der Sitzung und leitet die Nutzer an die Autorisierungs-URL weiter.

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

Serverantwort verarbeiten

Nach der Autorisierung kehrt der Nutzer zur Route redirect_uri aus dem vorherigen Schritt zurück. Im Beispiel oben ist dies /callback.

Sie erhalten code in der Antwort, wenn der Nutzer von der Autorisierungsseite zurückkehrt. Tauschen Sie dann den Code gegen Zugriffs- und Aktualisierungstokens ein:

Python

Fügen Sie der Prometheus-Serverdatei die folgenden Importe hinzu.

import google.oauth2.credentials
import googleapiclient.discovery

Fügen Sie die Route Ihrem Server hinzu. Erstellen Sie eine weitere Instanz von google_auth_oauthlib.flow.Flow, aber verwenden Sie diesmal den im vorherigen Schritt gespeicherten Status.

@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)

Als Nächstes fordern Sie Zugriffs- und Aktualisierungstoken an. Glücklicherweise enthält das flow-Objekt dazu auch die Methode fetch_token. Die Methode erwartet entweder das Argument code oder authorization_response. Verwenden Sie authorization_response, da es sich um die vollständige URL der Anfrage handelt.

authorization_response = flask.request.url
flow.fetch_token(authorization_response=authorization_response)

Sie haben jetzt vollständige Anmeldedaten. Speichern Sie sie in der Sitzung, damit sie mit anderen Methoden oder Routen abgerufen werden können, und leiten Sie sie dann auf eine Add-on-Landingpage weiter.

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

Fügen Sie Ihrer Dienstklasse eine Methode hinzu, die das Credentials-Objekt zurückgibt. Dazu übergeben Sie den Autorisierungscode, der aus der Weiterleitung abgerufen wurde, die von der Autorisierungs-URL ausgeführt wird. Dieses Credentials-Objekt wird später verwendet, um das Zugriffstoken und das Aktualisierungstoken abzurufen.

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

Fügen Sie dem Controller einen Endpunkt für den Weiterleitungs-URI hinzu. Rufen Sie den Autorisierungscode und den Parameter state aus der Anfrage ab. Vergleichen Sie diesen state-Parameter mit dem in der Sitzung gespeicherten Attribut state. Wenn sie übereinstimmen, fahren Sie mit dem Autorisierungsvorgang fort. Wenn sie nicht übereinstimmen, wird ein Fehler zurückgegeben.

Rufen Sie dann die Methode AuthService getAndSaveCredentials auf und übergeben Sie den Autorisierungscode als Parameter. Speichern Sie das Credentials-Objekt nach dem Abrufen in der Sitzung. Schließen Sie dann das Dialogfeld und leiten Sie den Nutzer zur Add-on-Landingpage weiter.

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

Wenn der Vorgang abgeschlossen ist, können Sie jetzt Aufrufe an Google APIs senden.

Fordere beispielsweise die Profilinformationen des Nutzers an. Sie können die Nutzerdaten über die OAuth 2.0 API anfordern.

Python

Lesen Sie die Dokumentation zur OAuth 2.0 Discovery API. Damit können Sie ein ausgefülltes UserInfo-Objekt abrufen.

# 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

Erstellen Sie eine Methode in der Dienstklasse, mit der ein UserInfo-Objekt erstellt wird. Verwenden Sie dabei Credentials als Parameter.

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

Fügen Sie dem Controller, auf dem die E-Mail-Adresse des Nutzers angezeigt wird, den Endpunkt /test hinzu.

/** 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);
    }
}

Anmeldedaten löschen

Sie können die Anmeldedaten eines Nutzers „löschen“, indem Sie ihn aus der aktuellen Sitzung entfernen. So können Sie das Routing auf der Add-on-Landingpage testen.

Es empfiehlt sich, einen Hinweis anzuzeigen, dass sich der Nutzer abgemeldet hat, bevor er zur Landingpage des Add-ons weitergeleitet wird. Ihre Anwendung muss den Autorisierungsvorgang durchlaufen, um neue Anmeldedaten zu erhalten. Nutzer werden jedoch nicht aufgefordert, die App noch einmal zu autorisieren.

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

Alternativ können Sie flask.session.clear() verwenden. Dies kann jedoch unbeabsichtigte Auswirkungen haben, wenn Sie andere Werte in der Sitzung gespeichert haben.

Java

Fügen Sie im Controller einen /clear-Endpunkt hinzu.

/** 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);
    }
}

Berechtigung der App widerrufen

Ein Nutzer kann die Berechtigung deiner App widerrufen, indem er eine POST-Anfrage an https://oauth2.googleapis.com/revoke sendet. Die Anfrage sollte das Zugriffstoken des Nutzers enthalten.

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

Fügen Sie der Dienstklasse eine Methode hinzu, die einen Aufruf an den Widerrufsendpunkt ausführt.

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

Fügen Sie dem Controller den Endpunkt /revoke hinzu, der die Sitzung löscht und den Nutzer bei einem erfolgreichen Widerruf zur Autorisierungsseite weiterleitet.

/** 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);
    }
}

Add-on testen

Melden Sie sich als einer Ihrer Teacher-Testnutzer in Google Classroom an. Gehen Sie zum Tab Kursaufgaben und erstellen Sie eine neue Aufgabe. Klicken Sie unter dem Textbereich auf die Schaltfläche Add-ons und wählen Sie das Add-on aus. Der iFrame wird geöffnet und das Add-on lädt den URI für die Anhangeinrichtung, den Sie im GWM SDK auf der Seite App-Konfiguration angegeben haben.

Das wars! Sie können nun mit dem nächsten Schritt fortfahren: Wiederholte Besuche des Add-ons verarbeiten.