这样做的原因是我想要保护我的API或者“锁定”它只对我指定的客户机。有时我会有一个没有用户登录的应用程序。我不想纠缠我的用户现在登录只是为了我的API是安全的。或者其他时候,我只想像在一个网站上那样管理自己的用户,而不使用Google+、Facebook,或者其他什么登录认证。
首先,让我介绍一下如何使用文档中指定的Google Accounts登录名,通过云endpointAPI验证Android应用程序。之后,我将向你展示我的发现和一个解决方案的潜在领域,我需要帮助。
(1)指定被授权向API后端发出请求的应用程序的客户端ID(ClientID);(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)在Android中,调用Asynctask中的API方法,确保在Builder
中传入Credential
变量:
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 account picker,将Google account电子邮件存储在您的共享首选项中,然后将其设置为GoogleAccountCredential
对象的一部分(在此提供更多信息)。
Google App Engine服务器接收您的请求并进行检查。如果Android客户机是您在@API
符号中指定的客户机之一,那么服务器将把com.google.API.server.spi.auth.common.user
对象注入到您的API方法中。现在您有责任检查user
对象是否为null
或不在API方法中。如果user
对象为null
,则应在方法中引发异常以阻止其运行。如果不执行此检查,您的API方法将执行(如果试图限制对它的访问,则为no-no)。
您可以访问Google Developers Console获得android_client_id
。在这里,您提供了Android应用程序的包名和SHA1,它为您生成了一个Android客户端id,供您在@api
注释中使用(或者将其放在一个类constants
中,就像上面为可用性指定的那样)。
我对上述所有内容做了一些广泛的测试,以下是我的发现:
如果您在@API
注释中指定了伪造的或无效的Android clientId,则在API方法中,user
对象将为null
。如果您正在检查If(user==null)是否抛出新的UnauthorizedException(“user is Not valid”);
,那么您的API方法将不会运行。
这是令人惊讶的,因为云endpoint中似乎正在进行一些幕后验证,以检查Android ClientId是否有效。如果它无效,它将不会返回user
对象--即使最终用户登录到他们的Google帐户并且GoogleAccountCredential
有效。
我的问题是,有人知道我如何在我的云endpoint方法中检查这种类型的ClientId验证吗?例如,该信息可以在HttpHeader
中传递吗?
云endpoint中注入的另一种类型是javax.html" target="_blank">servlet.http.HttpServletRequest
。您可以在您的API方法中获得如下所示的请求:
@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;
}
}
这样,您就可以将API锁定到Android应用程序(可能还有其他客户端),而不必纠缠最终用户登录(或者只需创建您自己的简单用户名+密码登录)。
要使所有这些工作正常,您必须在Builder
的第三个参数中传入null
,如下所示:
myapi.builder builder=new myapi.builder(AndroidHttp.NewCompatibleTransport(),new AndroidJsonFactory(),null)
然后在API方法中提取调用是否来自经过身份验证的客户机,并抛出异常或运行您想要的任何代码。
我知道这是可能的,因为当在Builder
中使用GoogleAccountCredential
时,云endpoint知道调用是否来自经过身份验证的客户端,然后将其User
对象注入API方法,或者是否基于此。
这些信息可能会在标题或正文中吗?如果是这样,我如何将它取出以便稍后检查它是否存在于我的API方法中?
注意:我看了其他关于这个话题的帖子。它们提供了传递您自己的身份验证令牌的方法--这很好--但如果有人对.apk进行反编译,它仍然不安全。我认为如果我的假设有效,您将能够将您的云endpointAPI锁定到客户机,而无需任何登录。
Google Cloud终结点的自定义身份验证(而不是OAuth2)
将我的“应用程序”身份验证给谷歌云endpoint而不是“用户”
(皱着眉头的脸)--不过,也许还是有可能的?
在主机上安装harbor。使用普通HTTP协议。 IP为。 我可以从harbor服务器本身登录它: 并可以从浏览器访问它: https://github.com/vmware/harbor/blob/master/docs/installation_guide.md 重要提示:Harbor的默认安装使用HTTP--因此,您需要将选项--insecure-registry添加到客户端的Docker守
我正在开发一个在JBOSS Wildfly下运行的JSF2应用程序,它利用了Java的JAAS安全机制。 一切都按预期工作,我可以使用 request.login(用户名,密码)机制登录。 我还需要授权设备(我已使用cookie实现)作为登录过程的一部分。我试图实施的过程如下: 验证用户名和密码(但不登录) 检查设备授权并重定向到授权过程页面(如果尚未授权)。 登录(如果授权成功) 除非用户被授权
我正在处理一个使用PHP的项目,需要使用PHP客户端库实现Google CloudAPI,但身份验证似乎对我不起作用。我已经创建了一个服务帐户并授予了项目所有者权限,我不想通过使用GOOGLE_DEFAULT_CREDENTIALS环境变量进行身份验证,我想使用服务帐户身份验证。 致命错误:未捕获异常“Google\Cloud\Core\exception\ServiceException”,消息
从命令行,我可以像这样登录mysql: (仅供参考,不能使用本地主机,必须使用IP)我可以得到:http://myhost.com/phpmyadmin/ 但我无法使用myuser帐户登录 - 收到重复的登录提示并最终“拒绝访问”。 所以我尝试编辑:/var/lib/phpmyadmin/config.inc.php添加了: < Li > $ CFG[' Servers '][1][' host
我有一个场景,我通过使用firebase身份验证通过匿名登录,并从匿名登录帐户,我已经从事件列表中添加了事件作为收藏夹项目,现在我想使用Google或Facebook登录,以便我最喜欢的项目永远不会丢失,每当我登录收藏夹项目必须从该登录帐户获得。 我正在使用上述场景Firebase链接。但问题是,firebase链接只对一个匿名帐户有效一次,如果我再次匿名登录并添加最喜欢的事件,现在我使用以前的方
因此,为了实现这个逻辑,我认为我需要在客户端验证JWT令牌。Q1,这是一个明智的做法吗。 Q2,我正在使用的库似乎需要一个公钥才能使用它的函数。我似乎没有公钥,只有一个秘密,这是我刚刚编造的,所以它不是用一对生成的。我的公钥从何而来,或者是否有另一种方法来验证我的令牌而不使用此方法? 这一切似乎应该是显而易见的,我错过了一些东西,所以很抱歉,如果这是一个愚蠢的问题,但我似乎找不到答案?