Pour utiliser les services Google au nom d'un utilisateur lorsqu'il est hors connexion, vous devez utiliser un flux hybride côté serveur, dans lequel un utilisateur autorise votre application côté client à l'aide du client de l'API JavaScript, et vous envoyez un code d'autorisation à usage unique spécial à votre serveur. Votre serveur échange ce code à usage unique pour acquérir ses propres jetons d'accès et d'actualisation auprès de Google afin qu'il puisse effectuer ses propres appels d'API, ce qui peut être fait lorsque l'utilisateur est hors connexion. Ce flux de code à usage unique présente des avantages de sécurité par rapport à un flux côté serveur pur et à l'envoi de jetons d'accès à votre serveur.
Le flux de connexion permettant d'obtenir un jeton d'accès pour votre application côté serveur est illustré ci-dessous.
Les codes à usage unique présentent plusieurs avantages en termes de sécurité. Avec les codes, Google fournit des jetons directement à votre serveur sans intermédiaire. Bien que nous ne recommandions pas de divulguer des codes, ils sont très difficiles à utiliser sans votre secret client. Gardez votre code secret secret !
Implémenter le flux de code à usage unique
Le bouton Google Sign-In fournit à la fois un jeton d'accès et un code d'autorisation. Il s'agit d'un code à usage unique que votre serveur peut échanger avec les serveurs de Google contre un jeton d'accès.
L'exemple de code suivant montre comment effectuer le flux de code à usage unique.
Pour authentifier la connexion Google avec le flux de code à usage unique, vous devez:
Étape 1: Créer un ID client et un code secret client
Pour créer un ID client et un secret client, créez un projet dans la console Google APIs, configurez un ID client OAuth et enregistrez vos origines JavaScript:
Accédez à la console Google APIs.
Dans le menu déroulant des projets, sélectionnez un projet existant ou créez-en un en sélectionnant Créer un projet.
Dans la barre latérale, sous "API et services", sélectionnez Identifiants, puis cliquez sur Configurer l'écran d'autorisation.
Choisissez une adresse e-mail, indiquez un nom de produit, puis appuyez sur Enregistrer.
Dans l'onglet Credentials (Identifiants), sélectionnez la liste déroulante Create credentials (Créer des identifiants) et choisissez OAuth client ID (ID client OAuth).
Sous Type d'application, sélectionnez Application Web.
Enregistrez les origines à partir desquelles votre application est autorisée à accéder aux API Google, comme suit. Une origine est une combinaison unique de protocole, de nom d'hôte et de port.
Dans le champ Origines JavaScript autorisées, saisissez l'origine de votre application. Vous pouvez saisir plusieurs origines pour permettre à votre application de s'exécuter sur différents protocoles, domaines ou sous-domaines. Vous ne pouvez pas utiliser de caractères génériques. Dans l'exemple ci-dessous, la deuxième URL peut être une URL de production.
http://localhost:8080 https://myproductionurl.example.com
Le champ URI de redirection autorisé ne nécessite pas de valeur. Les URI de redirection ne sont pas utilisés avec les API JavaScript.
Appuyez sur le bouton Créer.
Dans la boîte de dialogue OAuth client (Client OAuth) qui s'affiche, copiez l'ID client. L'ID client permet à votre application d'accéder aux API Google activées.
Étape 2: Incluez la bibliothèque de la plate-forme Google sur votre page
Incluez les scripts suivants qui illustrent une fonction anonyme qui insère un script dans le DOM de cette page Web index.html
.
<!-- The top of file index.html -->
<html itemscope itemtype="http://schema.org/Article">
<head>
<!-- BEGIN Pre-requisites -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js">
</script>
<script src="https://apis.google.com/js/client:platform.js?onload=start" async defer>
</script>
<!-- END Pre-requisites -->
Étape 3: Initialisez l'objet GoogleAuth
Chargez la bibliothèque auth2 et appelez gapi.auth2.init()
pour initialiser l'objet GoogleAuth
. Spécifiez votre ID client et les portées que vous souhaitez demander lorsque vous appelez init()
.
<!-- Continuing the <head> section -->
<script>
function start() {
gapi.load('auth2', function() {
auth2 = gapi.auth2.init({
client_id: 'YOUR_CLIENT_ID.apps.googleusercontent.com',
// Scopes to request in addition to 'profile' and 'email'
//scope: 'additional_scope'
});
});
}
</script>
</head>
<body>
<!-- ... -->
</body>
</html>
Étape 4: Ajoutez le bouton de connexion à votre page
Ajoutez le bouton de connexion à votre page Web et joignez un gestionnaire de clics pour appeler grantOfflineAccess()
afin de démarrer le flux de code à usage unique.
<!-- Add where you want your sign-in button to render -->
<!-- Use an image that follows the branding guidelines in a real app -->
<button id="signinButton">Sign in with Google</button>
<script>
$('#signinButton').click(function() {
// signInCallback defined in step 6.
auth2.grantOfflineAccess().then(signInCallback);
});
</script>
Étape 5: Connectez l'utilisateur
L'utilisateur clique sur le bouton de connexion et accorde à votre application l'accès aux autorisations que vous avez demandées. Ensuite, la fonction de rappel que vous avez spécifiée dans la méthode grantOfflineAccess().then()
reçoit un objet JSON avec un code d'autorisation. Exemple :
{"code":"4/yU4cQZTMnnMtetyFcIWNItG32eKxxxgXXX-Z4yyJJJo.4qHskT-UtugceFc0ZRONyF4z7U4UmAI"}
Étape 6: Envoyer le code d'autorisation au serveur
code
est votre code à usage unique que votre serveur peut échanger contre son propre jeton d'accès et son propre jeton d'actualisation. Vous ne pouvez obtenir un jeton d'actualisation qu'après avoir présenté à l'utilisateur une boîte de dialogue d'autorisation demandant un accès hors connexion.
Si vous avez spécifié le prompt
select-account
dans OfflineAccessOptions
à l'étape 4, vous devez stocker le jeton d'actualisation que vous récupérez pour une utilisation ultérieure, car les échanges ultérieurs renvoient null
pour le jeton d'actualisation. Ce flux offre une sécurité accrue par rapport à votre flux OAuth 2.0 standard.
Les jetons d'accès sont toujours renvoyés lors de l'échange d'un code d'autorisation valide.
Le script suivant définit une fonction de rappel pour le bouton de connexion. Lorsqu'une connexion aboutit, la fonction stocke le jeton d'accès pour une utilisation côté client et envoie le code à usage unique à votre serveur sur le même domaine.
<!-- Last part of BODY element in file index.html -->
<script>
function signInCallback(authResult) {
if (authResult['code']) {
// Hide the sign-in button now that the user is authorized, for example:
$('#signinButton').attr('style', 'display: none');
// Send the code to the server
$.ajax({
type: 'POST',
url: 'http://example.com/storeauthcode',
// Always include an `X-Requested-With` header in every AJAX request,
// to protect against CSRF attacks.
headers: {
'X-Requested-With': 'XMLHttpRequest'
},
contentType: 'application/octet-stream; charset=utf-8',
success: function(result) {
// Handle or verify the server response.
},
processData: false,
data: authResult['code']
});
} else {
// There was an error.
}
}
</script>
Étape 7: Échangez le code d'autorisation contre un jeton d'accès
Sur le serveur, échangez le code d'autorisation contre des jetons d'accès et d'actualisation. Utilisez le jeton d'accès pour appeler les API Google au nom de l'utilisateur et, éventuellement, stockez le jeton d'actualisation pour acquérir un nouveau jeton d'accès lorsque le jeton existant expirera.
Si vous avez demandé l'accès au profil, vous recevez également un jeton d'ID contenant des informations de profil de base pour l'utilisateur.
Exemple :
Java
// (Receive authCode via HTTPS POST) if (request.getHeader("X-Requested-With") == null) { // Without the `X-Requested-With` header, this request could be forged. Aborts. } // Set path to the Web application client_secret_*.json file you downloaded from the // Google API Console: https://console.cloud.google.com/apis/credentials // You can also find your Web application client ID and client secret from the // console and specify them directly when you create the GoogleAuthorizationCodeTokenRequest // object. String CLIENT_SECRET_FILE = "/path/to/client_secret.json"; // Exchange auth code for access token GoogleClientSecrets clientSecrets = GoogleClientSecrets.load( JacksonFactory.getDefaultInstance(), new FileReader(CLIENT_SECRET_FILE)); GoogleTokenResponse tokenResponse = new GoogleAuthorizationCodeTokenRequest( new NetHttpTransport(), JacksonFactory.getDefaultInstance(), "https://oauth2.googleapis.com/token", clientSecrets.getDetails().getClientId(), clientSecrets.getDetails().getClientSecret(), authCode, REDIRECT_URI) // Specify the same redirect URI that you use with your web // app. If you don't have a web version of your app, you can // specify an empty string. .execute(); String accessToken = tokenResponse.getAccessToken(); // Use access token to call API GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken); Drive drive = new Drive.Builder(new NetHttpTransport(), JacksonFactory.getDefaultInstance(), credential) .setApplicationName("Auth Code Exchange Demo") .build(); File file = drive.files().get("appfolder").execute(); // Get profile info from ID token GoogleIdToken idToken = tokenResponse.parseIdToken(); GoogleIdToken.Payload payload = idToken.getPayload(); String userId = payload.getSubject(); // Use this value as a key to identify a user. String email = payload.getEmail(); boolean emailVerified = Boolean.valueOf(payload.getEmailVerified()); String name = (String) payload.get("name"); String pictureUrl = (String) payload.get("picture"); String locale = (String) payload.get("locale"); String familyName = (String) payload.get("family_name"); String givenName = (String) payload.get("given_name");
Python
from apiclient import discovery import httplib2 from oauth2client import client # (Receive auth_code by HTTPS POST) # If this request does not have `X-Requested-With` header, this could be a CSRF if not request.headers.get('X-Requested-With'): abort(403) # Set path to the Web application client_secret_*.json file you downloaded from the # Google API Console: https://console.cloud.google.com/apis/credentials CLIENT_SECRET_FILE = '/path/to/client_secret.json' # Exchange auth code for access token, refresh token, and ID token credentials = client.credentials_from_clientsecrets_and_code( CLIENT_SECRET_FILE, ['https://www.googleapis.com/auth/drive.appdata', 'profile', 'email'], auth_code) # Call Google API http_auth = credentials.authorize(httplib2.Http()) drive_service = discovery.build('drive', 'v3', http=http_auth) appfolder = drive_service.files().get(fileId='appfolder').execute() # Get profile info from ID token userid = credentials.id_token['sub'] email = credentials.id_token['email']