我正在开发一个可直接连接到Google Books API的android应用。其工作的一部分还在于获取用户的私人图书数据。 (例如书架)
我使用Android的Google登录进行身份验证。但是,我也需要访问令牌来获得请求的授权。
问题:-
Google登录在处理身份验证部分方面做得很好,但是由于它没有提供任何方法,因此我不得不实施授权部分。以下是我想出授权的有效解决方案。
问:我当前的解决方案(如下所示)是否可以(如果不是首选方式)来获取访问令牌?
当前解决方案:-
首先,我使用requestServerAuthCode(...)
方法请求授权代码并传递了Web应用客户端ID(由Google API控制台自动为Google登录创建的:-]
...
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestScopes(new Scope(SCOPE_BOOKS))
.requestServerAuthCode(WEB_APP_CLIENT_ID) //NOTE: this was auto generated for Google Sign-in along with my android client id.
.requestEmail()
.build();
...
然后,我使用接收到的身份验证令牌(通过调用getServerAuthCode()
)并使用它来手动获取访问令牌,
MainActivity.java
...
Task<GoogleSignInAccount> accountTask = GoogleSignIn.getSignedInAccountFromIntent(data);
GoogleSignInAccount account = accountTask.getResult(ApiException.class);
new TokenTask().execute(account.getServerAuthCode());
...
TokenTask.java
@Override
protected String doInBackground(String... authToken) {
//Time to get the access token from the authToken
...
final URL url = new URL("https://www.googleapis.com/oauth2/v4/token");
conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod("POST");
...
final StringBuilder b = new StringBuilder();
b.append("code=").append(authToken[0]).append('&')
.append("client_id=").append(WEB_APP_CLIENT_ID).append('&') //NOTE: this client id was auto generated for Google Sign-in along with my android client id.
.append("client_secret=").append(WEB_APP_CLIENT_SECRET).append('&')
.append("redirect_uri=").append("").append('&')
.append("grant_type=").append("authorization_code");
final byte[] postData = b.toString().getBytes(StandardCharsets.UTF_8);
os = conn.getOutputStream();
os.write(postData);
/*
The response contains fields such as: access_token, expires_in, refresh_token etc...
*/
final int responseCode = conn.getResponseCode();
if (200 <= responseCode && responseCode <= 299) {
is = conn.getInputStream();
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
} else {
Log.d("Error:", conn.getResponseMessage());
return null;
}
b.setLength(0);
String output;
while ((output = br.readLine()) != null) {
b.append(output);
}
final JSONObject jsonResponse = new JSONObject(b.toString());
String mAccessToken = jsonResponse.getString("access_token");
注:-
我从here获得了有关此解决方案的想法。尽管传递到requestServerAuthCode(...)
的Web客户端ID应该是我们服务器端应用的客户端ID。但由于我没有任何网络应用程序,因此我使用由Google api控制台自动生成的网络客户端ID进行Google登录(在上面的代码中声明为WEB_APP_CLIENT_ID)。
这些天,您应该在移动应用中使用授权码流(PKCE),作为recommended by Google。在登录时提供code_challenge而不是在交换令牌的授权码时提供code_verifier,而不是客户机密。
出于兴趣,我的Android Blog Post显示了一些带有上述参数的示例消息。它还有一个可以运行的代码示例,以及有关用户体验和令牌存储的一些内容。