每次用户登录时,Google 登录都使用相同的帐户
Posted
技术标签:
【中文标题】每次用户登录时,Google 登录都使用相同的帐户【英文标题】:Google login uses same account everytime users login 【发布时间】:2016-08-08 04:05:48 【问题描述】:我使用 OAuth 让用户通过 Google 帐户登录到 android 应用。当用户第一次点击 Google 登录按钮时,它会产生一个对话框来选择帐户。同样,当用户退出并决定使用不同的 Google 帐户登录时,它不会提示选择帐户,它会登录用户之前选择的帐户
'
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
initialize();
Firebase.setAndroidContext(this);
ref=new Firebase("https://texter10c.firebaseio.com");
loginButton.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
progressDialog.setMessage("Logging in !");
progressDialog.setTitle("Hang on!");
progressDialog.show();
ref.authWithPassword(emailField.getText().toString(), passwordField.getText().toString(), new Firebase.AuthResultHandler()
@Override
public void onAuthenticated(AuthData authData)
Log.e("Authenticated","Authenticated");
getUserIdandLogin();
@Override
public void onAuthenticationError(FirebaseError firebaseError)
progressDialog.dismiss();
Toast.makeText(LoginActivity.this, firebaseError.getMessage(), Toast.LENGTH_SHORT).show();
);
);
signupButton.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
Intent intent = new Intent(LoginActivity.this, SignupActivity.class);
startActivity(intent);
);
googleSignInButton.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
progressDialog.setTitle("Contacting Google");
progressDialog.setMessage("Logging you in");
progressDialog.show();
if(!mGoogleApiClient.isConnected())
mGoogleApiClient.connect();
);
private void getGoogleToken()
AsyncTask<Void,Void,String> task=new AsyncTask<Void, Void, String>()
@Override
protected String doInBackground(Void... params)
final String scopes="oauth2:"+"https://www.googleapis.com/auth/plus.login"+" "+"https://www.googleapis.com/auth/plus.me";
try
if(!mGoogleApiClient.isConnected())
mGoogleApiClient.connect();
googleAccessToken= GoogleAuthUtil.getToken(LoginActivity.this,Plus.AccountApi.getAccountName(mGoogleApiClient),scopes);
Log.e("AccessToken",googleAccessToken+"");
catch (IOException e)
e.printStackTrace();
catch (GoogleAuthException e)
e.printStackTrace();
return null;
@Override
protected void onPostExecute(String s)
super.onPostExecute(s);
try
ref.authWithOAuthToken("google", googleAccessToken, new Firebase.AuthResultHandler()
@Override
public void onAuthenticated(final AuthData authData)
try
Log.e("Firebase", "Google Authentication Success");
Log.e("Username", authData.getProviderData().get("displayName").toString());
Log.e("Id", authData.getProviderData().get("id").toString());
Firebase googleUserRef = ref.child("UserDetails/names/" + authData.getProviderData().get("id").toString());
Map<String, String> googleUserMap = new HashMap<String, String>();
googleUserMap.put("Username", authData.getProviderData().get("displayName").toString());
final String UserID = "GoogleUser" + authData.getProviderData().get("displayName") + authData.getProviderData().get("id");
googleUserMap.put("UserId", UserID);
googleUserRef.setValue(googleUserMap, new Firebase.CompletionListener()
@Override
public void onComplete(FirebaseError firebaseError, Firebase firebase)
progressDialog.dismiss();
dataStore.setCurrentUserName(authData.getProviderData().get("displayName").toString());
dataStore.setCurrentUserID(UserID);
storeDatainSharedPreferences();
Intent intent = new Intent(LoginActivity.this, DialogActivity.class);
startActivity(intent);
);
catch (NullPointerException e)
e.printStackTrace();
@Override
public void onAuthenticationError(FirebaseError firebaseError)
Log.e("GogoleAuthFailed", firebaseError.getMessage());
);
catch (NullPointerException e)
Log.e("Accesstoken problem",e.getMessage());
;
task.execute();
public void getUserIdandLogin()
dataStore.userDialogMap=new ArrayList<Map<String,String>>();
dataStore.generatedChatIds=new ArrayList<>();
Firebase refUser=ref.child("UserDetails/names");
refUser.addChildEventListener(new ChildEventListener()
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s)
Map<String, String> map = new HashMap<String, String>();
map = dataSnapshot.getValue(Map.class);
try
if (map.get("Email").equals(emailField.getText().toString()))
Toast.makeText(LoginActivity.this, "Successfilly Logged in", Toast.LENGTH_SHORT).show();
dataStore.setCurrentUserName(map.get("Username"));
dataStore.setCurrentUserID(map.get("UserId"));
intent=new Intent(LoginActivity.this,DialogActivity.class);
startActivity(intent);
storeDatainSharedPreferences();
progressDialog.dismiss();
catch (NullPointerException e)
Log.e("NullPointerGUser",e.getMessage());
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s)
@Override
public void onChildRemoved(DataSnapshot dataSnapshot)
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s)
@Override
public void onCancelled(FirebaseError firebaseError)
);
private void storeDatainSharedPreferences()
try
SharedPreferences.Editor editor = getSharedPreferences(NEW_PREFS, MODE_PRIVATE).edit();
editor.putString("CurrentUsername", dataStore.getCurrentUserName());
editor.putString("CurrentUserId", dataStore.getCurrentUserID());
editor.commit();
catch (NoSuchElementException e)
new AlertDialog.Builder(LoginActivity.this).setMessage("There was an error whil logging in")
.setTitle("Little Problem here!").setPositiveButton("Retry", new DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int which)
Intent intent=new Intent(LoginActivity.this,LoginActivity.class);
removeDatainSharedPreferences();
mGoogleApiClient.disconnect();
startActivity(intent);
).show();
private void removeDatainSharedPreferences()
SharedPreferences.Editor editor = getSharedPreferences(NEW_PREFS, MODE_PRIVATE).edit();
editor.remove("CurrentUsername");
editor.remove("CurrentUserId");
editor.commit();
private void initialize()
emailInputLayout=(TextInputLayout)findViewById(R.id.emailInputLayout);
emailField=(EditText)findViewById(R.id.emailField);
passwordField=(EditText)findViewById(R.id.passwordField);
passwordInputLayout=(TextInputLayout)findViewById(R.id.passwordInputLayout);
loginButton=(Button)findViewById(R.id.loginButton);
emailInputLayout.setHint("Email");
passwordInputLayout.setHint("Password");
progressDialog=new ProgressDialog(LoginActivity.this);
signupButton=(TextView)findViewById(R.id.signupButton);
forgotPasswordButton=(TextView)findViewById(R.id.forgotPasswordField);
googleSignInButton=(SignInButton)findViewById(R.id.googleSignInButton);
googleSignInButton.setColorScheme(SignInButton.COLOR_AUTO);
forgotPasswordButton.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
Intent intent=new Intent(LoginActivity.this,ForgotPasswordActivity.class);
startActivity(intent);
);
SharedPreferences sharePreferences=getSharedPreferences(NEW_PREFS,MODE_PRIVATE);
if(!sharePreferences.getString("CurrentUsername","null").equals("null"))
Log.e("SharedPreferences", sharePreferences.getString("CurrentUsername", "null"));
Log.e("SharedPreferences",sharePreferences.getString("CurrentUserId",null));
Intent intent=new Intent(LoginActivity.this,DialogActivity.class);
startActivity(intent);
mGoogleApiClient=new GoogleApiClient.Builder(this)
.addApi(Plus.API)
.addScope(Plus.SCOPE_PLUS_LOGIN)
.addScope(Plus.SCOPE_PLUS_PROFILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
if(!isNetworkAvailable())
snackbar=Snackbar.make(findViewById(android.R.id.content),"You are offline",Snackbar.LENGTH_INDEFINITE)
.setAction("Retry", new View.OnClickListener()
@Override
public void onClick(View v)
if(!isNetworkAvailable())
dismissSnackBar();
else
snackbar.show();
);
snackbar.show();
private void dismissSnackBar()
snackbar.dismiss();
private boolean isNetworkAvailable()
ConnectivityManager manager=(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkIngo=manager.getActiveNetworkInfo();
return networkIngo!=null&& networkIngo.isConnected();
@Override
public void onConnected(@Nullable Bundle bundle)
Log.e("GoogleApi","Connected");
getGoogleToken();
@Override
public void onConnectionSuspended(int i)
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult)
Log.e("GoogleApi",connectionResult.toString());
if(!connectionResult.hasResolution())
GooglePlayServicesUtil.getErrorDialog(connectionResult.getErrorCode(),LoginActivity.this,0).show();
if(connectionResult.isSuccess())
getGoogleToken();
try
connectionResult.startResolutionForResult(this,100);
catch (IntentSender.SendIntentException e)
e.printStackTrace();
`
【问题讨论】:
粘贴相关代码以便我们帮忙! 很好!给我一分钟! 在获得登录详细信息后立即断开mGoogleApiClient
。因为你不再需要它了。
它不起作用.. 下次我尝试登录时它使用相同的帐户。只有当我清除设置中的缓存数据时,它才会提示选择帐户。
您需要明确注销您的用户。
【参考方案1】:
使用以下方式注销您的用户:
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>()
@Override
public void onResult(Status status)
// ...
);
【讨论】:
【参考方案2】:如果您有任何注销功能。将以下代码放在您的注销代码之前:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1)
CookieManager.getInstance().removeAllCookies(null);
CookieManager.getInstance().flush();
else
CookieSyncManager cookieSyncMngr=CookieSyncManager.createInstance(activity);
cookieSyncMngr.startSync();
CookieManager cookieManager=CookieManager.getInstance();
cookieManager.removeAllCookie();
cookieManager.removeSessionCookie();
cookieSyncMngr.stopSync();
cookieSyncMngr.sync();
希望这会有所帮助。
编辑:您也可以尝试用以下代码替换
storeDatainSharedPreferences
方法:
private void storeDatainSharedPreferences()
try
SharedPreferences.Editor editor = getSharedPreferences(NEW_PREFS, MODE_PRIVATE).edit();
editor.putString("CurrentUsername", dataStore.getCurrentUserName());
editor.putString("CurrentUserId", dataStore.getCurrentUserID());
editor.commit();
if(mGoogleApiClient!=null)
mGoogleApiClient.disconnect();
catch (NoSuchElementException e)
new AlertDialog.Builder(LoginActivity.this).setMessage("There was an error whil logging in")
.setTitle("Little Problem here!").setPositiveButton("Retry", new DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int which)
Intent intent=new Intent(LoginActivity.this,LoginActivity.class);
removeDatainSharedPreferences();
mGoogleApiClient.disconnect();
startActivity(intent);
).show();
解释:对于第一个解决方案:这是清除所有Cookie的代码 与您的应用程序相关。这对您的情况很有帮助 因为你想清除以前可能存储的数据 饼干。
说明:对于第二种解决方案:它是断开 mGoogleApiClient 的代码。这将很有帮助,因为您已将数据存储在 sharedPref 中,现在您不需要
mGoogleApiClient
。
【讨论】:
【参考方案3】:最简单的方法是在处理完结果 (onActivityResult) 后注销客户端。只需确保在触发注销之前客户端已连接。这是我的代码的 sn-p:
private void handleGoogleLoginResult(Intent data)
if (data != null)
// get result from data received
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
int statusCode = result.getStatus().getStatusCode();
if (result.isSuccess() && result.getSignInAccount() != null)
// Signed in successfully
// logout
if (mGoogleApiClient != null && mGoogleApiClient.isConnected())
Auth.GoogleSignInApi.signOut(mGoogleApiClient);
【讨论】:
【参考方案4】:我在使用 javascript 客户端搜索解决方案时发现了这个问题,但它可能与 Android 类似。
signIn( prompt: 'select_account' )
select_account
授权服务器提示用户选择一个 Google 帐户。这允许拥有多个帐户的用户在他们可能拥有当前会话的多个帐户中进行选择。
见https://developers.google.com/identity/sign-in/web/reference#googleauthsigninoptions。
【讨论】:
【参考方案5】:您不会通过注销用户来撤销用户,请使用以下内容来实现您的需要:
将此代码放入任何活动中并在退出按钮单击时调用它:
private void signOut()
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>()
@Override
public void onResult(Status status)
// ...
);
写在onCreate()
:
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API)
.build();
在onStart()
中覆盖它:
@Override
protected void onStart()
super.onStart();
mGoogleApiClient.connect();
参考链接:Google Developer Page
【讨论】:
【参考方案6】:对我来说简单的锻炼
1>Activity implements GoogleApiClient.OnConnectionFailedListener
2>
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
3>在 OnButtonClicked 中
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, 2);
4>
protected void onActivityResult(int requestCode, int resultCode, Intent data)
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 2)
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
if (result.isSuccess())
GoogleSignInAccount acct = result.getSignInAccount();
if(acct!=null)
//Take all data You Want
String identifier = acct.getId()+"";
String displayName = acct.getDisplayName()+"";
//After You got your data add this to clear the priviously selected mail
mGoogleApiClient.clearDefaultAccountAndReconnect();
else Log.e("handleSignInResult","Failed ; "+result.getStatus());
【讨论】:
工作就像一个魅力。我刚刚添加了“mGoogleApiClient.clearDefaultAccountAndReconnect();”在获得 Firebase 用户并且它正在工作之后。 不适用于 lib 版本 11.8.0。与java.lang.IllegalStateException: GoogleApiClient is not connected yet.
崩溃。【参考方案7】:
只需在从 Intent 获取数据后添加此 signIn()
方法即可。
Intent signInIntent=Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
mGoogleApiClient.clearDefaultAccountAndReconnect();
【讨论】:
稍微解释一下就好了。 @J..S - 我也不清楚为什么,但是在看到它起作用后,我理解的解释是:一旦你有了 firebase 用户,你就是在告诉 GoogleApiClient 它当它返回再次进行身份验证时,不应使用任何默认值。除了 Javadoc 之外,我在 GoogleApiClient 上找不到太多教程/示例 :( - 这节省了时间,谢谢! 获取firebase用户后,如果我调用这个方法,它会以java.lang.IllegalStateException: GoogleApiClient is not connected yet.
崩溃。我正在使用 lib 版本 11.8.0。
getting error "* 无连接客户端不支持该方法。支持无连接客户端的API不得调用该方法。"【参考方案8】:
无需调用 SignOut
那些在 kotlin 中需要它的人,这对我有用,我会在发出新的登录请求之前清除当前登录缓存
/**
* signInGoogle
*/
private fun signInGoogle() = launch(Dispatchers.IO)
//init google sigin
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(GOOGLE_WEBCLIENT_ID)
.requestEmail()
.build()
val gApiClient = GoogleApiClient.Builder(activity)
.addApi(Auth.GOOGLE_SIGN_IN_API,gso)
.build()
val c = gApiClient.blockingConnect()
if(c.isSuccess && gApiClient.isConnected)
gApiClient.clearDefaultAccountAndReconnect().await()
val mGoogleSignInClient = GoogleSignIn.getClient(activity, gso)
val signInIntent = mGoogleSignInClient.signInIntent
launch (Dispatchers.Main)
// IN MAIN THREAD
startActivityForResult(signInIntent, GOOGLE_SIGNIN)
.start()
//start activity
//end request google login
你可以在这里查看完整的源代码:https://github.com/transcodium/TNSMoney-Android/blob/master/app/src/main/java/com/transcodium/tnsmoney/SocialLoginActivity.kt
Java 用户:
/**
* signInGoogle
*/
private void signInGoogle()
new Thread(new Runnable()
@Override
public void run()
//init google sigin
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id)) // required to get accesstoken
.requestEmail()
.build();
GoogleApiClient gApiClient = new GoogleApiClient.Builder(activity)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
ConnectionResult c = gApiClient.blockingConnect();
if (c.isSuccess() && gApiClient.isConnected())
gApiClient.clearDefaultAccountAndReconnect().await();
GoogleSignInClient mGoogleSignInClient = GoogleSignIn.getClient(activity, gso);
Intent signInIntent = mGoogleSignInClient.getSignInIntent();
getActivity().runOnUiThread(new Runnable()
@Override
public void run()
//start activit
getActivity().startActivityForResult(signInIntent, RC_SIGN_IN);
);
).start();
//end request google login
【讨论】:
java.lang.IllegalStateException:不能在 UI 线程上调用blockingConnect。我遇到了这个异常! 这对我有用!因为我想实现切换帐户功能,并且由于注销,令牌被清除,所以我无法使用它。但这有效。谢谢【参考方案9】:您需要从谷歌客户端注销用户。
public void signOut()
mAuth.signOut();
mGoogleSignInClient.signOut();
LoginManager.getInstance().logOut();
在哪里
private FirebaseAuth mAuth;
private GoogleSignInClient mGoogleSignInClient;
和
mGoogleSignInClient = GoogleSignIn.getClient(this, gso);
mAuth = FirebaseAuth.getInstance();
【讨论】:
【参考方案10】:我正在使用 Firebase 身份验证 UI,对我来说,解决方法是;
AuthUI.getInstance().setIsSmartLockEnabled(false)...
登录时,然后;
AuthUI.signOut(context)
退出时
【讨论】:
【参考方案11】:这对我有用。 !!
@Override
public void onPause()
super.onPause();
if (mGoogleApiClient.isConnected())
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>()
@Override
public void onResult(Status status)
// ...
);
mGoogleApiClient.stopAutoManage(Objects.requireNonNull(getActivity()));
mGoogleApiClient.disconnect();
如果要在 Fragment 或 Activity 内再次进入,则需要重新创建这些变量
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestEmail()
.build();
mGoogleApiClient = new GoogleApiClient.Builder(Objects.requireNonNull(getActivity()))
.enableAutoManage(getActivity(), (this))
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
【讨论】:
【参考方案12】:成功处理登录后添加mGoogleSignInClient.signOut();
即可。
private void handleSignInResult(Task<GoogleSignInAccount> completedTask)
try
GoogleSignInAccount account = completedTask.getResult(ApiException.class);
AuthCredential credential = GoogleAuthProvider.getCredential(account.getIdToken(), null);
mAuth.signInWithCredential(credential).addOnCompleteListener(this, task ->
if(task.isSuccessful())
mGoogleSignInClient.signOut();
updateUI();
else
Toast.makeText(this, "Something went wrong.", Toast.LENGTH_SHORT).show();
);
catch (ApiException e)
Log.w("SignIn Failed", "signInResult:failed code=" + e.getStatusCode());
updateUI(null);
【讨论】:
【参考方案13】:您只需清除预先登录的帐户即可。为此,请在 signIn() 函数下添加以下内容作为第一行: mGoogleSignInClient.signOut();
private void signIn()
// clearing previous signin caches
mGoogleSignInClient.signOut();
//getting the google signin intent
Intent signInIntent = mGoogleSignInClient.getSignInIntent();
//starting the activity for result
startActivityForResult(signInIntent, RC_SIGN_IN);
【讨论】:
但是如果我们不想退出,有什么解决办法吗? 因为 ios 有显示列表的选项,但 android 没有 @NehaK 如果我们不想退出,我们将不会退出会话。这样我们就不必再次调用 signIn() 方法了。 谢谢@amitsatputecd7。我知道这不可能是那么复杂的事情。我得到了我想要的确切结果:)【参考方案14】:对于 2K21 中的人们,这是您需要做的,
private static final int RC_GOOGLE_SIGN_IN = 500;
private void signWithGoogle()
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestEmail()
.build();
GoogleSignInClient googleSignInClient=GoogleSignIn.getClient(this, gso);
googleSignInClient.signOut();
Intent signInIntent = googleSignInClient.getSignInIntent();
startActivityForResult(signInIntent, RC_GOOGLE_SIGN_IN);
【讨论】:
【参考方案15】:简单而优雅的处理选项是在启动 google singin intent 之前使用 GoogleSingInClient
注销。
使用 Kotlin,您可以像这样编写代码,
private fun signInUsingGoogleAccount()
try
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id))
.requestEmail()
.build()
val googleSignInClient = GoogleSignIn.getClient(requireActivity(), gso)
googleSignInClient.signOut()
// Launch Intent
val signInIntent = googleSignInClient.signInIntent
startActivityForResult(signInIntent, GOOGLE_RESULT_CODE)
catch (ex: Exception)
ex.printStackTrace()
【讨论】:
以上是关于每次用户登录时,Google 登录都使用相同的帐户的主要内容,如果未能解决你的问题,请参考以下文章
每次使用 Rails 3 中的 Devise 登录时,如何检查用户帐户?