Présentation
Objectif:ce document décrit les fonctions génériques OAuth 2.0 proposées par la bibliothèque cliente Google OAuth pour Java. Vous pouvez utiliser ces fonctions pour l'authentification et l'autorisation pour tout service Internet.
Pour obtenir des instructions sur l'utilisation de GoogleCredential
afin d'effectuer une autorisation OAuth 2.0 avec
Services Google, consultez
Utiliser OAuth 2.0 avec la bibliothèque cliente des API Google pour Java
Résumé:OAuth 2.0 est un spécification standard permettant aux utilisateurs finaux d'autoriser un client de façon sécurisée pour accéder aux ressources protégées côté serveur. En outre, Jeton de support OAuth 2.0 explique comment accéder à ces ressources protégées à l'aide d'une règle d'accès est accordé lors du processus d'autorisation de l'utilisateur final.
Pour en savoir plus, consultez la documentation Javadoc pour les packages suivants:
- com.google.api.client.auth.oauth2 (depuis google-oauth-client)
- com.google.api.client.extensions.servlet.auth.oauth2 (from google-oauth-client-servlet)
- com.google.api.client.extensions.appengine.auth.oauth2 (from google-oauth-client-appengine)
Enregistrement du client
Avant d'utiliser la bibliothèque cliente Google OAuth pour Java, vous devez probablement enregistrer votre application auprès d'un serveur d'autorisation afin de recevoir un identifiant client client secret. Pour obtenir des informations générales sur cette procédure, consultez la Client Spécification d'enregistrement.
Identifiants et magasin d'identifiants
Justificatif
est une classe d'assistance OAuth 2.0 thread-safe pour accéder aux ressources protégées à l'aide d'un
un jeton d'accès. Lorsque vous utilisez un jeton d'actualisation, Credential
actualise également l'accès
à l'expiration du jeton d'accès à l'aide du jeton d'actualisation. Par exemple, si vous
dispose déjà d'un jeton d'accès, vous pouvez effectuer une demande de la manière suivante:
public static HttpResponse executeGet( HttpTransport transport, JsonFactory jsonFactory, String accessToken, GenericUrl url) throws IOException { Credential credential = new Credential(BearerToken.authorizationHeaderAccessMethod()).setAccessToken(accessToken); HttpRequestFactory requestFactory = transport.createRequestFactory(credential); return requestFactory.buildGetRequest(url).execute(); }
La plupart des applications doivent conserver le jeton d'accès des identifiants et d'actualiser le jeton afin d'éviter une future redirection vers l'autorisation dans le navigateur. La CredentialStore implémentation de cette bibliothèque est obsolète et sera supprimée à l'avenir versions. Vous pouvez également utiliser la classe DataStoreFactory et DataStore interagit avec StoredCredential, qui sont fournies par Bibliothèque cliente HTTP Google pour Java.
Vous pouvez utiliser l'une des implémentations suivantes fournies par la bibliothèque:
- JdoDataStoreFactory conserve l'identifiant à l'aide de JPO.
- AppEngineDataStoreFactory conserve l'identifiant à l'aide de l'API Google App Engine Data Store.
- MemoryDataStoreFactory "persiste" les identifiants en mémoire, ce qui n'est utile que pour le stockage pendant toute la durée de vie du processus.
- FileDataStoreFactory conserve l'identifiant dans un fichier.
Utilisateurs de Google App Engine:
AppEngineCredentialStore est obsolète et est en cours de suppression.
Nous vous recommandons d'utiliser AppEngineDataStoreFactory avec StoredCredential. Si vous aviez des identifiants stockés dans l'ancienne méthode, vous pouvez utiliser les méthodes d'assistance ajoutées migrateTo(AppEngineDataStoreFactory) ou migrateTo(DataStore) à migrer.
Utiliser DataStoreCredentialRefreshListener et le définir pour l'identifiant à l'aide de GoogleCredential.Builder.addRefreshListener(CredentialRefreshListener).
Flux avec code d'autorisation
Utilisez le flux avec code d'autorisation pour permettre à l'utilisateur final d'accorder à votre application l'accès à leurs données protégées. Le protocole de ce flux est spécifié dans Spécification d'attribution de code d'autorisation
Ce flux est implémenté à l'aide de AuthorizationCodeFlow Voici la procédure à suivre :
- Un utilisateur final se connecte à votre application. Vous devez associer cet utilisateur un ID utilisateur propre à votre application.
- Appeler AuthorizationCodeFlow.loadCredential(String), en fonction de l'ID utilisateur, pour vérifier si les identifiants de l'utilisateur sont déjà connus. Si c'est le cas, vous avez terminé.
- Si ce n'est pas le cas, appelez AuthorizationCodeFlow.newAuthorizationUrl() et diriger le navigateur de l'utilisateur final vers une page d'autorisation lui permettant l'accès de votre application à leurs données protégées.
- Le navigateur Web effectue ensuite la redirection vers l'URL de redirection à l'aide d'un "code" requête qui peut ensuite être utilisé pour demander un jeton d'accès à l'aide de AuthorizationCodeFlow.newTokenRequest(String)
- Utilisez AuthorizationCodeFlow.createAndStoreCredential(TokenResponse, String) pour stocker et obtenir des identifiants permettant d'accéder aux ressources protégées.
Si vous n'utilisez pas AuthorizationCodeFlow, vous pouvez utiliser les classes de niveau inférieur:
- Utilisez DataStore.get(String). pour charger les identifiants à partir du magasin, en fonction de l'ID utilisateur.
- Utiliser AuthorizationCodeRequestUrl pour rediriger le navigateur vers la page d'autorisation.
- Utiliser AuthorizationCodeResponseUrl pour traiter la réponse d'autorisation et analyser le code d'autorisation.
- Utiliser AuthorizationCodeTokenRequest pour demander un jeton d'accès et éventuellement un jeton d'actualisation.
- Créez un Credential (Identifiant) et stockez-le à l'aide de DataStore.set(String, V).
- Accéder aux ressources protégées à l'aide de l'identifiant Les jetons d'accès expirés sont automatiquement actualisés à l'aide du jeton d'actualisation, si : applicables. Veillez à utiliser DataStoreCredentialRefreshListener et le définir pour l'identifiant à l'aide de Credential.Builder.addRefreshListener(CredentialRefreshListener).
Flux avec code d'autorisation des servlets
Cette bibliothèque fournit des classes d'assistance de servlet pour simplifier considérablement pour les cas d'utilisation de base. Il suffit de fournir des sous-classes concrètes de AbstractAuthorizationCodeServlet et AbstractAuthorizationCodeCallbackServlet (de google-oauth-client-servlet) et ajoutez-les à votre fichier web.xml. Notez que vous devez toujours vous occuper des utilisateurs pour votre application Web afin d'extraire un ID utilisateur.
Exemple de code :
public class ServletSample extends AbstractAuthorizationCodeServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { // do stuff } @Override protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException { GenericUrl url = new GenericUrl(req.getRequestURL().toString()); url.setRawPath("/oauth2callback"); return url.build(); } @Override protected AuthorizationCodeFlow initializeFlow() throws IOException { return new AuthorizationCodeFlow.Builder(BearerToken.authorizationHeaderAccessMethod(), new NetHttpTransport(), new JacksonFactory(), new GenericUrl("https://server.example.com/token"), new BasicAuthentication("s6BhdRkqt3", "7Fjfp0ZBr1KtDRbnfVdmIw"), "s6BhdRkqt3", "https://server.example.com/authorize").setCredentialDataStore( StoredCredential.getDefaultDataStore( new FileDataStoreFactory(new File("datastoredir")))) .build(); } @Override protected String getUserId(HttpServletRequest req) throws ServletException, IOException { // return user ID } } public class ServletCallbackSample extends AbstractAuthorizationCodeCallbackServlet { @Override protected void onSuccess(HttpServletRequest req, HttpServletResponse resp, Credential credential) throws ServletException, IOException { resp.sendRedirect("/"); } @Override protected void onError( HttpServletRequest req, HttpServletResponse resp, AuthorizationCodeResponseUrl errorResponse) throws ServletException, IOException { // handle error } @Override protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException { GenericUrl url = new GenericUrl(req.getRequestURL().toString()); url.setRawPath("/oauth2callback"); return url.build(); } @Override protected AuthorizationCodeFlow initializeFlow() throws IOException { return new AuthorizationCodeFlow.Builder(BearerToken.authorizationHeaderAccessMethod(), new NetHttpTransport(), new JacksonFactory(), new GenericUrl("https://server.example.com/token"), new BasicAuthentication("s6BhdRkqt3", "7Fjfp0ZBr1KtDRbnfVdmIw"), "s6BhdRkqt3", "https://server.example.com/authorize").setCredentialDataStore( StoredCredential.getDefaultDataStore( new FileDataStoreFactory(new File("datastoredir")))) .build(); } @Override protected String getUserId(HttpServletRequest req) throws ServletException, IOException { // return user ID } }
Flux avec code d'autorisation Google App Engine
Le flux du code d'autorisation sur App Engine est presque identique au servlet. de code d'autorisation, sauf que nous pouvons exploiter API Java Users L'utilisateur doit être connecté pour activer l'API Java Users. pour des informations sur la redirection des utilisateurs vers une page de connexion, s'ils ne l'ont pas déjà fait. connecté, consultez la page Sécurité et authentification (dans web.xml).
La principale différence par rapport au cas des servlets est que vous fournissez des
sous-classes de
AbstractAppEngineAuthorizationCodeServlet et AbstractAppEngineAuthorizationCodeCallbackServlet (de google-oauth-client-appengine). Ils étendent les classes de servlet abstraites et implémentent la méthode getUserId
à votre place à l'aide de l'API Users Java. AppEngineDataStoreFactory (de la bibliothèque cliente HTTP Google pour Java est une bonne option pour conserver les identifiants à l'aide de l'API Google App Engine Data Store).
Exemple de code :
public class AppEngineSample extends AbstractAppEngineAuthorizationCodeServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { // do stuff } @Override protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException { GenericUrl url = new GenericUrl(req.getRequestURL().toString()); url.setRawPath("/oauth2callback"); return url.build(); } @Override protected AuthorizationCodeFlow initializeFlow() throws IOException { return new AuthorizationCodeFlow.Builder(BearerToken.authorizationHeaderAccessMethod(), new UrlFetchTransport(), new JacksonFactory(), new GenericUrl("https://server.example.com/token"), new BasicAuthentication("s6BhdRkqt3", "7Fjfp0ZBr1KtDRbnfVdmIw"), "s6BhdRkqt3", "https://server.example.com/authorize").setCredentialStore( StoredCredential.getDefaultDataStore(AppEngineDataStoreFactory.getDefaultInstance())) .build(); } } public class AppEngineCallbackSample extends AbstractAppEngineAuthorizationCodeCallbackServlet { @Override protected void onSuccess(HttpServletRequest req, HttpServletResponse resp, Credential credential) throws ServletException, IOException { resp.sendRedirect("/"); } @Override protected void onError( HttpServletRequest req, HttpServletResponse resp, AuthorizationCodeResponseUrl errorResponse) throws ServletException, IOException { // handle error } @Override protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException { GenericUrl url = new GenericUrl(req.getRequestURL().toString()); url.setRawPath("/oauth2callback"); return url.build(); } @Override protected AuthorizationCodeFlow initializeFlow() throws IOException { return new AuthorizationCodeFlow.Builder(BearerToken.authorizationHeaderAccessMethod(), new UrlFetchTransport(), new JacksonFactory(), new GenericUrl("https://server.example.com/token"), new BasicAuthentication("s6BhdRkqt3", "7Fjfp0ZBr1KtDRbnfVdmIw"), "s6BhdRkqt3", "https://server.example.com/authorize").setCredentialStore( StoredCredential.getDefaultDataStore(AppEngineDataStoreFactory.getDefaultInstance())) .build(); } }
Flux avec code d'autorisation en ligne de commande
Exemple de code simplifié issu de dailymotion-cmdline-sample:
/** Authorizes the installed application to access user's protected data. */ private static Credential authorize() throws Exception { OAuth2ClientCredentials.errorIfNotSpecified(); // set up authorization code flow AuthorizationCodeFlow flow = new AuthorizationCodeFlow.Builder(BearerToken .authorizationHeaderAccessMethod(), HTTP_TRANSPORT, JSON_FACTORY, new GenericUrl(TOKEN_SERVER_URL), new ClientParametersAuthentication( OAuth2ClientCredentials.API_KEY, OAuth2ClientCredentials.API_SECRET), OAuth2ClientCredentials.API_KEY, AUTHORIZATION_SERVER_URL).setScopes(Arrays.asList(SCOPE)) .setDataStoreFactory(DATA_STORE_FACTORY).build(); // authorize LocalServerReceiver receiver = new LocalServerReceiver.Builder().setHost( OAuth2ClientCredentials.DOMAIN).setPort(OAuth2ClientCredentials.PORT).build(); return new AuthorizationCodeInstalledApp(flow, receiver).authorize("user"); } private static void run(HttpRequestFactory requestFactory) throws IOException { DailyMotionUrl url = new DailyMotionUrl("https://api.dailymotion.com/videos/favorites"); url.setFields("id,tags,title,url"); HttpRequest request = requestFactory.buildGetRequest(url); VideoFeed videoFeed = request.execute().parseAs(VideoFeed.class); ... } public static void main(String[] args) { ... DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR); final Credential credential = authorize(); HttpRequestFactory requestFactory = HTTP_TRANSPORT.createRequestFactory(new HttpRequestInitializer() { @Override public void initialize(HttpRequest request) throws IOException { credential.initialize(request); request.setParser(new JsonObjectParser(JSON_FACTORY)); } }); run(requestFactory); ... }
Flux client basé sur le navigateur
Voici les étapes typiques du flux client basé sur le navigateur spécifié dans Spécification d'octroi implicite:
- Avec BrowserClientRequestUrl, rediriger le navigateur de l'utilisateur final vers la page d'autorisation où il peut d'autoriser votre application à accéder à ses données protégées.
- Utiliser une application JavaScript pour traiter le jeton d'accès trouvé dans l'URL fragment à l'URI de redirection enregistrée auprès du serveur d'autorisation.
Exemple d'utilisation pour une application Web:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { String url = new BrowserClientRequestUrl( "https://server.example.com/authorize", "s6BhdRkqt3").setState("xyz") .setRedirectUri("https://client.example.com/cb").build(); response.sendRedirect(url); }
Détecter un jeton d'accès expiré
Conformément à la spécification de support OAuth 2.0,
Lorsque le serveur est appelé pour accéder à une ressource protégée dont l'accès a expiré
le serveur répond généralement par un code d'état HTTP 401 Unauthorized
par exemple:
HTTP/1.1 401 Unauthorized WWW-Authenticate: Bearer realm="example", error="invalid_token", error_description="The access token expired"
Cependant, la spécification semble offrir une grande flexibilité. Pour consultez la documentation du fournisseur OAuth 2.0.
Une autre approche consiste à vérifier le paramètre expires_in
dans la
réponse de jeton d'accès.
Cela spécifie la durée de vie en secondes du jeton d'accès accordé, qui est
généralement une heure. Toutefois, il est possible que le jeton d'accès n'expire pas
de cette période, et le serveur peut
continuer à autoriser l'accès. C'est pourquoi nous
recommandent généralement d'attendre un code d'état 401 Unauthorized
, plutôt que
en supposant que le jeton a expiré
compte tenu du temps écoulé. Vous pouvez également
essayer d'actualiser un jeton d'accès peu de temps avant son expiration. Si le serveur de jetons
n'est pas disponible, continuez à utiliser le jeton d'accès jusqu'à ce que vous receviez une 401
. Ce
est la stratégie utilisée par défaut
Identifiant :
Vous pouvez aussi récupérer un nouveau jeton d'accès avant chaque requête, nécessite une requête HTTP supplémentaire au serveur de jetons à chaque fois. Il est donc probable un mauvais choix en termes de vitesse et d’utilisation du réseau. Idéalement, stockez le jeton d'accès dans un espace de stockage persistant et sécurisé, afin de limiter les demandes de nouvel accès d'une application. de jetons. (Mais pour les applications installées, le stockage sécurisé est un problème difficile.)
Notez qu'un jeton d'accès peut devenir non valide pour d'autres raisons que l'expiration, Par exemple, si l'utilisateur a explicitement révoqué le jeton, assurez-vous que votre code de gestion des erreurs est robuste. Une fois que vous avez détecté qu'un jeton n'est plus valide, par exemple s'il a expiré ou a été révoqué, vous devez supprimer l'accès de votre espace de stockage. Sur Android, par exemple, vous devez appeler AccountManager.invalidateAuthToken