نظرة عامة
الغرض: يشرح هذا المستند كيفية استخدام GoogleCredential فئة خدمات Google لإجراء تفويض OAuth 2.0 مع خدمات Google. بالنسبة معلومات حول دوال OAuth 2.0 العامة التي نقدمها، راجع OAuth 2.0 ومكتبة عميل OAuth من Google للغة Java
ملخص: للوصول إلى البيانات المحمية المخزَّنة على خدمات Google، استخدِم OAuth 2.0 للتفويض. تتيح Google APIs تدفقات OAuth 2.0 لأنواع مختلفة من تطبيقات العميل. وفي جميع هذه التدفقات، يطلب تطبيق العميل رمز دخول المرتبطة بتطبيق العميل فقط ومالك البيانات المحمية الوصول إليه. يرتبط رمز الدخول أيضًا بنطاق محدود نوع البيانات التي يمكن لتطبيق العميل الوصول إليها (على سبيل المثال "إدارة مهامك"). أحد الأهداف المهمة لـ OAuth 2.0 هو توفير الأمان وصول مريح إلى البيانات المحمية، مع تقليل التأثير المحتمل في حالة سرقة رمز الدخول.
تم تضمين حزم OAuth 2.0 في مكتبة برامج Google API للغة Java. والغرض العام مكتبة برامج Google OAuth 2.0 للغة Java.
للحصول على التفاصيل، اطلع على وثائق Javadoc للحزم التالية:
- com.google.api.client.googleapis.auth.oauth2 (من google-api-client)
- com.google.api.client.googleapis.extensions.appengine.auth.oauth2 (من google-api-client-appengine)
وحدة تحكّم Google API
قبل أن تتمكن من الوصول إلى Google APIs، يجب إعداد مشروع على وحدة التحكم في واجهة Google API للمصادقة والفوترة سواءً كان العميل عبارة عن تطبيق مثبّت أو تطبيق للأجهزة الجوّالة أو خادم ويب أو برنامج يعمل في المتصفح.
للحصول على تعليمات حول إعداد بيانات الاعتماد بشكل صحيح، يُرجى الاطّلاع على مساعدة وحدة تحكُّم واجهة برمجة التطبيقات
بيانات الاعتماد
GoogleCredential
GoogleCredential هي فئة مساعدة آمنة سلسلة التعليمات لـ OAuth 2.0 للوصول إلى الموارد المحمية باستخدام رمز الدخول. على سبيل المثال، إذا كان لديك رمز الدخول من قبل، تقديم طلب بالطريقة التالية:
GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken); Plus plus = new Plus.builder(new NetHttpTransport(), GsonFactory.getDefaultInstance(), credential) .setApplicationName("Google-PlusSample/1.0") .build();
هوية Google App Engine
تعتمد بيانات الاعتماد البديلة هذه على واجهة برمجة تطبيقات هوية تطبيقات Google App Engine. على عكس بيانات الاعتماد التي يطلب فيها أحد تطبيقات العميل الدخول إلى بيانات المستخدم النهائي، توفر واجهة برمجة تطبيقات هوية التطبيق إمكانية الوصول إلى بيانات العميل البيانات الخاصة بالتطبيق.
استخدام AppIdentityCredential (من google-api-client-appengine). وهذا الاعتماد هو أبسط بكثير لأن Google App Engine يهتم بجميع التفاصيل. يمكنك فقط تحديد نطاق OAuth 2.0 الذي تحتاجه.
مثال على رمز مأخوذ من urlshortener-robots-appengine-sample:
static Urlshortener newUrlshortener() { AppIdentityCredential credential = new AppIdentityCredential( Collections.singletonList(UrlshortenerScopes.URLSHORTENER)); return new Urlshortener.Builder(new UrlFetchTransport(), GsonFactory.getDefaultInstance(), credential) .build(); }
مخزن البيانات
عادةً ما يكون لرمز الدخول تاريخ انتهاء صلاحية يبلغ ساعة واحدة، وبعد ذلك يجب
ستظهر لك رسالة خطأ إذا حاولت استخدامها.
GoogleCredential
تعتني "بتحديث" الرمز، وهو ما يعني ببساطة الحصول على
رمز دخول جديد. ويتم ذلك عن طريق رمز مميز للتحديث طويل الأمد،
عادةً مع رمز الدخول إذا كنت تستخدم
معلَمة access_type=offline
أثناء مسار رمز التفويض (يُرجى الاطّلاع على
GoogleAuthorizationCodeFlow.Builder.setAccessType(String)).
ستحتاج معظم التطبيقات إلى الاحتفاظ برمز الدخول إلى بيانات الاعتماد و/أو الرمز المميز لإعادة التحميل. للاحتفاظ برموز الدخول و/أو إعادة تحميل بيانات الاعتماد، يمكنك تقديم التنفيذ الخاص بك لمنتج DataStoreFactory مع StoredCredential أو يمكنك استخدام أحد الإجراءات التالية التي توفّرها المكتبة:
- AppEngineDataStoreFactory: بيانات الاعتماد باستخدام واجهة برمجة التطبيقات Google App Engine Data Store API.
- MemoryDataStoreFactory: "المستمرة" بيانات الاعتماد في الذاكرة، والتي تكون مفيدة فقط كتخزين قصير المدى طوال مدة العملية.
- FileDataStoreFactory: تحتفظ ببيانات الاعتماد في ملف.
مستخدمو AppEngine: AppEngineCredentialStore تم إيقافها وستتم إزالتها قريبًا. ننصحك باستخدام AppEngineDataStoreFactory باستخدام StoredCredential. إذا كانت لديك بيانات اعتماد مخزنة بالطريقة القديمة، فيمكنك استخدام طريقة الطرق المساعدة migrateTo(AppEngineDataStoreFactory) أو migrateTo(DataStore) لإجراء الترحيل.
يمكنك استخدام DataStoreCredentialRefreshListener واضبطها لبيانات الاعتماد باستخدام GoogleCredential.Builder.addRefreshListener(CredentialRefreshListener)).
مسار رمز التفويض
استخدام مسار رمز التفويض للسماح للمستخدم النهائي بمنح تطبيقك الوصول إلى بياناتهم المحمية على Google APIs. بروتوكول هذا التدفق هو محددة في منح رموز التفويض
يتم تنفيذ هذا المسار باستخدام GoogleAuthorizationCodeFlow. الخطوات كالآتي:
- يسجِّل المستخدم الدخول إلى تطبيقك. عليك ربط هذا المستخدم. مع رقم تعريف مستخدم فريد لتطبيقك.
- طلب AuthorizationCodeFlow.loadCredential(String)) استنادًا إلى رقم تعريف المستخدم للتحقق مما إذا كانت بيانات اعتماد المستخدم النهائي معروفة بالفعل. إذا كان الأمر كذلك، فقد انتهينا.
- إذا لم يكن لديك رمز التفويض، يمكنك استدعاء الدالة AuthorizationCodeFlow.newAuthorizationUrl(). وتوجيه متصفّح المستخدم إلى صفحة تفويض لمنح وصول التطبيقات إلى بياناتهم المحمية.
- سيعيد خادم تفويض Google بعد ذلك توجيه المتصفح مرة أخرى إلى
عنوان URL لإعادة التوجيه الذي حدّده تطبيقك، مع طلب بحث
code
. استخدام المعلمةcode
لطلب رمز الدخول باستخدام AuthorizationCodeFlow.newTokenRequest(String)). - استخدِم PermissionCodeFlow.createAndStoreCredential(TokenResponse, String)) لتخزين بيانات اعتماد الوصول إلى الموارد المحمية والحصول عليها.
بدلاً من ذلك، إذا كنت لا تستخدم GoogleAuthorizationCodeFlow، فيمكنك استخدام الفئات الأدنى مستوى:
- استخدِم DataStore.get(String) لتحميل بيانات الاعتماد من المتجر استنادًا إلى رقم تعريف المستخدم.
- استخدِم GoogleAuthorizationCodeRequestUrl لتوجيه المتصفِّح إلى صفحة التفويض.
- استخدِم AuthorizationCodeResponseUrl لمعالجة استجابة التفويض وتحليل رمز التفويض.
- استخدِم GoogleAuthorizationCodeTokenRequest لطلب رمز الدخول وربما رمز التحديث.
- أنشئ سمة GoogleCredential جديدة وخزّنها باستخدام DataStore.set(String, V).
- يمكنك الوصول إلى الموارد المحمية باستخدام
GoogleCredential
. ستتم تلقائيًا إعادة تحميل رموز الدخول المنتهية الصلاحية باستخدام الرمز المميّز لإعادة التحميل (إذا كان ذلك منطبقًا). تأكَّد من استخدام DataStoreCredentialRefreshListener وضبطه لبيانات الاعتماد باستخدام GoogleCredential.Builder.addRefreshListener(CredentialRefreshListener)).
عند إعداد مشروعك في وحدة التحكم في واجهة Google API، وتختار من بين بيانات اعتماد مختلفة، اعتمادًا على التدفق الذي تستخدمه. لمزيد من التفاصيل، يُرجى الاطّلاع على إعداد OAuth 2.0. وسيناريوهات OAuth 2.0. توجد مقتطفات التعليمات البرمجية لكل مسار من التدفقات أدناه.
تطبيقات خادم الويب
يتم شرح بروتوكول هذا التدفق استخدام OAuth 2.0 مع تطبيقات خادم الويب
توفر هذه المكتبة فئات serlet مساعدًا لتبسيط عملية مسار رمز التفويض لحالات الاستخدام الأساسية. ما عليك سوى تقديم فئات فرعية ملموسة من AbstractAuthorizationCodeServlet وAbstractAuthorizationCodeCallbackServlet (من google-oauth-client-servlet) وإضافتها إلى ملف web.xml. ملاحظة: لا يزال عليك العناية بالمستخدم تسجيل الدخول إلى تطبيق الويب واستخراج معرّف المستخدم.
public class CalendarServletSample 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 GoogleAuthorizationCodeFlow.Builder( new NetHttpTransport(), GsonFactory.getDefaultInstance(), "[[ENTER YOUR CLIENT ID]]", "[[ENTER YOUR CLIENT SECRET]]", Collections.singleton(CalendarScopes.CALENDAR)).setDataStoreFactory( DATA_STORE_FACTORY).setAccessType("offline").build(); } @Override protected String getUserId(HttpServletRequest req) throws ServletException, IOException { // return user ID } } public class CalendarServletCallbackSample 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 GoogleAuthorizationCodeFlow.Builder( new NetHttpTransport(), GsonFactory.getDefaultInstance() "[[ENTER YOUR CLIENT ID]]", "[[ENTER YOUR CLIENT SECRET]]", Collections.singleton(CalendarScopes.CALENDAR)).setDataStoreFactory( DATA_STORE_FACTORY).setAccessType("offline").build(); } @Override protected String getUserId(HttpServletRequest req) throws ServletException, IOException { // return user ID } }
تطبيقات Google App Engine
تدفق رمز التفويض على App Engine متطابق تقريبًا مع سيرفلت مسار شفرة التفويض، إلا أننا نستطيع الاستفادة من واجهة برمجة تطبيقات المستخدمون Java API: المستخدِم تسجيل الدخول حتى يتم تفعيل واجهة برمجة تطبيقات Java للمستخدمين للحصول على معلومات عن إعادة توجيه المستخدمين إلى صفحة تسجيل دخول إذا لم يسبق لهم تسجيل الدخول، فراجع الأمان والمصادقة (في web.xml).
الاختلاف الأساسي عن حالة serlet هو أنك تقوم بتقديم بدائل
الفئات الفرعية من
AbstractAppEngineAuthorizationCodeServlet وAbstractAppEngineAuthorizationCodeCallbackServlet
(من google-oauth-client-appengine.
توسّع فئات serlet التجريدية وتنفذ طريقة getUserId
لك باستخدام واجهة برمجة تطبيقات Java للمستخدمين. AppEngineDataStoreFactory
(من google-http-client-appengine)
هو خيار جيد للاحتفاظ ببيانات الاعتماد باستخدام بيانات Google App Engine
واجهة برمجة التطبيقات الخاصة بالمتجر
مثال مأخوذ (تم تعديله قليلاً) من calendar-appengine-sample:
public class CalendarAppEngineSample extends AbstractAppEngineAuthorizationCodeServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { // do stuff } @Override protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException { return Utils.getRedirectUri(req); } @Override protected AuthorizationCodeFlow initializeFlow() throws IOException { return Utils.newFlow(); } } class Utils { static String getRedirectUri(HttpServletRequest req) { GenericUrl url = new GenericUrl(req.getRequestURL().toString()); url.setRawPath("/oauth2callback"); return url.build(); } static GoogleAuthorizationCodeFlow newFlow() throws IOException { return new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, getClientCredential(), Collections.singleton(CalendarScopes.CALENDAR)).setDataStoreFactory( DATA_STORE_FACTORY).setAccessType("offline").build(); } } public class OAuth2Callback extends AbstractAppEngineAuthorizationCodeCallbackServlet { private static final long serialVersionUID = 1L; @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 { String nickname = UserServiceFactory.getUserService().getCurrentUser().getNickname(); resp.getWriter().print("<h3>" + nickname + ", why don't you want to play with me?</h1>"); resp.setStatus(200); resp.addHeader("Content-Type", "text/html"); } @Override protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException { return Utils.getRedirectUri(req); } @Override protected AuthorizationCodeFlow initializeFlow() throws IOException { return Utils.newFlow(); } }
للاطّلاع على عيّنة إضافية، يُرجى مراجعة storage-serviceaccount-appengine-sample.
حسابات الخدمة
GoogleCredential تتوافق أيضًا مع حسابات الخدمة. على عكس بيانات الاعتماد التي يطلب فيها أحد تطبيقات العميل الدخول إلى بيانات المستخدم النهائي، توفر حسابات الخدمة إمكانية الوصول إلى حسابات بياناتك الخاصة. يوقّع تطبيق العميل على طلب رمز الدخول باستخدام مفتاح خاص تم تنزيله من وحدة التحكم في واجهة Google API.
مثال على الرمز مأخوذ من plus-serviceaccount-cmdline-sample:
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport(); JsonFactory jsonFactory = GsonFactory.getDefaultInstance(); ... // Build service account credential. GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json")) .createScoped(Collections.singleton(PlusScopes.PLUS_ME)); // Set up global Plus instance. plus = new Plus.Builder(httpTransport, jsonFactory, credential) .setApplicationName(APPLICATION_NAME).build(); ...
للاطّلاع على عيّنة إضافية، يُرجى مراجعة storage-serviceaccount-cmdline-sample.
انتحال الهوية
ويمكنك أيضًا استخدام مسار حساب الخدمة لانتحال هوية مستخدم في نطاق. التي تملكها. يشبه هذا إلى حد كبير تدفق حساب الخدمة أعلاه، ولكنك أيضًا GoogleCredential.Builder.setServiceAccountUser(String)
التطبيقات المثبتة
هذا هو مسار رمز تفويض سطر الأوامر الموضح في استخدام OAuth 2.0 مع التطبيقات المثبّتة.
مثال على مقتطف من plus-cmdline-sample:
public static void main(String[] args) { try { httpTransport = GoogleNetHttpTransport.newTrustedTransport(); dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR); // authorization Credential credential = authorize(); // set up global Plus instance plus = new Plus.Builder(httpTransport, JSON_FACTORY, credential).setApplicationName( APPLICATION_NAME).build(); // ... } private static Credential authorize() throws Exception { // load client secrets GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(PlusSample.class.getResourceAsStream("/client_secrets.json"))); // set up authorization code flow GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder( httpTransport, JSON_FACTORY, clientSecrets, Collections.singleton(PlusScopes.PLUS_ME)).setDataStoreFactory( dataStoreFactory).build(); // authorize return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user"); }
التطبيقات من جانب العميل
لاستخدام تدفق العميل المستند إلى المتصفح الموضح في استخدام OAuth 2.0 مع التطبيقات من جهة العميل، ستتبع عادةً هذه الخطوات:
- إعادة توجيه المستخدم النهائي في المتصفح إلى صفحة التفويض باستخدام GoogleBrowserClientRequestUrl لمنح تطبيق المتصفّح إذن الوصول إلى البيانات المحمية الخاصة بالمستخدم النهائي.
- استخدام مكتبة برامج Google API للغة JavaScript لمعالجة رمز الدخول الموجود في جزء عنوان URL في عنوان URI لإعادة التوجيه مسجَّلة في وحدة التحكم في واجهة Google API
مثال على استخدام تطبيق ويب:
public void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException { String url = new GoogleBrowserClientRequestUrl("812741506391.apps.googleusercontent.com", "https://oauth2.example.com/oauthcallback", Arrays.asList( "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile")).setState("/profile").build(); response.sendRedirect(url); }
Android
المكتبة التي يمكن استخدامها مع Android:
إذا كنت تطور برامج لنظام Android وتم تضمين واجهة برمجة تطبيقات Google التي تريد استخدامها في مكتبة خدمات Google Play استخدم تلك المكتبة للحصول على أفضل أداء وتجربة. إذا كانت واجهة برمجة تطبيقات Google تريد استخدامها مع Android ليس جزءًا من مكتبة خدمات Google Play، يمكن استخدام مكتبة برامج Google API للغة Java، والتي تتوافق مع نظام التشغيل Android 4.0 (Iceكريم ساندويتش) (أو أعلى)، والموضح هنا. يأتي دعم Android في مكتبة برامج واجهة برمجة التطبيقات للغة Java هي @إصدار تجريبي.
الخلفية:
بدءًا من Eclair (الإصدار 2.1 من حزمة تطوير البرامج (SDK))، تتم إدارة حسابات المستخدمين على جهاز Android. من خلال استخدام مدير الحساب تتم إدارة جميع تفويضات تطبيقات Android في مكان مركزي بواسطة حزمة SDK باستخدام AccountManager. وعليك أن تحدِّد نطاق OAuth 2.0 الذي يحتاجه تطبيقك، ويعرض إذنًا بالوصول المستخدم الصحيح.
يتم تحديد نطاق OAuth 2.0 من خلال مَعلمة authTokenType
باعتباره oauth2:
.
بالإضافة إلى النطاق. على سبيل المثال:
oauth2:https://www.googleapis.com/auth/tasks
يحدّد هذا الإعداد إذن الوصول للقراءة/الكتابة إلى واجهة برمجة تطبيقات "مهام Google". إذا كنت بحاجة إلى عدة نطاقات OAuth 2.0، يمكنك استخدام قائمة مفصولة بمسافات.
تحتوي بعض واجهات برمجة التطبيقات على معلَمات authTokenType
خاصة تعمل أيضًا. على سبيل المثال:
"إدارة المهام" هو اسم مستعار للمثال authtokenType
الموضح أعلاه.
يجب عليك أيضًا تحديد مفتاح واجهة برمجة التطبيقات من وحدة التحكم في واجهة Google API: وبخلاف ذلك، لا يوفر لك الرمز المميز الذي يوفره لك مدير الحساب سوى حصة مجهولة، والتي عادةً ما تكون منخفضة للغاية. أمّا من خلال تحديد واجهة برمجة تطبيقات تحصل على حصة مجانية أعلى، ويمكنك إعداد الفوترة للاستخدام اختياريًا فوق ذلك.
مثال على مقتطف الرمز مأخوذ من tasks-android-sample:
com.google.api.services.tasks.Tasks service; @Override public void onCreate(Bundle savedInstanceState) { credential = GoogleAccountCredential.usingOAuth2(this, Collections.singleton(TasksScopes.TASKS)); SharedPreferences settings = getPreferences(Context.MODE_PRIVATE); credential.setSelectedAccountName(settings.getString(PREF_ACCOUNT_NAME, null)); service = new com.google.api.services.tasks.Tasks.Builder(httpTransport, jsonFactory, credential) .setApplicationName("Google-TasksAndroidSample/1.0").build(); } private void chooseAccount() { startActivityForResult(credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case REQUEST_GOOGLE_PLAY_SERVICES: if (resultCode == Activity.RESULT_OK) { haveGooglePlayServices(); } else { checkGooglePlayServicesAvailable(); } break; case REQUEST_AUTHORIZATION: if (resultCode == Activity.RESULT_OK) { AsyncLoadTasks.run(this); } else { chooseAccount(); } break; case REQUEST_ACCOUNT_PICKER: if (resultCode == Activity.RESULT_OK && data != null && data.getExtras() != null) { String accountName = data.getExtras().getString(AccountManager.KEY_ACCOUNT_NAME); if (accountName != null) { credential.setSelectedAccountName(accountName); SharedPreferences settings = getPreferences(Context.MODE_PRIVATE); SharedPreferences.Editor editor = settings.edit(); editor.putString(PREF_ACCOUNT_NAME, accountName); editor.commit(); AsyncLoadTasks.run(this); } } break; } }