如果我使用 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 来确定对该数据的读/写访问权限。您的用户唯一的id
和email
已经在您将在编写规则时使用的auth
变量中。
【讨论】:
感谢您的信息 - 我认为那里存在依赖关系,但如果我为每个用户存储的数据不同步,比如意外删除,我怎么知道当前谁可以访问我的应用程序?数据是分开的很好,但肯定会被我从管理 POV 中看不到的事实所否定? 列出所有创建的用户和删除用户看起来是必须的! 可通过控制台访问的用户列表现在又回到了新的 Google 的 Firebase 中 这是一个必须具备的... 感谢弗兰克的回答。但是,如果您正在谈论的单独的用户数据库只存储电子邮件/密码组合(而不是任何其他用户信息),为什么在 Manager Users 部分(firebase.google.com/docs/auth/web/manage-users)下他们提到user.updateProfile
具有保存能力的方法displayName
和 photoURL
?那么这些信息存储在哪里呢?它没有保存在我的 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 简单的用户名和密码身份验证,如何返回用户列表的主要内容,如果未能解决你的问题,请参考以下文章
在 Android 应用中使用 Firebase (BaaS) 存储电子邮件和密码时如何包含用户名?