gpt4 book ai didi

android - 如何将 GoogleAuthUtil.getToken 返回的 token 与我的 App Engine 后端一起使用

转载 作者:塔克拉玛干 更新时间:2023-11-02 09:06:51 25 4
gpt4 key购买 nike

我想做什么

我有一个简单的 Google App Engine 后端和一个简单的 Android 应用程序,我想从 Android 应用程序向服务器发出经过身份验证的请求。我阅读了有关 Google Cloud Endpoints 的文章,即使它是一个非常好的 API,我也觉得它对我想做的事情来说有点矫枉过正。我只想执行经过身份验证的 HTTP 请求并获取响应文本。

GET myappid.appspot.com/api/user

应该回答:

Hello john.doe

如果用户 john.doe@gmail.com 提出请求。

后端:

我创建了一个新的 App Engine 项目:

WEB_CLIENT_ID=123456789012.apps.googleusercontent.com

并注册了一个 Android 应用程序(“直接从 Android 访问 API”):

package name : com.myappid
debug SHA1 fingerprint: 3a:e1:05:17:15:54:c6:c7:9b:ef:19:74:ae:5b:f7:0f:c3:d5:45:9d

这创造了

ANDROID_CLIENT_ID=123456789012-9f4sd525df3254s3d5s40s441df705sd.apps.googleusercontent.com

应用.yaml

application: myappid
version: 1
runtime: python27
api_version: 1
threadsafe: true

handlers:
- url: /api/.*
secure: always
script: api.APP

libraries:
- name: webapp2
version: latest
- name: pycrypto
version: latest

接口(interface).py
import webapp2
from google.appengine.api import users
from google.appengine.api import oauth

class GetUser(webapp2.RequestHandler):

def get(self):
user = users.get_current_user()
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write('Hello, {}\n'.format('None' if user is None else user.nickname()))
try:
user = oauth.get_current_user()
self.response.out.write('Hello OAuth, {}\n'.format('None' if user is None else user.nickname()))
except Exception as e:
self.response.out.write(str(e)+'\n')

class SignIn(webapp2.RequestHandler):

def get(self):
if users.get_current_user() is None:
self.redirect(users.create_login_url(self.request.uri))

APP = webapp2.WSGIApplication([
('/api/user', GetUser),
('/api/signin', SignIn),
], debug = True)

安卓端

public class MainActivity extends Activity
{
private static final String CLIENT_ID = "123456789012.apps.googleusercontent.com";
private static final String SCOPE = "audience:server:client_id:" + CLIENT_ID;
private static final int AUTH_REQUEST_CODE = 1;
private Account mAccount;

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAccount = AccountManager.get(mActivity).getAccountsByType(GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE)[0];
new GetAuthToken().execute(mAccount.name);
}

protected void log(String msg) {
TextView tv = (TextView) mActivity.findViewById(R.id.textView);
tv.setText(tv.getText() + "\n" + msg);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == AUTH_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
new GetAuthToken().execute(mAccount.name);
}
}
}

private class GetAuthToken extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... params) {
try {
// Retrieve a token for the given account and scope. It will always return either
// a non-empty String or throw an exception.
String email = params[0];
String token = GoogleAuthUtil.getToken(mActivity, email, SCOPE);
return token;
} catch (GooglePlayServicesAvailabilityException playEx) {
Dialog alert = GooglePlayServicesUtil.getErrorDialog(playEx.getConnectionStatusCode(), mActivity, AUTH_REQUEST_CODE);
return "error - Play Services needed " + playEx;
} catch (UserRecoverableAuthException userAuthEx) {
// Start the user recoverable action using the intent returned by
// getIntent()
mActivity.startActivityForResult(userAuthEx.getIntent(), AUTH_REQUEST_CODE);
return "error - Autorization needed " + userAuthEx;
} catch (IOException transientEx) {
// network or server error, the call is expected to succeed if you try again later.
// Don't attempt to call again immediately - the request is likely to
// fail, you'll hit quotas or back-off.
return "error - Network error " + transientEx;
} catch (GoogleAuthException authEx) {
// Failure. The call is not expected to ever succeed so it should not be
// retried.
return "error - Other auth error " + authEx;
}
}

@Override
protected void onPostExecute(String result) {
if (result.startsWith("error -")) {
log(result);
} else {
log("Obtained token : " + result);
new GetAuthedUserName().execute(result);
}
}
}

private class GetAuthedUserName extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... params) {
try {
String token = params[0];
URL url = new URL("https://myappid.appspot.com/api/user");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//conn.setRequestProperty("Authorization", "Bearer " + token);
conn.addRequestProperty("Authorization", "OAuth " + token);
InputStream istream = conn.getInputStream();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(istream));
String line;
StringBuilder sb = new StringBuilder();
while ((line = reader.readLine()) != null) {
sb.append(line);
}
return sb.toString();
} catch (IOException e) {
return "error - Unable to read from the connection";
}
} catch (MalformedURLException e) {
return "error - Malformed URL " + e;
} catch (IOException e) {
return "error - IO error " + e;
}
}

@Override
protected void onPostExecute(String result) {
if (result.startsWith("error -")) {
log(result);
} else {
log("Request result : " + result);
}
}
}
}

什么有效

我可以使用我的浏览器,来

https://myappid.appspot.com/api/signin

以 John Doe 身份登录,然后

https://myappid.appspot.com/api/user

我明白了

Hello, john.doe

太棒了,这正是我所期望的。

什么不起作用

在 Android 上,我所有的尝试都是

Hello, None

正如您在 Android 代码中看到的那样,我使用 GoogleAuthUtil 来检索 token ,但我真的不明白我应该用它做什么。

String token = GoogleAuthUtil.getToken(mActivity, email, SCOPE);

然后我构建请求:

URL url = new URL("https://myappid.appspot.com/api/user");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();

并添加“授权” header :

conn.setRequestProperty("Authorization", "Bearer " + token);

我也试过:

conn.addRequestProperty("Authorization",  "OAuth " + token);

Android 或 App Engine 后端可能缺少某些东西,但我真的不明白是什么。有没有 API 可以简化这个?

用浏览器就这么简单...

TIA

最佳答案

可以将访问 token 发送到您的 Google App Engine 应用程序(或任何其他网络应用程序)(作为不记名 token ,这是转发凭据所需的全部)但是 Google App Engine 不会自动识别“Authorization" header 并为您设置用户对象(这是 Endpoints 可以帮助您的事情)。

您可以选择通过请求 header 对象自行查找访问 token :

access_token = self.request.headers['Authorization']

然后将其发送到 Google API 以验证它是否有效并获取有关该用户的信息(我认为这包括电子邮件,只要电子邮件是您最初为其请求访问 token 的范围)。

参见 Get user info via Google API有关如何执行此操作的详细信息。

您还应该检查访问 token 是否已颁发给您的应用程序(https://www.googleapis.com/oauth2/v1/tokeninfo?access_token= {access_token} - 验证响应中的客户端 ID)- 如果您不这样做,那么其他获得许可的应用程序就很容易用户获取访问 token 以针对您的私有(private) API 进行调用。

总而言之,另一种机制是从 Android 获取 IDToken,并将其发送到您的 Web 应用程序 - 可以在此处找到更多详细信息: http://googledevelopers.blogspot.com/2013/05/cross-platform-sso-technology.htmlhttps://developers.google.com/accounts/docs/CrossClientAuth

显示使用 Google API Python 客户端获取有关已发行 token 的信息的示例:

from apiclient.discovery import build
print build('oauth2', 'v1').tokeninfo(access_token=access_token).execute()

# Result
{
'issued_to': 'xxxxxx.apps.googleusercontent.com',
'user_id': 'yyyyyy',
'expires_in': 3457,
'access_type': 'online',
'audience': 'xxxxxx.apps.googleusercontent.com',
'scope': 'https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile',
'email': 'xxxxx@yyyyy.com',
'verified_email': True
}

关于android - 如何将 GoogleAuthUtil.getToken 返回的 token 与我的 App Engine 后端一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20660845/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com