gpt4 book ai didi

android - 使用 android GoogleSignInApi 凭据执行 google Sheets api 访问

转载 作者:行者123 更新时间:2023-12-02 15:12:15 36 4
gpt4 key购买 nike

我知道有几篇文章讨论 Android 的登录/oauth,但没有一个能解决我的问题。

我正在努力使用 Google Sheets v4 教程中的 AccountManager 来协调 GoogleSignInApi 的身份验证流程。

使用 GoogleSignInApi 我最终得到了一个授权码。到目前为止,一切都很好。接下来,文档建议将授权码交换为授权 token /恢复 token 。 https://developers.google.com/identity/sign-in/android/offline-access有一个很好的示例,说明如何将身份验证代码发送到后端进行交换。

此流程的唯一问题 - 我没有自己的后端,因为我只想访问 google Sheets api。 Sheets api 调用需要一个 GoogleCredential 对象,我无法从授权码或其他方式通过 GoogleSignInAccount 对象获取该对象。

所以,我的问题:

  1. 我可以将通过 GoogleSignInApi 收到的授权码发送到哪里将其交换为 authtoken。
  2. 是否有一个库可以处理交换请求和刷新魔法还是我期望捕获刷新 token 并发出另一个我自己请求身份验证 token 。
  3. 有没有更好的方法来获取工作表的正确凭据访问的同时还使用 GoogleSignInApi for firebase 服务?
  4. 如果我最终按照建议使用 GoogleAuthorizationCodeTokenRequest对于服务器端访问,在以下位置使用客户端 secret 是否可以接受客户端?可能不会。

这是我尝试进行的 Sheets API 调用的简化版本。

GoogleCredential credential = new GoogleCredential().setAccessToken("TEST_ACCESS_TOKEN_FROM_OAUTH_PLAYGROUND");

mService = new com.google.api.services.sheets.v4.Sheets.Builder(
transport, jsonFactory, credential)
.setApplicationName("Google Sheets API Android Quickstart")
.build();

更新:为了取得一些进展,我最终实现了服务器端流程来交换 token 。我很确定,这不是正确的技术,因为它需要在应用程序中使用 client_secret。

第 1 部分:SignInActivity 基于 firebase 代码实验室。我需要一个 firebase 帐户,所以我觉得我必须使用 GoogleSignInApi。

public class SignInActivity extends AppCompatActivity implements GoogleApiClient.OnConnectionFailedListener,
View.OnClickListener {


private static final int RC_SIGN_IN = 9001;

private GoogleApiClient mGoogleApiClient;
private FirebaseAuth mFirebaseAuth;

public static final String PREF_ACCOUNT_NAME = "accountName";
public static final String PREF_ID_TOKEN = "idToken";
public static final String PREF_AUTH_CODE = "authCode";

public static final Scope SHEETS_SCOPE = new Scope(SheetsScopes.SPREADSHEETS);

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

SignInButton signInButton = (SignInButton) findViewById(R.id.sign_in_button);
signInButton.setOnClickListener(this);

Log.d(TAG, getString(R.string.default_web_client_id));

GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestScopes(SHEETS_SCOPE)
.requestServerAuthCode(getString(R.string.default_web_client_id))
.requestEmail()
.build();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();

// Initialize FirebaseAuth
mFirebaseAuth = FirebaseAuth.getInstance();
}

private void handleFirebaseAuthResult(AuthResult authResult) {
// ...
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.sign_in_button:
signIn();
break;
default:
return;
}
}

private void signIn() {
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, RC_SIGN_IN);
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

// Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
if (requestCode == RC_SIGN_IN) {
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
if (result.isSuccess()) {
// Google Sign In was successful, authenticate with Firebase
GoogleSignInAccount account = result.getSignInAccount();

SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this.getApplicationContext());
SharedPreferences.Editor editor = prefs.edit();
editor.putString(PREF_ACCOUNT_NAME, account.getEmail());
editor.putString(PREF_ID_TOKEN, account.getIdToken());
editor.putString(PREF_AUTH_CODE, account.getServerAuthCode());
editor.apply();

// TODO: it would be great to do the exchange of the authcode now but it's doing a
// network call and can't be on the main thread.

// I really need this one
firebaseAuthWithGoogle(account);
} else {
// Google Sign In failed
Log.e(TAG, "Google Sign In failed.");
}
}
}

private void firebaseAuthWithGoogle(GoogleSignInAccount acct) {
Log.d(TAG, "firebaseAuthWithGoogle:" + acct.getId());
AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), null);
mFirebaseAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful());

// If sign in fails, display a message to the user. If sign in succeeds
// the auth state listener will be notified and logic to handle the
// signed in user can be handled in the listener.
if (!task.isSuccessful()) {
Log.w(TAG, "signInWithCredential", task.getException());
Toast.makeText(SignInActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
} else {
startActivity(new Intent(SignInActivity.this, MainActivity.class));
finish();
}
}
});
}

@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
// An unresolvable error has occurred and Google APIs (including Sign-In) will not
// be available.
Log.d(TAG, "onConnectionFailed:" + connectionResult);
Toast.makeText(this, "Google Play Services error.", Toast.LENGTH_SHORT).show();
}
}

第 2 部分:DataManager 是一个实用程序类,应用程序使用它来访问工作表数据。它不使用工作表代码实验室中推荐的流程,因为该流程不允许我使用相同的用户数据设置 firebase 帐户。

public class DataManager {

public static final String UNDEF = "undefined";

private com.google.api.services.sheets.v4.Sheets mService = null;
// this is the play copy
private static String mSheetID = SHEET_ID;

private static final String PREF_ACCESS_TOKEN = "accessToken";
private static final String PREF_REFRESH_TOKEN = "refreshToken";
private static final String PREF_EXPIRES_IN_SECONDS = "expiresInSec";

private Context mContext;
private String mAccessToken;
private String mRefreshToken;
private Long mExpiresInSeconds;
private String mAuthCode;

public DataManager(Context context) {
mContext = context;

SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
mAuthCode = prefs.getString(SignInActivity.PREF_AUTH_CODE, UNDEF);
mAccessToken = prefs.getString(PREF_ACCESS_TOKEN, UNDEF);
mRefreshToken = prefs.getString(PREF_REFRESH_TOKEN, UNDEF);
mExpiresInSeconds = prefs.getLong(PREF_EXPIRES_IN_SECONDS, 0);
}

private void exchangeCodeForToken(String authCode) {

try {
GoogleTokenResponse tokenResponse =
new GoogleAuthorizationCodeTokenRequest(
new NetHttpTransport(),
JacksonFactory.getDefaultInstance(),
"https://www.googleapis.com/oauth2/v4/token",
mContext.getString(R.string.default_web_client_id),
// TODO: the app shouldn't have to use the client secret
{CLIENT_SECRET},
authCode,
"")
.execute();

mAccessToken = tokenResponse.getAccessToken();
mRefreshToken = tokenResponse.getRefreshToken();
mExpiresInSeconds = tokenResponse.getExpiresInSeconds();

// TODO: do I really need to store and pass the three values individually?
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
SharedPreferences.Editor editor = prefs.edit();
editor.putString(PREF_ACCESS_TOKEN, mAccessToken);
editor.putString(PREF_REFRESH_TOKEN, mRefreshToken);
editor.putLong(PREF_EXPIRES_IN_SECONDS, mExpiresInSeconds);
editor.remove(SignInActivity.PREF_AUTH_CODE);
editor.apply();

} catch (Exception e) {
Log.e(TAG, "Token exchange failed with " + e.getMessage());
}
}

private void refreshAccessToken(String refreshToken) {
try {
// TODO: what to do here?
throw new Exception("TBD");
} catch (Exception e) {
Log.e(TAG, "Token refresh failed with " + e.getMessage());
}
}

private GoogleCredential getCredential() {

if (mAuthCode != UNDEF) {
exchangeCodeForToken(mAuthCode);
}

// TODO: handle missing or expired token
if (mRefreshToken != UNDEF && mExpiresInSeconds < 30) {
refreshAccessToken(mRefreshToken);
}

GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(new NetHttpTransport())
.setJsonFactory(JacksonFactory.getDefaultInstance())
.build();
credential.setAccessToken(mAccessToken);
if (mRefreshToken != UNDEF) {
credential.setRefreshToken(mRefreshToken);
credential.setExpiresInSeconds(mExpiresInSeconds);
}

return credential;
}

// Set up credential and service object, then issue api call.
public ArrayList<Foo> getFooListFromServer() throws IOException {
try {
GoogleCredential credential = getCredential();

HttpTransport transport = AndroidHttp.newCompatibleTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
mService = new com.google.api.services.sheets.v4.Sheets.Builder(
transport, jsonFactory, credential)
.setApplicationName(mContext.getString(R.string.app_name))
.build();

return getDataFromServer();
} catch (IOException exception) {
// ...
throw exception;
} catch (Exception e) {
Log.e(TAG, "something else is going on " + e.toString());
throw e;
}
}

/**
* Actually fetch the data from google
*
* @return List of Foos
* @throws IOException
*/
private ArrayList<Foo> getDataFromServer() throws IOException {

ArrayList<Foo> foos = new ArrayList<Foo>();

ValueRange response = this.mService.spreadsheets().values()
.get(mSheetID, mRange)
.setValueRenderOption("UNFORMATTED_VALUE")
.setDateTimeRenderOption("FORMATTED_STRING")
.execute();
//...
return foos;
}
}

最佳答案

如果您使用Android Quickstart for Sheets API,您的凭据问题将很容易避免。 .

以下是指南中提到的步骤:

Step 1: Acquire a SHA1 fingerprint
Step 2: Turn on the Google Sheets API
Step 3: Create a new Android project
Step 4: Prepare the project
Step 5: Setup the sample

OAuth 客户端 ID 可在 Google Dev Console 中找到.

关于android - 使用 android GoogleSignInApi 凭据执行 google Sheets api 访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40719389/

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