【问题标题】:GoogleJsonResponseException: 401 Unauthorized calling endpoint with OAuth2 protectionGoogleJsonResponseException:401 具有 OAuth2 保护的未经授权的调用端点
【发布时间】:2014-12-21 18:15:03
【问题描述】:

我正在尝试制作一个使用 App Engine 作为移动后端的 Android 应用。 当我尝试调用受身份验证保护的端点时出现此错误:

12-21 18:58:05.120    4452-4477/com.test.myapplication W/System.err﹕ com.google.api.client.googleapis.json.GoogleJsonResponseException: 401 Unauthorized
12-21 18:58:05.120    4452-4477/com.test.myapplication W/System.err﹕ {
12-21 18:58:05.130    4452-4477/com.test.myapplication W/System.err﹕ {
12-21 18:58:05.130    4452-4477/com.test.myapplication W/System.err﹕ "domain": "global",
12-21 18:58:05.130    4452-4477/com.test.myapplication W/System.err﹕ "location": "Authorization",
12-21 18:58:05.130    4452-4477/com.test.myapplication W/System.err﹕ "locationType": "header",
12-21 18:58:05.130    4452-4477/com.test.myapplication W/System.err﹕ "message": "Authorization required",
12-21 18:58:05.130    4452-4477/com.test.myapplication W/System.err﹕ "reason": "required"
12-21 18:58:05.130    4452-4477/com.test.myapplication W/System.err﹕ }
12-21 18:58:05.130    4452-4477/com.test.myapplication W/System.err﹕ ],
12-21 18:58:05.130    4452-4477/com.test.myapplication W/System.err﹕ "message": "Authorization required"
12-21 18:58:05.130    4452-4477/com.test.myapplication W/System.err﹕ }
12-21 18:58:05.130    4452-4477/com.test.myapplication W/System.err﹕ at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
12-21 18:58:05.130    4452-4477/com.test.myapplication W/System.err﹕ at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
12-21 18:58:05.130    4452-4477/com.test.myapplication W/System.err﹕ at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:312)

这是 App Engine 上的端点代码

@ApiMethod(
        name = "signInWithGoogle",
        path = "signInWithGoogle",
        httpMethod = ApiMethod.HttpMethod.POST
)
public Profile signInWithGoogle(final User user) throws UnauthorizedException {
    if (user == null) {
        throw new UnauthorizedException("Authorization required");
    }
    Key<Profile> profileKey = Key.create(Profile.class, user.getEmail());
    return OfyService.ofy().load().key(profileKey).now();
}

这里是调用端点的活动代码

public class MainActivity extends Activity {

public static final String WEB_CLIENT_ID = "XXXX.apps.googleusercontent.com";
public static final String AUDIENCE = "server:client_id:" + WEB_CLIENT_ID;
protected static final HttpTransport HTTP_TRANSPORT = AndroidHttp.newCompatibleTransport();
protected static final JsonFactory JSON_FACTORY = new AndroidJsonFactory();

GoogleAccountCredential credential;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    credential = GoogleAccountCredential.usingAudience(this, AUDIENCE);

    startActivityForResult(credential.newChooseAccountIntent(), 0);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    String accountName = data.getExtras().getString(AccountManager.KEY_ACCOUNT_NAME);
    credential.setSelectedAccountName(accountName);
    final SignUser signUser = new SignUser.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).build();
    Log.d("TEST", "start");
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                Profile profile = signUser.signInWithGoogle().execute();
                Log.d("TEST", "success");
            } catch (IOException e) {
                e.printStackTrace();
                Log.d("TEST", "failed");
            }
        }
    }).start();
}
}

似乎signUser.signInWithGoogle().execute() 没有创建端点需要的用户对象,因此,端点抛出了 UnauthorizedException。 实际上,如果我从端点移除 OAuth2 保护,一切正常。

谁能解释一下错误是什么?

更新

这里是java类的@Api注解

@Api(
    name = "signUser",
    version = "v1",
    scopes = {Constants.EMAIL_SCOPE},
    clientIds = {Constants.ANDROID_CLIENT_ID, Constants.API_EXPLORER_CLIENT_ID},
    audiences = {Constants.ANDROID_AUDIENCE},
    description = "APIs for sign user"
)

EMAIL_SCOPEhttps://www.googleapis.com/auth/userinfo.email ANDROID_AUDIENCE 等于 WEB_CLIENT_ID

【问题讨论】:

  • 您确定 accountName 设置为有效的 gmail 地址吗?
  • 是的,我登录 accountName 只是为了确定。
  • 所以你的端点定义可能有问题。能否请您发布@Api 注释的内容?
  • 用@Api注解代码更新的问题。但是,使用 api explorer 似乎一切正常。
  • 为什么WEB_CLIENT_ID 不包含在clientIds 中?这可能是问题所在。

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


【解决方案1】:

我已经通过像这样为凭证对象设置自定义请求初始化程序来解决这个问题

GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(this.TRANSPORT).setJsonFactory(this.JSON_FACTORY)
.setClientSecrets(Constants.CLIENT_ID,     Constants.CLIENT_SECRET).setRequestInitializer((new HttpRequestInitializer(){
            @Override
            public void initialize(HttpRequest request)
                    throws IOException {
                request.getHeaders().put("Authorization", "Bearer " + accessToken);
            }
        })).build()

【讨论】:

  • Hardik,你能更好地解释你的代码吗? accessToken 来自哪里? "Bearer " 字符串是干什么用的?如何设置帐号名称?
  • Google 的文档规定了以下内容:** 例如,使用 access_token 查询字符串参数调用 UserInfo API 如下所示: GET googleapis.com/oauth2/v1/userinfo?access_token={accessToken} 使用相同的 API 调用HTTP 标头中的访问令牌如下所示: GET /oauth2/v1/userinfo HTTP/1.1 授权:Bearer {accessToken} 主机:googleapis.com** 希望这会对您有所帮助
  • 能否请您粘贴该文档的链接?谢谢。
猜你喜欢
  • 2018-02-04
  • 1970-01-01
  • 2021-10-01
  • 2019-02-01
  • 2019-08-09
  • 2017-03-17
  • 2017-11-10
  • 1970-01-01
  • 2017-10-18
相关资源
最近更新 更多