【问题标题】:Firebase Auth get additional user info (age, gender)Firebase Auth 获取其他用户信息(年龄、性别)
【发布时间】:2017-01-08 00:15:27
【问题描述】:

我正在为我的 Android 应用程序使用 Firebase 身份验证。用户可以使用多个提供商(Google、Facebook、Twitter)登录。

成功登录后,有没有办法使用 Firebase api 从这些提供商处获取用户性别/出生日期?

【问题讨论】:

    标签: android firebase-authentication


    【解决方案1】:

    很遗憾,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找到更多信息

    【讨论】:

    • 如何获取用户的名字和姓氏。由于 user.getGivenName()user.getFamilyName() 在这里不起作用。
    【解决方案2】:

    对于脸书:

    从 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");
    }
    

    快乐编码:)

    【讨论】:

      【解决方案3】:

      不,您无法直接获取这些数据。但是您可以使用用户的 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"));
      

      【讨论】:

      • 我在您的样本中看不到您的性别或出生日期?
      • 那些没有提供我的火力基地,因为您需要使用 facebook 的图形 API 和您在此处获得的 uid 来对图形 API 进行各种查询。 developers.facebook.com/docs/graph-api
      • 我明白了,所以无法使用 Firebase sdk 完成。我需要单独使用 Graph API 或 People API 来获取它们
      • 是的,仅靠 firebase 无法为您提供所有这些。它只是对用户进行身份验证就足够了,而不是根据不同提供者的权限方法使用用户的 id 来获取其他数据
      • @TareKhoury 如果对回答您的问题有帮助,请接受答案。问候
      【解决方案4】:

      我发现直接访问服务要简单得多,而不是使用 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}}]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-07
        • 1970-01-01
        相关资源
        最近更新 更多