【发布时间】:2017-01-08 00:15:27
【问题描述】:
我正在为我的 Android 应用程序使用 Firebase 身份验证。用户可以使用多个提供商(Google、Facebook、Twitter)登录。
成功登录后,有没有办法使用 Firebase api 从这些提供商处获取用户性别/出生日期?
【问题讨论】:
标签: android firebase-authentication
我正在为我的 Android 应用程序使用 Firebase 身份验证。用户可以使用多个提供商(Google、Facebook、Twitter)登录。
成功登录后,有没有办法使用 Firebase api 从这些提供商处获取用户性别/出生日期?
【问题讨论】:
标签: android firebase-authentication
很遗憾,Firebase 没有任何内置功能可以在成功登录后获取用户的性别/出生日期。您必须自己从每个提供者那里检索这些数据。
您可以通过以下方式使用 Google People API 从 Google 获取用户的性别
public class SignInActivity extends AppCompatActivity implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
View.OnClickListener {
private static final int RC_SIGN_IN = 9001;
private GoogleApiClient mGoogleApiClient;
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_google_sign_in);
// We can only get basic information using FirebaseAuth
mAuth = FirebaseAuth.getInstance();
mAuthListener = new FirebaseAuth.AuthStateListener() {
@Override
public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
// User is signed in to Firebase, but we can only get
// basic info like name, email, and profile photo url
String name = user.getDisplayName();
String email = user.getEmail();
Uri photoUrl = user.getPhotoUrl();
// Even a user's provider-specific profile information
// only reveals basic information
for (UserInfo profile : user.getProviderData()) {
// Id of the provider (ex: google.com)
String providerId = profile.getProviderId();
// UID specific to the provider
String profileUid = profile.getUid();
// Name, email address, and profile photo Url
String profileDisplayName = profile.getDisplayName();
String profileEmail = profile.getEmail();
Uri profilePhotoUrl = profile.getPhotoUrl();
}
} else {
// User is signed out of Firebase
}
}
};
// Google sign-in button listener
findViewById(R.id.google_sign_in_button).setOnClickListener(this);
// Configure GoogleSignInOptions
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.server_client_id))
.requestServerAuthCode(getString(R.string.server_client_id))
.requestEmail()
.requestScopes(new Scope(PeopleScopes.USERINFO_PROFILE))
.build();
// Build a GoogleApiClient with access to the Google Sign-In API and the
// options specified by gso.
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this, this)
.addOnConnectionFailedListener(this)
.addConnectionCallbacks(this)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.google_sign_in_button:
signIn();
break;
}
}
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()) {
// Signed in successfully
GoogleSignInAccount acct = result.getSignInAccount();
// execute AsyncTask to get gender from Google People API
new GetGendersTask().execute(acct);
// Google Sign In was successful, authenticate with Firebase
firebaseAuthWithGoogle(acct);
}
}
}
class GetGendersTask extends AsyncTask<GoogleSignInAccount, Void, List<Gender>> {
@Override
protected List<Gender> doInBackground(GoogleSignInAccount... googleSignInAccounts) {
List<Gender> genderList = new ArrayList<>();
try {
HttpTransport httpTransport = new NetHttpTransport();
JacksonFactory jsonFactory = JacksonFactory.getDefaultInstance();
//Redirect URL for web based applications.
// Can be empty too.
String redirectUrl = "urn:ietf:wg:oauth:2.0:oob";
// Exchange auth code for access token
GoogleTokenResponse tokenResponse = new GoogleAuthorizationCodeTokenRequest(
httpTransport,
jsonFactory,
getApplicationContext().getString(R.string.server_client_id),
getApplicationContext().getString(R.string.server_client_secret),
googleSignInAccounts[0].getServerAuthCode(),
redirectUrl
).execute();
GoogleCredential credential = new GoogleCredential.Builder()
.setClientSecrets(
getApplicationContext().getString(R.string.server_client_id),
getApplicationContext().getString(R.string.server_client_secret)
)
.setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.build();
credential.setFromTokenResponse(tokenResponse);
People peopleService = new People.Builder(httpTransport, jsonFactory, credential)
.setApplicationName("My Application Name")
.build();
// Get the user's profile
Person profile = peopleService.people().get("people/me").execute();
genderList.addAll(profile.getGenders());
}
catch (IOException e) {
e.printStackTrace();
}
return genderList;
}
@Override
protected void onPostExecute(List<Gender> genders) {
super.onPostExecute(genders);
// iterate through the list of Genders to
// get the gender value (male, female, other)
for (Gender gender : genders) {
String genderValue = gender.getValue();
}
}
}
}
您可以在Accessing Google APIs找到更多信息
【讨论】:
对于脸书:
从 firebase 获取 facebook accessToken 非常简单。我正在使用firebase auth UI。使用 facebook 进行身份验证后,您将从 firebase 用户对象获取基本信息,例如显示名称、电子邮件、提供者详细信息。但是如果你想要更多的信息,比如性别,生日 facebook Graph API 是解决方案。一旦用户通过 facebook 进行身份验证,您就可以获得这样的访问令牌。
AccessToken.getCurrentAccessToken() 但有时它会给你 NULL 值而不是有效的访问令牌。确保您在此之前已初始化 facebook SDK。
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
FacebookSdk.sdkInitialize(this);
}
} 初始化后使用graphAPI
if(AccessToken.getCurrentAccessToken()!=null) {
System.out.println(AccessToken.getCurrentAccessToken().getToken());
GraphRequest request = GraphRequest.newMeRequest(
AccessToken.getCurrentAccessToken(),
new GraphRequest.GraphJSONObjectCallback() {
@Override
public void onCompleted(JSONObject object, GraphResponse response) {
// Application code
try {
String email = object.getString("email");
String gender = object.getString("gender");
} catch (JSONException e) {
e.printStackTrace();
}
}
});
Bundle parameters = new Bundle();
parameters.putString("fields", "id,name,email,gender,birthday");
request.setParameters(parameters);
request.executeAsync();
}
else
{
System.out.println("Access Token NULL");
}
快乐编码:)
【讨论】:
不,您无法直接获取这些数据。但是您可以使用用户的 id 并从各种提供者那里获取这些数据。请在公共 API 中为每个这些提供程序提供哪些数据之前检查哪些数据,例如谷歌刚刚弃用了 peopleApi 中的一些方法。
无论如何,这就是我为 facebook 做的事情
// Initialize Firebase Auth
FirebaseAuth mAuth = FirebaseAuth.getInstance();
// Create a listener
FirebaseAuth.AuthStateListener mAuthListener = firebaseAuth -> {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
// User is signed in
Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid());
} else {
// User is signed out
Log.d(TAG, "onAuthStateChanged:signed_out");
}
if (user != null) {
Log.d(TAG, "User details : " + user.getDisplayName() + user.getEmail() + "\n" + user.getPhotoUrl() + "\n"
+ user.getUid() + "\n" + user.getToken(true) + "\n" + user.getProviderId());
String userId = user.getUid();
String displayName = user.getDisplayName();
String photoUrl = String.valueOf(user.getPhotoUrl());
String email = user.getEmail();
Intent homeIntent = new Intent(LoginActivity.this, HomeActivity.class);
startActivity(homeIntent);
finish();
}
};
//Initialize the fB callbackManager
mCallbackManager = CallbackManager.Factory.create();
并在 FB 登录按钮的 onClick 中执行以下操作
LoginManager.getInstance().registerCallback(mCallbackManager,
new FacebookCallback<LoginResult>() {
@Override
public void onSuccess(LoginResult loginResult) {
Log.d(TAG, "facebook:onSuccess:" + loginResult);
handleFacebookAccessToken(loginResult.getAccessToken());
}
@Override
public void onCancel() {
Log.d(TAG, "facebook:onCancel");
}
@Override
public void onError(FacebookException error) {
Log.d(TAG, "facebook:onError", error);
}
});
LoginManager.getInstance().logInWithReadPermissions(this, Arrays.asList("public_profile", "email"));
【讨论】:
我发现直接访问服务要简单得多,而不是使用 Google 的 People API 类来访问他们的 REST 服务。
还可以节省 1.5 MB 的 APK 大小。
public static final String USER_BIRTHDAY_READ = "https://www.googleapis.com/auth/user.birthday.read";
public static final String USER_PHONENUMBERS_READ = "https://www.googleapis.com/auth/user.phonenumbers.read";
public static final String USERINFO_EMAIL = "https://www.googleapis.com/auth/userinfo.email";
public static final String USERINFO_PROFILE = "https://www.googleapis.com/auth/userinfo.profile";
public JSONObject getUserinfo(@NotNull Context context, @NotNull GoogleSignInAccount acct) {
try {
String token = GoogleAuthUtil.getToken(context, acct.getAccount(), "oauth2: " +USERINFO_PROFILE+" "+USER_PHONENUMBERS_READ+" "+USERINFO_EMAIL+" "+USER_BIRTHDAY_READ);
URL url = new URL("https://people.googleapis.com/v1/people/me?"
+"personFields=genders,birthdays,phoneNumbers,emailAddresses"
+"&access_token=" + token);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
int sc = con.getResponseCode();
if (sc == 200) {
InputStream is = con.getInputStream();
JSONObject profile = new JSONObject(readStream(is));
Log.d(TAG, "Got:" + profile.toString(2));
Log.d(TAG, "genders: "+profile.opt("genders"));
Log.d(TAG, "birthdays: "+profile.opt("birthdays"));
Log.d(TAG, "phoneNumbers: "+profile.opt("phoneNumbers"));
return profile;
} else if (sc == 401) {
GoogleAuthUtil.clearToken(context, token);
Log.d("Server auth fejl, prøv igen\n" + readStream(con.getErrorStream()));
} else {
Log.d("Serverfejl: " + sc);
}
} catch (UserRecoverableAuthException recoverableException) {
startActivityForResult(recoverableException.getIntent(), 1234);
} catch (Exception e) {
e.printStackTrace();
}
public static String readStream(InputStream is) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] data = new byte[2048];
int len = 0;
while ((len = is.read(data, 0, data.length)) >= 0) {
bos.write(data, 0, len);
}
is.close();
return new String(bos.toByteArray(), "UTF-8");
}
输出很容易解析为 JSON:
genders: [{"metadata":{"primary":true,"source":{"type":"PROFILE","id":"101628018970026223117"}},"value":"male","formattedValue":"Male"}]
birthdays: [{"metadata":{"primary":true,"source":{"type":"PROFILE","id":"101628018970026223117"}},"date":{"year":1985,"month":3,"day":5}},{"metadata":{"source":{"type":"ACCOUNT","id":"101628018970026223117"}},"date":{"year":1985,"month":3,"day":5}}]
【讨论】: