限制访问我的API端点到Android应用程序

时间:2014-11-26 10:52:05

标签: android google-app-engine oauth-2.0 google-cloud-endpoints

我想限制我的API端点仅访问我的Android应用,但没有google_account /密码。 我选择了这些方法:https://developers.google.com/accounts/docs/OAuth2

为了测试,我成功使用此方法将我的Android应用程序验证到我的API:https://cloud.google.com/appengine/docs/python/endpoints/consume_android ==>此方法允许您使用组合验证您的应用程序:

  • 登录/密码(Google帐户)
  • 您的Android APP的SHA1和包名称

因此,如果有人获取我的代码(反编译apk)并修改我的Android代码,他们就无法访问我的API,因为我的应用程序的SHA1指纹会发生变化。 (我测试了它,它的工作原理=)) 此方法运行正常,但我不希望Google登录/密码进行身份验证..

所以我尝试了这种方法:https://developers.google.com/accounts/docs/OAuth2ServiceAccount 我成功验证了我的Android应用程序,但是,如果我的android代码被其他人修改(所以SHA1已更改),我的Android应用程序仍然可以连接到我的API!因此,如果有人获得我的包并对其进行反编译,他将自由更改代码并成功访问我的API ..

这是我的API代码:

@ApiMethod( name = "ListCampagnes", httpMethod = ApiMethod.HttpMethod.GET, path="list", clientIds = {CONSTANTES.ANDROID_CLIENT_ID, CONSTANTES.WEB_CLIENT_ID, CONSTANTES.SERVICE_CLIENT_ID, com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID}, audiences = {CONSTANTES.ANDROID_AUDIENCE})

public Collection<Campagne> getCampagnes(@Named("NumPortable")String NumPortable, User user) throws  UnauthorizedException {

    if (user == null) throw new UnauthorizedException("User is Not Valid");

        return CampagneCRUD.getInstance().findCampagne(NumPortable);
    }

这是我的android代码:

GoogleCredential credentialToAppengine;
try {

    String p12Password = "notasecret";
    KeyStore keystore = KeyStore.getInstance("PKCS12");
    InputStream keyFileStream = getAssets().open("59ce5a08e110.p12");
    keystore.load(keyFileStream, p12Password.toCharArray());
    PrivateKey key = (PrivateKey)keystore.getKey("privatekey", p12Password.toCharArray());
    credentialToAppengine = new GoogleCredential.Builder().setTransport(AndroidHttp.newCompatibleTransport()).setJsonFactory(new JacksonFactory()).setServiceAccountId("301991144702-3v9ikfp4lsmokee1utkucj35847eddvg@developer.gserviceaccount.com").setServiceAccountPrivateKey(key).setServiceAccountScopes(Collections.singleton("https://www.googleapis.com/auth/userinfo.email")).build();
} catch (GeneralSecurityException e) {

    e.printStackTrace();
    return null;
} catch (Exception e) {

    e.printStackTrace();
    return null;
} 

我是否尝试其他方法来验证我的Android应用程序?或者我在API代码中遗漏了什么? 提前谢谢你,

1 个答案:

答案 0 :(得分:0)

在没有Google用户帐户的情况下验证Android端点是不可能的!我尝试了各种方法,但仍然无效!

所以这是解决这个问题的方法,没有任何用户交互(也许不是正确的但是有效,而且你有强大的身份验证(SHA1 + Google帐户)):

这是我的安卓代码

获取并构建有效凭据

  //Get all accounts from my Android Phone
         String validGoogleAccount = null;
         Pattern emailPattern = Patterns.EMAIL_ADDRESS; // API level 8+
         Account[] accounts = AccountManager.get(context).getAccounts();
         for (Account account : accounts) {
             if (emailPattern.matcher(account.name).matches()) {
                 //Just store mail if countain gmail.com
                 if (account.name.toString().contains("gmail.com")&&account.type.toString().contains("com.google")){
                     validGoogleAccount=account.name.toString();
                 }

             }
         }

        //Build Credential with valid google account
        GoogleAccountCredential credential = GoogleAccountCredential.usingAudience(this,"server:client_id:301991144702-5qkqclsogd0b4fnkhrja7hppshrvp4kh.apps.googleusercontent.com");
        credential.setSelectedAccountName(validGoogleAccount);

使用此凭据进行安全通话

Campagneendpoint.Builder endpointBuilder = new Campagneendpoint.Builder(AndroidHttp.newCompatibleTransport(), new JacksonFactory(), credential);

这是我的API后备代码: API注释

@Api(
        scopes=CONSTANTES.EMAIL_SCOPE,
        clientIds = {CONSTANTES.ANDROID_CLIENT_ID, 
                     CONSTANTES.WEB_CLIENT_ID,
                     com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID},
        audiences = {CONSTANTES.ANDROID_AUDIENCE},      
        name = "campagneendpoint",
        version = "v1"
     )

方法代码:

public Collection<Campagne> getCampagnes(@Named("NumPortable")String NumPortable, User user) throws  UnauthorizedException {
        if (user == null) throw new UnauthorizedException("User is Not Valid");

      return CampagneCRUD.getInstance().findCampagne(NumPortable);
     }

目前,它仅适用于Android(我不知道我们将如何处理IOS ..)..

希望它会对你有帮助!