如果我使用 Firebase 简单的用户名和密码身份验证,如何返回用户列表

Posted

技术标签:

【中文标题】如果我使用 Firebase 简单的用户名和密码身份验证,如何返回用户列表【英文标题】:How do I return a list of users if I use the Firebase simple username & password authentication 【发布时间】:2013-01-18 09:11:59 【问题描述】:

不确定我是否做错了什么,但使用此 api https://www.firebase.com/docs/security/simple-login-email-password.html 我可以成功创建一个用户 - 根据返回消息,但我在 Forge 控制台的任何地方都看不到该用户。您如何知道注册了哪些用户?

我应该获取返回的用户 ID 并在 Firebase 中创建自己的用户对象,还是这种重复是不必要的。我确实需要添加一些额外的用户属性,所以也许我还是需要这样做。

【问题讨论】:

【参考方案1】:

在 Firebase 身份验证(以前称为 Firebase SimpleLogin)中使用电子邮件/密码身份验证时,用户的电子邮件和密码组合与实际存储在 Firebase 中的数据分开安全存储。

Firebase 中的数据与用户的电子邮件/密码哈希组合之间的屏障是设计使然:我们希望让您更轻松地 (1) 开发应用程序,(2) 防止任何意外的用户凭据泄露, (3) 在如何将用户数据存储在 Firebase 中时,您仍然可以拥有完全的灵活性。

这意味着我们只存储电子邮件地址/密码哈希组合而不存储其他任何内容,因此您可以决定如何在 Firebase 中存储实际用户数据。正如您所建议的,您应该获取用户 ID 并将该数据存储在您的 Firebase 中的某个位置,例如 /users/$id,并使用 Firebase Security Rules Language 来确定对该数据的读/写访问权限。您的用户唯一的idemail 已经在您将在编写规则时使用的auth 变量中。

【讨论】:

感谢您的信息 - 我认为那里存在依赖关系,但如果我为每个用户存储的数据不同步,比如意外删除,我怎么知道当前谁可以访问我的应用程序?数据是分开的很好,但肯定会被我从管理 POV 中看不到的事实所否定? 列出所有创建的用户和删除用户看起来是必须的! 可通过控制台访问的用户列表现在又回到了新的 Google 的 Firebase 中 这是一个必须具备的... 感谢弗兰克的回答。但是,如果您正在谈论的单独的用户数据库只存储电子邮件/密码组合(而不是任何其他用户信息),为什么在 Manager Users 部分(firebase.google.com/docs/auth/web/manage-users)下他们提到user.updateProfile 具有保存能力的方法displayNamephotoURL?那么这些信息存储在哪里呢?它没有保存在我的 Firestore 中 - 我检查过 - 所以我假设它在那个单独的数据库中。如果当前用户是唯一可以看到的人,那么这种方法的意义何在?【参考方案2】:

在这里,我创建了一个 android 程序来执行 Rob 为 firebase 初学者(如我)所说的内容 out there.this程序首先存储signedUp或signedIn用户的用户名,然后将它们显示在listView中

SignInActivity.java

public class SignInActivity extends BaseActivity implements View.OnClickListener,View.OnKeyListener

    private DatabaseReference mDatabase;
    public static FirebaseAuth mAuth;
    private static final String TAG = "MainActivity";

    EditText usernameField;
    EditText passwordField;
    TextView changeSignUpModeTextView;
    Button signUpButton;
    ImageView logo;
    RelativeLayout relativeLayout;

    Boolean signUpModeActive;
    static ArrayList<String> userList = new ArrayList<>();

    @Override
    public void onStart() 
        super.onStart();

        // Check auth on Activity start
        if (mAuth.getCurrentUser() != null) 
            onAuthSuccess(mAuth.getCurrentUser());
        
    
    @Override
    public boolean onKey(View view, int i, KeyEvent keyEvent) 

        if(i == keyEvent.KEYCODE_ENTER && keyEvent.getAction() == keyEvent.ACTION_DOWN)
            signUpOrLogIn(view);
        
         return false;
    

    @Override
    public void onClick(View view) 

        if(view.getId() == R.id.changeSignUpMode)

            if (signUpModeActive == true)

                signUpModeActive = false;
                changeSignUpModeTextView.setText("Sign Up");
                signUpButton.setText("Log In");

            else

                signUpModeActive = true;
                changeSignUpModeTextView.setText("Log In");
                signUpButton.setText("Sign Up");
            

        else if(view.getId() == R.id.logo || view.getId() == R.id.relativeLayout)

            InputMethodManager inm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
            inm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(),0);

        

    


    public void signUpOrLogIn(View view) 

        showProgressDialog();
        String email = usernameField.getText().toString().trim();
        String password = passwordField.getText().toString().trim();

        if (signUpModeActive == true) 
            mAuth.createUserWithEmailAndPassword(email,password)
                    .addOnCompleteListener(MainActivity.this, new OnCompleteListener<AuthResult>() 
                        @Override
                        public void onComplete(@NonNull Task<AuthResult> task) 
                            hideProgressDialog();
                            Toast.makeText(MainActivity.this, "createUserWithEmail:onComplete:" + task.isSuccessful(), Toast.LENGTH_SHORT).show();
                            // 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()) 
                                Toast.makeText(MainActivity.this, "Authentication failed." + task.getException().toString().substring(task.getException().toString().indexOf(" ")),
                                        Toast.LENGTH_SHORT).show();
                                Log.i("Error", task.getException().toString());
                             else 
                                onAuthSuccess(task.getResult().getUser());
                                showUserList();
                            
                        
                    );
         else 
            mAuth.signInWithEmailAndPassword(email,password)
                    .addOnCompleteListener(MainActivity.this, new OnCompleteListener<AuthResult>() 
                        @Override
                        public void onComplete(@NonNull Task<AuthResult> task) 
                            hideProgressDialog();
                            // 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()) 
                                // there was an error

                                Toast.makeText(MainActivity.this, task.getException().toString(),
                                        Toast.LENGTH_LONG).show();
                             else

                            
                                onAuthSuccess(task.getResult().getUser());
                                showUserList();
                            
                        
                    );
        
    

    public void showUserList()
        startActivity(new Intent(getApplicationContext(), UserList.class));
        finish();
    
    private void onAuthSuccess(FirebaseUser user) 
        String username = usernameFromEmail(user.getEmail());

        // Write new user
        writeNewUser(user.getUid(), username, user.getEmail());

        // Go to MainActivity

    
    private String usernameFromEmail(String email) 
        if (email.contains("@")) 
            return email.split("@")[0];
         else 
            return email;
        
    

    private void writeNewUser(String userId, String name, String email) 
        User user = new User(name, email);

        mDatabase.child("users").child(userId).setValue(user);
        ArrayList<String> userNames = new ArrayList<>();
        userNames.add(name);
        mDatabase.child("usernamelist").setValue(userNames);
    


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

        mAuth = FirebaseAuth.getInstance();
        mDatabase = FirebaseDatabase.getInstance().getReference();


        if(mAuth.getCurrentUser()!=null)
            showUserList();
        

        usernameField = (EditText) findViewById(R.id.username);
        passwordField = (EditText) findViewById(R.id.password);
        changeSignUpModeTextView = (TextView) findViewById(R.id.changeSignUpMode);
        signUpButton = (Button) findViewById(R.id.signupbutton);
        logo = (ImageView)findViewById(R.id.logo);
        relativeLayout= (RelativeLayout)findViewById(R.id.relativeLayout);

        signUpModeActive = true;

        changeSignUpModeTextView.setOnClickListener(this);

        usernameField.setOnKeyListener(this);
        passwordField.setOnKeyListener(this);

        logo.setOnClickListener(this);
        relativeLayout.setOnClickListener(this);



    

UserList.java

public class UserList extends AppCompatActivity 

    private static final String TAG = "UserList" ;
    private DatabaseReference userlistReference;
    private ValueEventListener mUserListListener;
    ArrayList<String> usernamelist = new ArrayList<>();
    ArrayAdapter arrayAdapter;;

    ListView userListView;


    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user_list);
        userlistReference = FirebaseDatabase.getInstance().getReference().child("usernamelist");
        onStart();
        userListView = (ListView) findViewById(R.id.userlistview);


    

    @Override
    protected void onStart() 
        super.onStart();
        final ValueEventListener userListener = new ValueEventListener() 
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) 
                usernamelist = new ArrayList<>((ArrayList) dataSnapshot.getValue());
                usernamelist.remove(usernameOfCurrentUser());
                Log.i(TAG, "onDataChange: "+usernamelist.toString());
                arrayAdapter = new ArrayAdapter(UserList.this,android.R.layout.simple_list_item_1,usernamelist);
                userListView.setAdapter(arrayAdapter);
            

            @Override
            public void onCancelled(DatabaseError databaseError) 
                Log.w(TAG, "onCancelled: ",databaseError.toException());
                Toast.makeText(UserList.this, "Failed to load User list.",
                        Toast.LENGTH_SHORT).show();
            
        ;
        userlistReference.addValueEventListener(userListener);

        mUserListListener = userListener;
    
    public String usernameOfCurrentUser()
    
        String email = MainActivity.mAuth.getCurrentUser().getEmail();
        if (email.contains("@")) 
            return email.split("@")[0];
         else 
            return email;
        
    
    @Override
    public void onStop() 
        super.onStop();

        // Remove post value event listener
        if (mUserListListener != null) 
            userlistReference.removeEventListener(mUserListListener);
        

    

    @Override
    public boolean onCreateOptionsMenu(Menu menu) 
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    

    @Override
    public boolean onOptionsItemSelected(MenuItem item) 
        switch(item.getItemId()) 
            case R.id.action_logout:
                FirebaseAuth.getInstance().signOut();
                startActivity(new Intent(this, MainActivity.class));
                finish();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        
    

【讨论】:

【参考方案3】:

您可以使用Google Identity Toolkit API 来获取您的Firebase 项目中所有注册用户的列表,此API 由Firebase CLI 使用,可以通过运行firebase auth:export results-file 来访问

确保身份工具包 API 已启用

firebase-users-list.js

const serviceAccount = require('path/to/firebase-sdk-json-service-account');

const googleapis = require('googleapis');
const identitytoolkit = googleapis.identitytoolkit('v3');

const authClient = new googleapis.auth.JWT(
    serviceAccount.client_email,
    null,
    serviceAccount.private_key,
    ['https://www.googleapis.com/auth/firebase'],
    null
);

authClient.authorize((err) => 
    if (err) 
        return console.error(err);
    

    let nextPageToken = undefined;
    let users = [];
    const getAccounts = () => identitytoolkit.relyingparty.downloadAccount(
        auth: authClient,
        resource: 
            targetProjectId: serviceAccount.project_id,
            maxResults: 200,
            nextPageToken: nextPageToken
        
    , (e, results) => 
        if (e) 
            return console.error(err);
        

        users = users.concat(results.users);
        if (results.nextPageToken) 
            nextPageToken = results.nextPageToken;
            return getAccounts();
         else 
            console.log(users);
        
    );
    getAccounts();
);

【讨论】:

【参考方案4】:

可以使用云功能来获取用户列表(查看文档firebase)。请注意,在以下示例中,custom claims 功能用于检查用户是否具有足够的权限。

// USERS: return full users list for admin
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
import * as admin from 'firebase-admin'
import * as functions from 'firebase-functions'

export const listUsers = functions.https.onCall((data, context) => 
  // check if user is admin (true "admin" custom claim), return error if not
  const isAdmin = context.auth.token.admin === true
  if (!isAdmin) 
    return  error: `Unauthorized.` 
  

  return admin
    .auth()
    .listUsers()
    .then((listUsersResult) => 
      // go through users array, and deconstruct user objects down to required fields
      const result = listUsersResult.users.map((user) => 
        const  uid, email, photoURL, displayName, disabled  = user
        return  uid, email, photoURL, displayName, disabled 
      )

      return  result 
    )
    .catch((error) => 
      return  error: 'Error listing users' 
    )
)

【讨论】:

【参考方案5】:

你可以使用admin.auth().listUsers来做到这一点

这是相关文档:https://firebase.google.com/docs/reference/admin/node/admin.auth.Auth.html#listusers

还有一个用法示例:https://firebase.google.com/docs/auth/admin/manage-users#list_all_users

function listAllUsers(nextPageToken) 
  // List batch of users, 1000 at a time.
  admin.auth().listUsers(1000, nextPageToken)
    .then(function(listUsersResult) 
      listUsersResult.users.forEach(function(userRecord) 
        console.log('user', userRecord.toJSON());
      );
      if (listUsersResult.pageToken) 
        // List next batch of users.
        listAllUsers(listUsersResult.pageToken);
      
    )
    .catch(function(error) 
      console.log('Error listing users:', error);
    );

// Start listing users from the beginning, 1000 at a time.
listAllUsers();

【讨论】:

不应该在客户端使用管理库? 是的,管理员仅用于服务器端(出于安全原因)。但是如果你需要客户端的信息,你可以做一个中间 API。 好主意。 Firestore 仍然不允许将用户信息存储在用户内部(我觉得这很愚蠢:D)所以您需要一次在 Firestore 中创建一个用户列表 ^^ 请注意,如果您不想创建“API”,您仍然可以依赖 firebase“函数” 但是如果你使用firebase“函数”,你仍然需要验证请求(使用类似jwt的东西)对吧?或者有什么办法解决它(它应该是安全的)?顺便说一句,我使用的是实时数据库,而不是 firestore。【参考方案6】:

我会尽可能简单地回答 只需使用以下代码将注册用户添加到您的数据库中

您也可以使用共享首选项将数据保存在本地,但其他用户无法使用。

在数据库中保存用户列表后,只需使用适配器从那里检索它

FirebaseDatabase.getInstance().getReference().child("my_user")
                        .child(task.getResult().getUser().getUid())
                        .child("username").setValue(autoCompleteTextView1.getText().toString());

【讨论】:

【参考方案7】:

python 中的用户列表:

from firebase_admin import credentials, db, auth
cred = credentials.Certificate('\path\to\serviceAccountKey.json')
default_app = firebase_admin.initialize_app(cred, 
    "databaseURL": "https://data_base_url.firebaseio.com"
)
users = auth.list_users()

【讨论】:

以上是关于如果我使用 Firebase 简单的用户名和密码身份验证,如何返回用户列表的主要内容,如果未能解决你的问题,请参考以下文章

使用firebase验证用户注册

在 Android 应用中使用 Firebase (BaaS) 存储电子邮件和密码时如何包含用户名?

使用 firebase 创建简单身份验证的最佳方法是啥?

在 Firebase 用户表上添加额外的详细信息

使用firebase中的signInWithPhoneNumber禁用注册

如何在 Firebase 中添加带有电子邮件和密码的用户名?