【问题标题】:Firebase kicks out current userFirebase 踢出当前用户
【发布时间】:2016-09-27 18:49:29
【问题描述】:

所以我遇到了这个问题,每次我添加一个新用户帐户时,它都会踢出已经登录的当前用户。我阅读了 firebase api,它说“如果创建了新帐户,用户是自动登录的”,但他们从未说过要避免这种情况。

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

我是管理员,我正在向我的网站添加帐户。如果我可以在不退出并登录到新帐户的情况下添加帐户,我会很高兴。有什么办法可以避免这种情况?

【问题讨论】:

  • 我猜您在设置身份验证时没有更改控制台中的默认设置(防止用户为每个注册创建单独的帐户)。

标签: javascript firebase firebase-authentication


【解决方案1】:

如果您想在前端创建第二个身份验证参考,请使用它来创建其他用户并注销并删除该参考。如果您这样做,您将不会在创建新用户时退出登录,也不会收到默认 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()
            )


        }
        

【讨论】:

    【解决方案2】:

    嘿,我有类似的问题,尝试通过管理员创建用户,因为没有登录就无法注册用户,我创建了一个解决方法,并在下面添加步骤

    1. 不用注册,而是在 firebase realtime db 中创建一个以电子邮件为密钥的节点(firebase 不允许电子邮件作为密钥,因此我创建了一个从电子邮件生成密钥的函数,反之亦然,我将附上以下函数)
    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;
    };
    

    【讨论】:

      【解决方案3】:

      您可以使用 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.')
          );
      

      }

      【讨论】:

      • 我们如何调用这个函数?可以展示一下app端吗?
      • 您好,我编辑并添加了对我有用的 CreateUser 函数。
      【解决方案4】:

      在网络上,这是由于您在注册上下文之外调用 createUserWithEmailAndPassword 时出现的意外行为;例如通过创建新用户帐户来邀请新用户使用您的应用。

      看起来,createUserWithEmailAndPassword 方法触发了一个新的刷新令牌,并且用户 cookie 也被更新了。 (此副作用未记录在案)

      以下是 Web SDK 的解决方法: 创建新用户后;

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

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

      【讨论】:

        【解决方案5】:

        这是一个使用 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);
        

        【讨论】:

        • 这是我最喜欢的解决方案,但被 CORS 阻止了?
        • @Davtho1983 听起来您需要调整与此答案无关的云功能设置:cloud.google.com/functions/docs/writing/…
        • Gud 解决方案将用户添加到身份验证部分而不是 firestore
        【解决方案6】:

        Android 解决方案 (Kotlin):

        1.你需要FirebaseOptions BUILDER(!)来设置api key、db url等,最后别忘了调用build()

        2.通过调用 FirebaseApp.initializeApp() 来创建一个辅助 auth 变量

        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()
        
                    }
        
                }
        
            }
        

        【讨论】:

          【解决方案7】:

          Swift 5:简单的解决方案

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

          let originalUser = Auth.auth().currentUser
          

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

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

          【讨论】:

          • 尽管在登录用户的电子邮件中有闪烁的行为,我会保留这个建议,我发现它更简单,更正确,也许我会在更新功能时做一些事情来隐藏闪烁执行
          • 绝妙的解决方案!
          【解决方案8】:

          我刚刚创建了一个 Firebase 函数,该函数在创建 Firestore 文档时触发(规则只写给管理员用户)。然后使用 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();
          });
          

          您可以使用 Algo 函数。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
          });
          

          【讨论】:

          • 我相信这是解决这个问题的唯一正确和好的解决方案!谢谢保罗。
          【解决方案9】:

          更新 20161110 - 下面的原始答案

          另外,请查看this answer 了解不同的方法。

          原答案

          这实际上是可能的。

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

          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();
          });
          

          如果您未指定用于操作的 Firebase 连接,则默认情况下将使用第一个连接。

          Source 用于多个应用参考。

          编辑

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

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

          您必须考虑的是将数据写入 firebase。通常的做法是用户可以编辑/更新他们自己的用户信息,因此当您使用第二个身份验证参考进行编写时,它应该可以工作。但是,如果您对该用户具有角色或权限之类的内容,请确保使用具有正确权限的身份验证引用编写该内容。在这种情况下,主要的身份验证是管理员,第二个身份验证是新创建的用户。

          【讨论】:

          • 我正在挖掘这个。但是,这是否仍然会取消对 secondaryApp 帐户(或 mainAppAccount)的身份验证,从而阻止在不重新进行身份验证的情况下创建另一个用户?
          • @Jay 没错,这是一个好观点,但这实际上对于创建新用户并不重要。任何人都可以创建用户。当我对此进行测试时,我可以创建多个用户。但是,您让我想到了其他可能成为问题的事情,即在创建该用户后将用户数据写入 Firebase。我会更新我的答案,包括我的想法。
          • @FrankvanPuffelen 好吧闭嘴。这是正确的(当然)。然后引出了这个问题;为什么要做出最初的改变?当任何人仍然可以创建帐户时,对创建用户的经过身份验证的帐户进行身份验证似乎有点违反直觉。诡异的。无论如何,这是一个 BRILLIANT 答案。
          • 这对我帮助很大,谢谢!。要添加的一件事是我必须添加“secondaryApp.delete();”阻止 firebase 告诉我在全球范围内注册了另一个应用程序。
          • @AndréKool:我们刚刚发布了一个 firebase-admin SDK,它不需要使用您的(诚然聪明的)解决方法。见my updated answer below
          【解决方案10】:

          Swift 4 更新

          我尝试了几种不同的选项来从一个帐户创建多个用户,但这是迄今为止最好和最简单的解决方案。

          Nico的原回答

          首先在你的 AppDelegate.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()
                                  
                              }
                          }
                      }
                  }
          

          【讨论】:

            【解决方案11】:

            我得到 André's very clever workaround 使用 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];
                                      }];
            

            【讨论】:

              【解决方案12】:

              如果您使用的是 Polymer 和 Firebase (polymerfire),请参阅此答案:https://stackoverflow.com/a/46698801/1821603

              本质上,您创建一个辅助&lt;firebase-app&gt; 来处理新用户注册,而不影响当前用户。

              【讨论】:

                【解决方案13】:

                这是 Jcabrera's answer 的 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")
                        }
                

                【讨论】:

                  【解决方案14】:

                  Swift 版本:

                  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(...)
                  }
                  

                  【讨论】:

                    【解决方案15】:

                    更新 20161108 - 下面的原始答案

                    Firebase 刚刚发布了它的 firebase-admin SDK,它允许为这个和其他常见的管理用例提供服务器端代码。阅读installation instructions,然后深入了解documentation on creating users

                    原始答案

                    目前这是不可能的。创建电子邮件+密码用户会自动让新用户登录。

                    【讨论】:

                    • 弗兰克,所以如果我想在不登录的情况下创建用户,我应该在我的 AngularJS 应用程序中使用 Firebase 管理 SDK?
                    • Firebase Admin node.js SDK 只能在受信任的环境中运行。在不登录的情况下创建用户被视为一项管理任务。
                    • @FrankvanPuffelen 我希望移动应用用户能够邀请使用createUserWithEmailAndPassword 并向用户发送电子邮件的用户。我不想在客户端/移动应用程序中使用 firebase-admin SDK。我还有哪些其他选择?
                    • 好的,所以我只花了几个小时研究 Node.js,设置了一个服务来处理来自 angular2 项目的新用户表单的 Post 数据,登录用户没有得到启动:)。现在来实现删除和更新。
                    • @FrankvanPuffelen 你们有什么理由不向createUserWithEmailAndPassword 添加noLogin 标志吗?像许多其他人一样,我也需要在不使用 Admin SDK 的情况下从我的前端添加用户。
                    猜你喜欢
                    • 2020-03-01
                    • 2016-12-11
                    • 2017-01-11
                    • 2021-08-24
                    • 2020-11-30
                    • 1970-01-01
                    • 2023-03-03
                    • 2017-04-06
                    相关资源
                    最近更新 更多