23

मैं अपने Google खाते लॉगिन का उपयोग करने के लिए अपने उपयोगकर्ता की आवश्यकता के बिना कैसे अपने ग्राहक (Android, iOS, वेब-एप्लीकेशन) क्लाउड अंतिम बिंदु के साथ प्रमाणित करने पर व्यापक शोध कर रहे हैं जिस तरह से documentation आपको दिखाता है।एक Google खाता लॉगिन बिना मेघ अंतिम बिंदु के लिए अपने ग्राहक प्रमाणित कर रहा है

इसका कारण यह है कि मैं अपने एपीआई को सुरक्षित करना चाहता हूं या केवल मेरे निर्दिष्ट ग्राहकों को "इसे लॉक करना" चाहता हूं। कभी-कभी मेरे पास एक ऐप होगा जिसमें उपयोगकर्ता लॉगिन नहीं होगा। मैं अपने उपयोगकर्ता को अब साइन इन करने के लिए परेशान करता हूं इसलिए मेरा एपीआई सुरक्षित है। या अन्य बार, मैं बस अपने स्वयं के उपयोगकर्ताओं को वेबसाइट पर प्रबंधित करना चाहता हूं और Google+, फेसबुक, या जो कुछ भी लॉगिन प्रमाणीकरण का उपयोग नहीं करना चाहता हूं।

प्रारंभ करने के लिए, मुझे सबसे पहले documentation में निर्दिष्ट Google खाता लॉगिन का उपयोग करके अपने क्लाउड एंडपॉइंट्स एपीआई के साथ अपने एंड्रॉइड ऐप को प्रमाणित करने का तरीका दिखाएं। इसके बाद मैं आपको एक समाधान के लिए अपने निष्कर्ष और संभावित क्षेत्र दिखाऊंगा जिसके लिए मुझे सहायता चाहिए।

(1) अपने एपीआई बैकएंड में अनुरोध करने के लिए अधिकृत ऐप्स के क्लाइंट आईडी (क्लाइंट आईडी) निर्दिष्ट करें और (2) प्रमाणीकरण द्वारा संरक्षित किए जाने वाले सभी खुला तरीकों में उपयोगकर्ता पैरामीटर जोड़ें।

public class Constants { 
     public static final String WEB_CLIENT_ID = "1-web-apps.apps.googleusercontent.com"; 
     public static final String ANDROID_CLIENT_ID = "2-android-apps.googleusercontent.com"; 
     public static final String IOS_CLIENT_ID = "3-ios-apps.googleusercontent.com"; 
     public static final String ANDROID_AUDIENCE = WEB_CLIENT_ID; 

     public static final String EMAIL_SCOPE = "https://www.googleapis.com/auth/userinfo.email"; 
    } 


import com.google.api.server.spi.auth.common.User; //import for the User object 

    @Api(name = "myApi", version = "v1", 
     namespace = @ApiNamespace(ownerDomain = "${endpointOwnerDomain}", 
     ownerName = "${endpointOwnerDomain}", 
     packagePath="${endpointPackagePath}"), 
     scopes = {Constants.EMAIL_SCOPE}, 
     clientIds = {Constants.WEB_CLIENT_ID, Constants.ANDROID_CLIENT_ID, 
         Constants.IOS_CLIENT_ID, 
         Constants.API_EXPLORER_CLIENT_ID}, 
         audiences = {Constants.ANDROID_AUDIENCE}) 

    public class MyEndpoint { 

     /** A simple endpoint method that takes a name and says Hi back */ 
     @ApiMethod(name = "sayHi") 
     public MyBean sayHi(@Named("name") String name, User user) throws UnauthorizedException { 
      if (user == null) throw new UnauthorizedException("User is Not Valid"); 
      MyBean response = new MyBean(); 
      response.setData("Hi, " + name); 

      return response; 
     } 

    } 

(3) एंड्रॉयड Builder में credential चर में पारित करने के लिए सुनिश्चित करने के लिए एक Asynctask में एपीआई विधि कॉल में:

class EndpointsAsyncTask extends AsyncTask<Pair<Context, String>, Void, String> { 
     private static MyApi myApiService = null; 
     private Context context; 

     @Override 
     protected String doInBackground(Pair<Context, String>... params) { 
      credential = GoogleAccountCredential.usingAudience(this, 
      "server:client_id:1-web-app.apps.googleusercontent.com"); 
      credential.setSelectedAccountName(settings.getString(PREF_ACCOUNT_NAME, null)); 
      if(myApiService == null) { // Only do this once 
       MyApi.Builder builder = new MyApi.Builder(AndroidHttp.newCompatibleTransport(), 
         new AndroidJsonFactory(), credential) 
        // options for running against local devappserver 
        // - 10.0.2.2 is localhost's IP address in Android emulator 
        // - turn off compression when running against local devappserver 
        .setRootUrl("http://<your-app-engine-project-id-here>/_ah/api/") 
        .setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() { 
         @Override 
         public void initialize(AbstractGoogleClientRequest<?> abstractGoogleClientRequest) throws IOException { 
          abstractGoogleClientRequest.setDisableGZipContent(true); 
         } 
        }); 
        // end options for devappserver 

       myApiService = builder.build(); 
      } 

      context = params[0].first; 
      String name = params[0].second; 

      try { 
       return myApiService.sayHi(name).execute().getData(); 
      } catch (IOException e) { 
       return e.getMessage(); 
      } 
     } 

     @Override 
     protected void onPostExecute(String result) { 
      Toast.makeText(context, result, Toast.LENGTH_LONG).show(); 
     } 
    } 

क्या हो रहा है कि अपने Android एप्लिकेशन में आप दिखा रहे हैं है Google खाता पिकर पहले, आपके द्वारा Google खाता ईमेल को साझा प्राथमिकताओं में संग्रहीत करता है, और उसके बाद इसे GoogleAccountCredential ऑब्जेक्ट (here को कैसे करें) के बारे में अधिक जानकारी के रूप में सेट करता है।

Google App Engine सर्वर आपका अनुरोध प्राप्त करता है और इसे जांचता है। यदि एंड्रॉइड क्लाइंट उन 0 में से एक है जिन्हें आपने @Api नोटेशन में निर्दिष्ट किया है, तो सर्वर com.google.api.server.spi.auth.common.User ऑब्जेक्ट को आपके एपीआई विधि में इंजेक्ट करेगा। यह जांचना आपकी ज़िम्मेदारी है कि User ऑब्जेक्ट null है या आपकी एपीआई विधि के अंदर नहीं है। यदि User ऑब्जेक्ट null है, तो आपको इसे चलाने से रोकने के लिए अपनी विधि में अपवाद फेंकना चाहिए। यदि आप यह चेक नहीं करते हैं, तो आपकी एपीआई विधि निष्पादित होगी (यदि आप इसे एक्सेस प्रतिबंधित करने का प्रयास कर रहे हैं तो कोई संख्या नहीं)।

आप अपने Google डेवलपर कंसोल पर जाकर ANDROID_CLIENT_ID प्राप्त कर सकते हैं। वहां, आप अपने एंड्रॉइड ऐप और SHA1 का पैकेज नाम प्रदान करते हैं जो आपके लिए आपके @Api एनोटेशन (या इसे Constants में उपयोगिता के लिए ऊपर निर्दिष्ट की तरह) में उपयोग करने के लिए एक एंड्रॉइड क्लाइंट आईडी उत्पन्न करता है।

मैं ऊपर और यहां के सभी के साथ कुछ व्यापक परीक्षण किया है कि मैं क्या पाया है:

आप अपने @Api टिप्पणी में फर्जी या अमान्य एंड्रॉयड clientid निर्दिष्ट करते हैं, User वस्तु में null हो जाएगा अपने एपीआई विधि। यदि आप if (user == null) throw new UnauthorizedException("User is Not Valid"); के लिए चेक कर रहे हैं तो आपकी एपीआई विधि नहीं चली जाएगी।

यह आश्चर्य की बात है क्योंकि ऐसा लगता है कि क्लाउड एंडपॉइंट्स में दृश्य सत्यापन सत्यापन के पीछे कुछ है जो जांचता है कि एंड्रॉइड क्लाइंटआईड मान्य है या नहीं। यदि यह अमान्य है, तो यह User ऑब्जेक्ट वापस नहीं करेगा - भले ही अंतिम उपयोगकर्ता अपने Google खाते में लॉग इन हो और GoogleAccountCredential मान्य था।

मेरा सवाल यह है कि, क्या कोई जानता है कि मैं क्लाउड एंडपॉइंट विधियों में अपने आप के क्लाइंट आईडी सत्यापन के लिए कैसे जांच सकता हूं? क्या यह जानकारी उदाहरण के लिए HttpHeader में पारित की जा सकती है?

क्लाउड एंडपॉइंट्स में एक और इंजेक्शन प्रकार javax.servlet.http.HttpServletRequest है। आप इस तरह के अनुरोध को अपने एपीआई विधि में प्राप्त कर सकते हैं:

@ApiMethod(name = "sayHi") 
      public MyBean sayHi(@Named("name") String name, HttpServletRequest req) throws UnauthorizedException { 

       String Auth = req.getHeader("Authorization");//always null based on my tests 
       MyBean response = new MyBean(); 
       response.setData("Hi, " + name); 

       return response; 
      } 

     } 

लेकिन मुझे यकीन नहीं है कि आवश्यक जानकारी वहां है या इसे कैसे प्राप्त किया जाए।

निश्चित रूप से कहीं वहाँ कुछ डेटा है, तो ग्राहक एक अधिकृत और @ApiclientIds में एक निर्दिष्ट है हमें बताता है कि होना चाहिए।

इस तरह, आप अपने एंड्रॉइड ऐप (और संभावित रूप से अन्य क्लाइंट) में अपने एपीआई को लॉक-डाउन कर सकते हैं, बिना किसी अंत में अपने अंतिम उपयोगकर्ताओं को लॉग इन करने के लिए परेशान किए बिना (या बस अपना खुद का सरल उपयोगकर्ता नाम + पासवर्ड लॉगिन बनाएं)।

यह सब हालांकि काम करने के लिए, तो आप इस तरह अपने Builder का तीसरा तर्क में null में पारित करने के लिए होगा:

MyApi.Builder बिल्डर = नए MyApi.Builder (AndroidHttp.newCompatibleTransport(), नया एंड्रॉइड जेसनफ़ैक्टरी(), शून्य)

फिर आपके एपीआई विधि में निकाला गया है कि कॉल किसी प्रमाणीकृत क्लाइंट से आया है या नहीं, या तो कोई अपवाद फेंक दें या जो भी कोड आप चाहते हैं उसे चलाएं।

मैं जानता हूँ कि यह संभव है, क्योंकि जब Builder में एक GoogleAccountCredential का उपयोग कर, किसी भी तरह मेघ अंतिम बिंदु जानता है या नहीं, कॉल एक प्रमाणीकृत क्लाइंट की ओर से आया था और फिर या तो एपीआई विधि या कि पर आधारित नहीं में अपनी User वस्तु injects।

क्या यह जानकारी किसी भी तरह हेडर या बॉडी में हो सकती है? यदि हां, तो मैं इसे बाद में जांचने के लिए कैसे प्राप्त कर सकता हूं कि यह मेरी एपीआई विधि में है या नहीं?

नोट: मैंने इस विषय पर अन्य पोस्ट पढ़ी हैं। वे आपके स्वयं के प्रमाणीकरण टोकन में पास करने के तरीके प्रदान करते हैं - जो ठीक है - लेकिन अगर कोई इसे डिमंपाइल करता है तो आपका .apk अभी भी सुरक्षित नहीं होगा। मुझे लगता है कि अगर मेरी परिकल्पना काम करती है, तो आप बिना किसी लॉग इन के क्लाइंट एंडपॉइंट्स एपीआई को क्लाइंट में लॉक-डाउन कर पाएंगे।

Custom Authentication for Google Cloud Endpoints (instead of OAuth2)

Authenticate my "app" to Google Cloud Endpoints not a "user"

Google Cloud Endpoints without Google Accounts

संपादित करें: हम Google मेघ प्लेटफ़ॉर्म के लिए सोने का समर्थन किया जाता है और आगे और पीछे सप्ताह के लिए अपना समर्थन टीम के साथ बात कर दिया गया है। यह हमारे लिए अपने अंतिम जवाब है:।

"दुर्भाग्य से, मैं नहीं इस पर कोई भाग्य पड़ा है मैं अपने टीम के आसपास पूछा है, और प्रलेखन के सभी की जाँच यह का उपयोग कर OAuth2 है जैसा दिखता है। आपका एकमात्र विकल्प। कारण यह है कि एंडपॉइंट सर्वर प्रमाणीकरण को आपके ऐप तक पहुंचने से पहले संभालता है।इसका मतलब है कि आप अपने स्वयं के प्रमाणीकरण प्रवाह को विकसित करने में सक्षम नहीं होंगे, और परिणाम परिणाम प्राप्त करेंगे जो आप टोकन के साथ देख रहे थे।

मुझे आपके लिए एक सुविधा अनुरोध सबमिट करने में खुशी होगी। आप क्यों OAuth2 प्रवाह अपने ग्राहकों के लिए काम करते नहीं करता है के बारे में थोड़ा और अधिक जानकारी प्रदान कर सकता है, मैं बाकी जानकारी के साथ (डाल सकते हैं और उत्पाद प्रबंधक के लिए सबमिट करें। "

उदास चेहरा) - हालांकि, शायद यह अभी भी संभव है?

उत्तर

1

मैंने कस्टम हेडर "प्राधिकरण" का उपयोग करके एंडपॉइंट एथ लागू किया है और यह ठीक काम करता है। मेरे मामले में यह टोकन लॉगिन के बाद सेट है लेकिन इसे आपके साथ भी काम करना चाहिए ऐप। अपने परीक्षणों की जांच करें क्योंकि मान वहां होना चाहिए। उस शीर्षलेख को पुनर्प्राप्त करने का तरीका वास्तव में है:

String Auth = req.getHeader("Authorization");

आप इसे एक कदम आगे ले और एक Authenticator का अपना स्वयं का कार्यान्वयन को परिभाषित करने और अपने सुरक्षित API कॉल करने के लिए यह लागू हो सकते हैं।

+0

'req.getHeader (" प्रमाणीकरण ")' null' है यदि आप एंड्रॉइड क्लाइंट से Google प्रमाण पत्र में पास नहीं करते हैं। मैंने 'प्रमाणीकरणकर्ता' के अपने कार्यान्वयन में भी गुजरने का प्रयास किया है, लेकिन समस्या अभी भी मौजूद है: यदि कोई व्यक्ति आपके ऐप को डि-कंपाइल करता है, तो वे आपके ऐप को खराब कर सकते हैं क्योंकि आपके 'प्रमाणक' को काले और सफेद रंग में लिखा गया है ... तो मैं उम्मीद कर रहा था कि कुछ और रास्ता था ... – Micro

+0

@micror यह सच नहीं है। मैंने उपयोगकर्ता परिभाषित मानों (उदाहरण के लिए एक कोणीय जेएस क्लाइंट से) के साथ एथ जैसे कस्टम हेडर पॉप्युलेट किए हैं – jirungaray

+0

कौन सा हिस्सा सत्य नहीं है? हां आप कस्टम हेडर जैसे खुद के द्वारा पॉप्युलेट कर सकते हैं लेकिन तथ्य यह है कि: आपके ऐप को डिमंपिल्ड और स्पूफ किया जा सकता है। कृपया मेरा प्रश्न दोबारा पढ़ें - सवाल दिखाता है कि कुछ प्रकार के प्रमाणीकरण कैसे हैं क्लाउड एंडपॉइंट्स एंड्रॉइड क्लाइंट को सत्यापित करने के लिए कर रहा है कि वे हमें इसके बारे में नहीं बता रहे हैं, इसलिए हम जवाब निकाल सकते हैं। – Micro

0

तो तुम किसी भी उपयोगकर्ता विशिष्ट जानकारी नहीं है, लेकिन सिर्फ यह सुनिश्चित करें कि अपने ऐप्लिकेशन अपने बैकएंड के साथ संवाद करने ... यह मैं क्या सोचते है में सक्षम है चाहता हूँ,

परिवर्तन

@Api(name = "myApi", version = "v1", 
     namespace = @ApiNamespace(ownerDomain = "${endpointOwnerDomain}", 
     ownerName = "${endpointOwnerDomain}", 
     packagePath="${endpointPackagePath}"), 
     scopes = {Constants.EMAIL_SCOPE}, 
     clientIds = {Constants.WEB_CLIENT_ID, Constants.ANDROID_CLIENT_ID, 
         Constants.IOS_CLIENT_ID, 
         Constants.API_EXPLORER_CLIENT_ID}, 
         audiences = {Constants.ANDROID_AUDIENCE}) 
{ 
... 
} 

को
@Api(name = "myApi", version = "v1", 
     namespace = @ApiNamespace(ownerDomain = "${endpointOwnerDomain}", 
     ownerName = "${endpointOwnerDomain}", 
     packagePath="${endpointPackagePath}"), 
     scopes = {Constants.EMAIL_SCOPE}, 
     clientIds = {Constants.ANDROID_CLIENT_ID}, 
     audiences = {Constants.ANDROID_AUDIENCE}) 

{ 
... 
} 

ग्राहक आईडी अपने अनुप्रयोग के हस्ताक्षर से उत्पन्न होता है। इसे दोहराया नहीं जा सकता है। यदि आप केवल एंड्रॉइड ऐप से अपने एंडपॉइंट्स को अनुरोध स्वीकार करने की अनुमति देते हैं, तो आपकी समस्या हल हो जाएगी।

मुझे बताएं कि यह काम करता है या नहीं।

+0

आपके उत्तर के लिए धन्यवाद लेकिन यह काम नहीं करता है। 'Constants.WEB_CLIENT_ID को हटा रहा है, Constants.IOS_CLIENT_ID, Constants.API_EXPLORER_CLIENT_ID' कुछ भी नहीं करता है। – Micro

+0

@MicroR हाँ शायद यह केवल ओथ के लिए ही है। आपकी समस्या के लिए, आपको एक कस्टम प्रमाणीकरण की आवश्यकता होगी। आरएसए के आधार पर कुछ क्यों नहीं उपयोग करें? –

1

Google खाता का उपयोग किए बिना मेरे एपीपी को सुरक्षित रूप से मेरे एपीआई को कॉल करने के लिए एक समाधान खोजने के लिए एक ही समस्या का सामना करना पड़ा। । हम

समाधान मैंने पाया सही नहीं है या किसी iOS एप्लिकेशन (बंडल) डिकंपाइल नहीं कर सकते, लेकिन डिकंपाइल एक Android अनुप्रयोग बहुत आसान है .. लेकिन काम बहुत अच्छी कार्य करें:

  1. Android एप्लिकेशन पर, मैं बस एक स्थिर स्ट्रिंग वैरिएबल बना देता हूं, जिसका नाम केवल एपीकेकी है, उदाहरण के लिए "helloworld145698")
  2. फिर मैं इसे sha1, अगले md5, और अंत में sha1 (ऑर्डर और एन्क्रिप्शन की आवृत्ति) के साथ एन्क्रिप्ट करता हूं और स्टोर करता हूं निजी मोड (अपने ऐप में एक यादृच्छिक वर्ग पर यह क्रिया करें) में साझाप्रेफ़ (एंड्रॉइड के लिए) पर परिवर्तनीय यह परिणाम एनक्रिप्ट किया गया है मैं अपने बैकएंड पर अधिकृत करता हूं!
  3. मेरी बैकएंड पर, मैं तो बस हर अनुरोध पर एक पैरामीटर (उदाहरण के लिए नामित किया गया टोकन) जोड़ने

उदाहरण:

@ApiMethod(name = "sayHi") 
    public void sayHi(@Named("name") String name, @Named("Token") String token) { 

    if (token == tokenStoreOnAPIServer) { 
     //Allow it 
    } else { 
     //Refuse it and print error 
    } 

} 
  1. पर एंड्रॉइड, सक्रिय प्रोगार्ड आपके कोड को पर रोक लगाता है। यह किसी को भी अपने app डिकंपाइल करने की कोशिश की के लिए वास्तव में पढ़ने योग्य नहीं किया जाएगा

नहीं सही सुरक्षित समाधान (रिवर्स इंजीनियरिंग वास्तव में कट्टर है), लेकिन यह काम करता है, और यह वास्तव में सच में (वास्तव में) मुश्किल लगता है हो जाएगा डिकंपिलेशन के बाद अपना कोड पढ़ने का प्रयास करने वाले किसी भी व्यक्ति के लिए असली एपीआई कुंजी।

+0

सुझाव के लिए धन्यवाद। – Micro

संबंधित मुद्दे