根据应用引擎端点对用户进行身份验证

时间:2016-03-14 11:25:28

标签: android google-app-engine authentication google-cloud-endpoints

我正在创建我的第一个应用引擎应用,并且在验证用户方面遇到了问题。

我跟着https://cloud.google.com/appengine/docs/python/endpoints/consume_android#making_authenticated_calls - 似乎有点神奇,我只是" setAccountName"并且它应该可以工作,但是我想它应该从Android Audience加载应用范围,然后检查我通过的帐户名是否已经实际登录到设备。

API调用有效,通过身份验证,但遗憾的是 - " endpoints.get_current_user()"后端的函数返回None。

所以我一直在挖掘,但我似乎无法找到关于这个话题的任何内容。我发现的最好的东西是http://blog.notdot.net/2010/05/Authenticating-against-App-Engine-from-an-Android-app - 但这是6年前的一篇文章,作者使用HTTP客户端,没有任何与端点库相关的内容。

我能想到的只是关注一些非端点"添加"登录Google"的方式到我的应用程序,然后尝试将我将获得的凭据传递给我的API构建器,但这只是感觉不对,就像应该有一个更简单的方法来做到这一点。

那么,我错过了一些步骤,https://cloud.google.com/appengine/docs/python/endpoints/consume_android#making_authenticated_calls中没有提到过吗?

下面的实际代码(稍微简化):

后端:

auth_api = endpoints.api(
    name='auth_api',
    version='v1.0',
    auth_level=endpoints.AUTH_LEVEL.REQUIRED,
    allowed_client_ids=[
        ANDROID_CLIENT_ID,
        WEB_CLIENT_ID,
        endpoints.API_EXPLORER_CLIENT_ID,
    ],
    audiences=[
        WEB_CLIENT_ID,
        endpoints.API_EXPLORER_CLIENT_ID,
    ],
    scopes=[
        'https://www.googleapis.com/auth/userinfo.profile',
        'https://www.googleapis.com/auth/userinfo.email',
    ],
)


@auth_api.api_class(resource_name='rating')
class RatingHandler(remote.Service):
    @endpoints.method(
        message_types.VoidMessage,
        RatingsMessage,
        path='rating/getRatings',
        http_method='GET',
    )
    def getRatings(self, request):
        rating_query = Rating.query(
            ancestor=ndb.Key(
                Account,
                endpoints.get_current_user().user_id(), // ERROR! endpoints.get_current_user() is None
            )
        ).order(-Rating.rating)

客户端:

// Somewhere these lines exist
if (credential == null || credential.getSelectedAccountName() == null) {
    startActivityForResult(
        AuthUtils.getCredentials(getActivity()).newChooseAccountIntent(),
        AuthUtils.REQUEST_ACCOUNT_PICKER
    );
} else {
    LoadRatings();
}

@Override
public void onActivityResult(
    int requestCode,
    int resultCode,
    Intent data
) {
    super.onActivityResult(requestCode, resultCode, data);
    if (data != null && data.getExtras() != null) {
        String accountName =
            data.getExtras().getString(
                AccountManager.KEY_ACCOUNT_NAME
            );
        if (accountName != null) {
            credential = GoogleAccountCredential.usingAudience(
                getApplicationContext(),
                "server:client_id:" + Constants.ANDROID_AUDIENCE
            );
            credential.setSelectedAccountName(accountName);
            LoadRatings();
        }
    }
}

public void LoadRatings() {
    // AuthApi was auto-generated by Google App Engine based on my Backend
    AuthApi.Builder api = new AuthApi.Builder(
        AndroidHttp.newCompatibleTransport(),
        new AndroidJsonFactory(),
        credential
    ).setApplicationName(getPackageName());
    AuthApi service = api.build();
    try {
        ApiMessagesRatingRatedBeerListMessage result = service.rating().getRatings().
        // some stuff done with result, but the Exception is thrown in line above

2 个答案:

答案 0 :(得分:2)

好的,我明白了。当我删除"范围"从API声明,它的工作原理。我还不确定如何访问用户的电子邮件/个人资料,但这至少是向前迈出的一步。

此问题实际上已经提出 - How to add more scopes in GoogleCloud Endpoints - 遗憾的是,没有任何答案

答案 1 :(得分:0)

您在为您创建的后端上没有User个对象(实体)。你必须自己做。例如:

@Entity
public class AppEngineUser {
    @Id
    private String email;
    private User user;
    private AppEngineUser() {}
    public AppEngineUser(User user) {
        this.user = user;
        this.email = user.getEmail();
    }
    public User getUser() {
        return user;
    }
    public Key<AppEngineUser> getKey() {
        return Key.create(AppEngineUser.class, email);
    }
}

创建API方法并指定User对象时,如下所示:

 @ApiMethod(name = "insertRecord", path = "insert_record", httpMethod = HttpMethod.POST)
    public Record insertRecord(User user,  Record record)

        // check if google user is authenticated
        throws UnauthorizedException {
        if (user == null) {
            throw new UnauthorizedException("Authorization required");
        }

        // user is authenticated... do some stuff!
}

User对象是注入类型。它实际上是:com.google.appengine.api.users.User。参见&#34;注入类型&#34;在https://cloud.google.com/appengine/docs/java/endpoints/paramreturn_types

这意味着,如果用户向其Google+帐户提供了正确的凭据,则GAE会注入Google用户对象。如果他们没有,则User将为空。如果是,您可以按照上述方法的方式抛出UnauthorizedException

如果user对象不为空,您现在可以获得用户的gmail地址等内容。从那里,您必须将这些值存储在您自己的自定义实体中,例如AppEngineUser并将其保存到数据存储区。然后你可以在以后用它做其他的事情,例如加载它,检查用户是否已经注册,以及其他任何你自己。

希望有所帮助!