Firebase 淘汰当前用户

所以我有这样一个问题,每次添加一个新用户帐户时,都会踢出已经登录的当前用户。我读了消防队的 API 上面说“ 如果创建了新帐户,用户将自动登录但他们从没说过要避免这种情况”。

      //ADD EMPLOYEES
addEmployees: function(formData){
firebase.auth().createUserWithEmailAndPassword(formData.email, formData.password).then(function(data){
console.log(data);
});
},

我是管理员,我添加帐户到我的网站。我想如果我可以添加一个帐户,而不是签出和签署到新的帐户。有什么办法可以避免这一切吗?

39150 次浏览

更新20161108-原始答案如下

Firebase 刚刚发布了它的 Firebase-admin SDK,它允许服务器端代码用于这个用例和其他常见的管理用例。阅读 安装说明书,然后潜入 关于创建用户的文档

原始答案

创建电子邮件 + 密码用户会自动为新用户签名。

更新20161110-原始答案如下

另外,查看 这个答案了解不同的方法。

原始答案

这是有可能的。

但不是直接创建,方法是创建第二个 auth 引用并使用它来创建用户:

var config = {apiKey: "apiKey",
authDomain: "projectId.firebaseapp.com",
databaseURL: "https://databaseName.firebaseio.com"};
var secondaryApp = firebase.initializeApp(config, "Secondary");


secondaryApp.auth().createUserWithEmailAndPassword(em, pwd).then(function(firebaseUser) {
console.log("User " + firebaseUser.uid + " created successfully!");
//I don't know if the next statement is necessary
secondaryApp.auth().signOut();
});

如果你没有指定使用哪个连接,默认情况下它会使用第一个连接。

多个应用程序引用的 Source

剪辑

对于新用户的实际创建,除了在第二个认证引用上进行身份验证的管理员之外,没有任何人或其他人是无关紧要的,因为创建帐户所需的只是认证引用本身。

以下内容尚未经过测试,但值得思考

你需要考虑的是把数据写到 Firebase。通常的做法是,用户可以编辑/更新自己的用户信息,所以当您使用第二个 auth 引用来编写时,这应该可以工作。但是,如果您对该用户有角色或权限之类的东西,请确保使用具有正确权限的授权引用编写该文件。在这种情况下,主 auth 是管理员,第二个 auth 是新创建的用户。

我让 安德烈很聪明使用 Firebase IOS SDK在 Objective-C 工作:

NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"GoogleService-Info" ofType:@"plist"];
FIROptions *secondaryAppOptions = [[FIROptions alloc] initWithContentsOfFile:plistPath];
[FIRApp configureWithName:@"Secondary" options:secondaryAppOptions];
FIRApp *secondaryApp = [FIRApp appNamed:@"Secondary"];
FIRAuth *secondaryAppAuth = [FIRAuth authWithApp:secondaryApp];


[secondaryAppAuth createUserWithEmail:user.email
password:user.password
completion:^(FIRUser * _Nullable user, NSError * _Nullable error) {
[secondaryAppAuth signOut:nil];
}];

斯威夫特版本:

FIRApp.configure()


// Creating a second app to create user without logging in
FIRApp.configure(withName: "CreatingUsersApp", options: FIRApp.defaultApp()!.options)


if let secondaryApp = FIRApp(named: "CreatingUsersApp") {
let secondaryAppAuth = FIRAuth(app: secondaryApp)
secondaryAppAuth?.createUser(...)
}

以下是改编自 Jcabrera 的回答的 Swift 3:

let bundle = Bundle.main
let path = bundle.path(forResource: "GoogleService-Info", ofType: "plist")!
let options = FIROptions.init(contentsOfFile: path)
FIRApp.configure(withName: "Secondary", options: options!)
let secondary_app = FIRApp.init(named: "Secondary")
let second_auth = FIRAuth(app : secondary_app!)
second_auth?.createUser(withEmail: self.username.text!, password: self.password.text!)
{
(user,error) in
print(user!.email!)
print(FIRAuth.auth()?.currentUser?.email ?? "default")
}

如果你正在使用聚合物和火焰(聚合火)看到这个答案: https://stackoverflow.com/a/46698801/1821603

实际上,您要创建一个辅助 <firebase-app>来处理新用户注册,而不影响当前用户。

Swift 4的更新

我已经尝试了一些不同的选项来从一个帐户创建多个用户,但这是目前为止最好和最简单的解决方案。

原答案由 尼科提供

第一次在您的 AppRegiate.swift 文件中配置 firebase

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
FirebaseApp.configure(name: "CreatingUsersApp", options: FirebaseApp.app()!.options)


return true
}

将下面的代码添加到创建帐户的操作中。

            if let secondaryApp = FirebaseApp.app(name: "CreatingUsersApp") {
let secondaryAppAuth = Auth.auth(app: secondaryApp)
                

// Create user in secondary app.
secondaryAppAuth.createUser(withEmail: email, password: password) { (user, error) in
if error != nil {
print(error!)
} else {
//Print created users email.
print(user!.email!)
                        

//Print current logged in users email.
print(Auth.auth().currentUser?.email ?? "default")
                        

try! secondaryAppAuth.signOut()
                        

}
}
}
}

我刚刚创建了一个 Firebase 函数,它在创建一个 Firestordocument 时触发(对管理员用户使用只写规则)。然后使用 admin.auth ()。CreateUser ()正确地创建新用户。

export const createUser = functions.firestore
.document('newUsers/{userId}')
.onCreate(async (snap, context) => {
const userId = context.params.userId;
const newUser = await admin.auth().createUser({
disabled: false,
displayName: snap.get('displayName'),
email: snap.get('email'),
password: snap.get('password'),
phoneNumber: snap.get('phoneNumber')
});
// You can also store the new user in another collection with extra fields
await admin.firestore().collection('users').doc(newUser.uid).set({
uid: newUser.uid,
email: newUser.email,
name: newUser.displayName,
phoneNumber: newUser.phoneNumber,
otherfield: snap.get('otherfield'),
anotherfield: snap.get('anotherfield')
});
// Delete the temp document
return admin.firestore().collection('newUsers').doc(userId).delete();
});

您可以使用 Functions.https.onCall ()算法

exports.createUser= functions.https.onCall((data, context) => {
const uid = context.auth.uid; // Authorize as you want
// ... do the same logic as above
});

宣布死亡。

const createUser = firebase.functions().httpsCallable('createUser');
createUser({userData: data}).then(result => {
// success or error handling
});

Android 解决方案(Kotlin) :

1. 您需要 FirebaseOptions BUILDER (!)来设置 api 键、 db URL 等,不要忘记在最后调用 build ()

2. 通过调用 FirebaseApp.initializeApp ()创建辅助认证变量

3. 通过传递新创建的辅助身份验证来获取 FirebaseAuth 的实例,然后做任何你想做的事情(例如 createUser)

    // 1. you can find these in your project settings under general tab
val firebaseOptionsBuilder = FirebaseOptions.Builder()
firebaseOptionsBuilder.setApiKey("YOUR_API_KEY")
firebaseOptionsBuilder.setDatabaseUrl("YOUR_DATABASE_URL")
firebaseOptionsBuilder.setProjectId("YOUR_PROJECT_ID")
firebaseOptionsBuilder.setApplicationId("YOUR_APPLICATION_ID") //not sure if this one is needed
val firebaseOptions = firebaseOptionsBuilder.build()


// indeterminate progress dialog *ANKO*
val progressDialog = indeterminateProgressDialog(resources.getString(R.string.progressDialog_message_registering))
progressDialog.show()


// 2. second auth created by passing the context, firebase options and a string for secondary db name
val newAuth = FirebaseApp.initializeApp(this@ListActivity, firebaseOptions, Constants.secondary_db_auth)
// 3. calling the create method on our newly created auth, passed in getInstance
FirebaseAuth.getInstance(newAuth).createUserWithEmailAndPassword(email!!, password!!)
.addOnCompleteListener { it ->


if (it.isSuccessful) {


// 'it' is a Task<AuthResult>, so we can get our newly created user from result
val newUser = it.result.user


// store wanted values on your user model, e.g. email, name, phonenumber, etc.
val user = User()
user.email = email
user.name = name
user.created = Date().time
user.active = true
user.phone = phone


// set user model on /db_root/users/uid_of_created_user/, or wherever you want depending on your structure
FirebaseDatabase.getInstance().reference.child(Constants.db_users).child(newUser.uid).setValue(user)


// send newly created user email verification link
newUser.sendEmailVerification()


progressDialog.dismiss()


// sign him out
FirebaseAuth.getInstance(newAuth).signOut()
// DELETE SECONDARY AUTH! thanks, Jimmy :D
newAuth.delete()


} else {


progressDialog.dismiss()


try {


throw it.exception!!


// catch exception for already existing user (e-mail)
} catch (e: FirebaseAuthUserCollisionException) {


alert(resources.getString(R.string.exception_FirebaseAuthUserCollision), resources.getString(R.string.alertDialog_title_error)) {


okButton {


isCancelable = false


}


}.show()


}


}


}

可以使用 firebase 函数添加用户。

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();


const cors = require('cors')({
origin: true,
});
exports.AddUser = functions.https.onRequest(( req, res ) => {
// Grab the text parameter.


cors( req, res, ()  => {
let email  = req.body.email;
let passwd = req.body.passwd;
let role   = req.body.role;
const token = req.get('Authorization').split('Bearer ')[1];


admin.auth().verifyIdToken(token)
.then(
(decoded) => {
// return res.status(200).send(  decoded )
return creatUser(decoded);
})
.catch((err) => {
return res.status(401).send(err)
});
       

function creatUser(user){
admin.auth().createUser({
email: email,
emailVerified: false,
password: passwd,
disabled: false
})
.then((result) => {
console.log('result',result);
return res.status(200).send(result);
}).catch((error) => {
console.log(error.message);
return res.status(400).send(error.message);
})
}


});
});


CreateUser(){
//console.log('Create User')
this.submitted = true;
if (this.myGroup.invalid) {
return;
}




let Email    = this.myGroup.value.Email;
let Passwd   = this.myGroup.value.Passwd;
let Role     = 'myrole';
let TechNum  = this.myGroup.value.TechNum;
let user     = JSON.parse(localStorage.getItem('user'));
let role     = user.role;
let AdminUid = user.uid;
let authToken = user.stsTokenManager.accessToken;
let httpHeaders = new HttpHeaders().set('Authorization', 'Bearer ' + authToken);
let options = { headers: httpHeaders };
let params  = { email:Email,passwd:Passwd,role:Role };


this.httpClient.post('https://us-central1-myproject.cloudfunctions.net/AddUser', params, options)
.subscribe( val => {
//console.log('Response from cloud function', val );
let createdUser:any = val;
//console.log(createdUser.uid);
const userRef: AngularFirestoreDocument<any> = this.afs.doc(`users/${createdUser.uid}`);
const userUpdate = {
uid: createdUser.uid,
email: createdUser.email,
displayName: null,
photoURL: null,
emailVerified: createdUser.emailVerified,
role: Role,
TechNum:TechNum,
AccountAccess:this.AccountAccess,
UserStatus:'open',
OwnerUid:AdminUid,
OwnerUidRole:role,
RootAccountAccess:this.RootAccountAccess
}
userRef.set(userUpdate, {
merge: false
});
this.toastr.success('Success, user add','Success');
this.myGroup.reset();
this.submitted = false;
},
err => {
console.log('HTTP Error', err.error)
this.toastr.error(err.error,'Error')
},
() => console.log('HTTP request completed.')
);

}

斯威夫特5: 简单的解决方案

首先将当前用户存储在一个名为 OrigalUser 的变量中

let originalUser = Auth.auth().currentUser

然后,在创建新用户的完成处理程序中,使用 updateCurrentUser 方法还原原始用户

Auth.auth().updateCurrentUser(originalUser, completion: nil)

下面是一个使用 web SDK 的简单解决方案。

  1. 创建一个云函数(https://firebase.google.com/docs/functions)
import admin from 'firebase-admin';
import * as functions from 'firebase-functions';


const createUser = functions.https.onCall((data) => {
return admin.auth().createUser(data)
.catch((error) => {
throw new functions.https.HttpsError('internal', error.message)
});
});


export default createUser;
  1. 从你的应用程序调用这个函数
import firebase from 'firebase/app';


const createUser = firebase.functions().httpsCallable('createUser');


createUser({ email, password })
.then(console.log)
.catch(console.error);
  1. 也可以使用返回的 uid 设置用户文档信息。
createUser({ email, password })
.then(({ data: user }) => {
return database
.collection('users')
.doc(user.uid)
.set({
firstname,
lastname,
created: new Date(),
});
})
.then(console.log)
.catch(console.error);

在 Web 上,这是由于在注册上下文之外调用 createUserWithEmailAndPassword 时出现了意想不到的行为; 例如,通过创建一个新用户帐户来邀请一个新用户访问您的应用程序。

看起来,createUserWithEmailAndPassword 方法会触发一个新的刷新令牌,用户 cookie 也会更新

下面是 WebSDK 的一个变通方法: 创建新用户后;

firebase.auth().updateCurrentUser (loggedInUser.current)

前提是您事先与原始用户启动 loggedInUser。

嘿,我有类似的问题,试图通过管理员创建用户,因为它是不可能的 signUp 用户没有 signIn,我创建了一个工作,添加到下面的步骤

  1. 与其注册,不如在 firebase 实时数据库中创建一个以 email 为键的节点(firebase 不允许 email 为键,所以我创建了一个函数来从 email 生成 key,反之亦然,我将附加以下函数)
  2. 在保存用户时保存一个初始密码字段(甚至可以使用 bcrypt 或其他方法进行哈希,如果您愿意的话,不过只能使用一次)
  3. 现在,一旦用户尝试登录检查是否有任何节点与该电子邮件(从电子邮件生成密钥)存在于数据库,如果是这样,然后匹配所提供的密码。
  4. 如果密码匹配,则删除节点并使用提供的凭据执行 authSignUpWithEmailandPassword。
  5. 用户已成功注册
//Sign In
firebaseDB.child("users").once("value", (snapshot) => {
const users = snapshot.val();
const userKey = emailToKey(data.email);
if (Object.keys(users).find((key) => key === userKey)) {
setError("user already exist");
setTimeout(() => {
setError(false);
}, 2000);
setLoading(false);
} else {
firebaseDB
.child(`users`)
.child(userKey)
.set({ email: data.email, initPassword: data.password })
.then(() => setLoading(false))
.catch(() => {
setLoading(false);
setError("Error in creating user please try again");
setTimeout(() => {
setError(false);
}, 2000);
});
}
});


//Sign Up
signUp = (data, setLoading, setError) => {
auth
.createUserWithEmailAndPassword(data.email, data.password)
.then((res) => {
const userDetails = {
email: res.user.email,
id: res.user.uid,
};
const key = emailToKey(data.email);
app
.database()
.ref(`users/${key}`)
.remove()
.then(() => {
firebaseDB.child("users").child(res.user.uid).set(userDetails);
setLoading(false);
})
.catch(() => {
setLoading(false);
setError("error while registering try again");
setTimeout(() => setError(false), 4000);
});
})
.catch((err) => {
setLoading(false);
setError(err.message);
setTimeout(() => setError(false), 4000);
});
};


//Function to create a valid firebase key from email and vice versa
const emailToKey = (email) => {
//firebase do not allow ".", "#", "$", "[", or "]"
let key = email;
key = key.replace(".", ",0,");
key = key.replace("#", ",1,");
key = key.replace("$", ",2,");
key = key.replace("[", ",3,");
key = key.replace("]", ",4,");


return key;
};


const keyToEmail = (key) => {
let email = key;
email = email.replace(",0,", ".");
email = email.replace(",1,", "#");
email = email.replace(",2,", "$");
email = email.replace(",3,", "[");
email = email.replace(",4,", "]");


return email;
};

如果您想在前端创建第二个认证引用,可以使用它来创建其他用户,然后注销并删除该引用。如果你这样做,当你创建一个新的用户时,你不会被注销,你不会得到默认的 Firebase 应用程序已经存在的错误。

   const createOtherUser =()=>{
var config = {
//your firebase config
};
let secondaryApp = firebase.initializeApp(config, "secondary");


secondaryApp.auth().createUserWithEmailAndPassword(email, password).then((userCredential) => {
console.log(userCredential.user.uid);
}).then(secondaryApp.auth().signOut()
)
.then(secondaryApp.delete()
)




}
        

对于 Android,我建议使用一种更简单的方法,不必手动提供 api 密钥、应用程序 ID... 等,只需使用默认实例的 FirebaseOptions即可。

val firebaseDefaultApp = Firebase.auth.app
val signUpAppName = firebaseDefaultApp.name + "_signUp"


val signUpApp = try {
FirebaseApp.initializeApp(
context,
firebaseDefaultApp.options,
signUpAppName
)
} catch (e: IllegalStateException) {
// IllegalStateException is throw if an app with the same name has already been initialized.
FirebaseApp.getInstance(signUpAppName)
}


// Here is the instance you can use to sign up without triggering auth state on the default Firebase.auth
val signUpFirebaseAuth = Firebase.auth(signUpApp)

怎么用?

signUpFirebaseAuth
.createUserWithEmailAndPassword(email, password)
.addOnSuccessListener {
// Optional, you can send verification email here if you need


// As soon as the sign up with sign in is over, we can sign out the current user
firebaseAuthSignUp.signOut()
}
.addOnFailureListener {
// Log
}

我对这个问题的解决方案是将用户名/电子邮件和密码存储在一个静态类中,然后添加一个新用户注销新用户,并立即以管理员用户的身份登录(您保存的 id 通行证)。对我来说很有效: D

更新19.05.2022-使用@angle/fire (最新版本 = v. 7.3.0)

如果你的应用程序中没有直接使用 firebase,而是仅仅为了授权目的而使用@angle/fire,那么你可以使用与之前建议的相同的方法来使用@angle/fire 库:

import { Auth, getAuth, createUserWithEmailAndPassword } from '@angular/fire/auth';
import { deleteApp, initializeApp } from '@angular/fire/app';
import { firebaseConfiguration } from '../config/app.config';   // <-- Your project's configuration here.




const tempApp = initializeApp(firebaseConfiguration, "tempApp");
const tempAppAuth = getAuth(tempApp);
await createUserWithEmailAndPassword(tempAppAuth, email, password)
.then(async (newUser) => {
resolve( () ==>  {
// Do something, e.g. add user info to database
});
})
.catch(error => reject(error))
.finally( () => {
tempAppAuth.signOut()
.then( () => deleteApp(tempApp));
});