代码之家  ›  专栏  ›  技术社区  ›  Brian Begun

重新验证用户导致https.onCall()firestore云函数不接收经过身份验证的用户信息

  •  0
  • Brian Begun  · 技术社区  · 5 年前

    这真是个让人头疼的问题。我有一个云函数https.onCall(). 此函数调用是从我的计算机上的密码保护区域触发的 (我正在使用 作为我的服务器)。为了访问这个区域,我强制用户重新输入他们的密码,然后调用FirebaseAuth.getInstance().getCurrentUser().reauthenticate()。

    我已经运行了调用https.onCall()云函数没有重新身份验证,并且该函数保留用户的身份验证凭据,因此我将其缩小到重新身份验证时的范围。我错过什么了吗?我需要做些什么来通知云功能身份验证更新吗?

    const adminUID = context.auth.uid;
    

    假设是因为我没有得到上面的错误,是因为没有经过身份验证的数据通过上下文进入。

    为了更好地阐明发生了什么,我的流程如下:

    用户从选项菜单中选择“帐户”。这将启动一个询问用户密码的dialogFragment:

    dialogFragment中的按钮代码:

     loginButton.setOnClickListener(new View.OnClickListener()
        {
            public void onClick(View view) {
                //execute the loginReAuth method
                authenticateSession.loginAdminReAuth(adminEmailAddress, passwordField);
            }
        });
    

    选择loginButton并输入用户密码后,我们将数据传递给重新验证方法:

    重新验证代码:

    public void loginAdminReAuth(final String email, TextView passwordText) {
        user = FirebaseAuth.getInstance().getCurrentUser();
        String password = passwordText.getText().toString();
    
        AuthCredential credential = EmailAuthProvider.getCredential(email, password);
        user.reauthenticate(credential)
                .addOnCompleteListener(new OnCompleteListener<Void>() {
                    @Override
                    public void onComplete(@NonNull Task<Void> task) {
                        if (task.isSuccessful()) {
                            Intent intent = new Intent(context, AccountSettingsActivity.class);
                            context.startActivity(intent);
                        } else {
                            // If sign in fails, display a message to the user.
                            Log.w(TAG, "re-authenticate:failure", task.getException());
                            Toast.makeText(MyApplication.getContext(), task.getException().getMessage(),
                                    Toast.LENGTH_SHORT).show();
                        }
                    }
                });
    }
    

    当重新验证成功时,我们运行intent并将它们带到AccountSettingsActivity。在这个活动中,我有一个方法:deleteAccount(),它是由alertDialog中的一个按钮点击来触发的,该按钮确认了这个操作。

    下面是触发该方法的按钮:

    @Override
    public void onDialogOKPressed(DialogFragment dialog) {
        dialog.dismiss();
        if (buttonSelected.equals("accountUpdateButton")) {
           //update code here.
        }
        else if (buttonSelected.equals("accountDeleteButton")) {
            deleteAccount(admin);
        }
    }
    

    调用云函数的方法:

    private Task<String> deleteAccount(Admin selectedAdmin) {
        Gson gson = new Gson();
        String selectedAdminJson;
        selectedAdminJson = gson.toJson(selectedAdmin);
    
        Map<String, Object> data = new HashMap<>();
        data.put("selectedAdminJson", selectedAdminJson);
    
        return mFunctions
                .getHttpsCallable("deleteAccount")
                .call(data)
                .continueWith(new Continuation<HttpsCallableResult, String>() {
                    @Override
                    public String then(@NonNull Task<HttpsCallableResult> task) throws Exception {
                        // This continuation runs on either success or failure, but if the task
                        // has failed then getResult() will throw an Exception which will be
                        // propagated down.
                        Log.d(TAG, "results from deleteAccount: " + task.getResult().getData().toString());
                        String result = (String) task.getResult().getData();
                        return result;
                    }
                });
    }
    

    最后,这里是执行请求的cloudfirestore代码。

    // The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
    import * as functions from 'firebase-functions';
    // The Firebase Admin SDK to access the Firebase Realtime Database.
    import * as admin from 'firebase-admin'
    
    export = module.exports = functions.https
    .onCall(async (data, context) => {
    
        //selectedAdminJson received from app client and converted to admin object class
        const selectedAdminJson = data.selectedAdminJson;
        const adminUID = context.auth.uid;
    
        //Error checking
        // Checking attribute.
        if (!(typeof selectedAdminJson === 'string') || selectedAdminJson.length === 0) {
            // Throwing an HttpsError so that the client gets the error details.
            throw new functions.https.HttpsError('invalid-argument', 'The function must be called with ' +
                'one arguments "JSON object" containing selectedAdmin to add.');
        }
        // Checking that the user is authenticated OR if the calling adminID doesn't match the data received
        if (!context.auth) {
            // Throwing an HttpsError so that the client gets the error details.
            throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' +
                'while authenticated.');
        }
        try {
    
            //METHODS EXECUTED HERE
    
        } catch (error) {
            console.error("Error removing adminUserGroup data: ", error);
        }
    
        // Returning result to the client.
        return {
            selectedAdminJson: "selectedAdminJson received and processing."
        };
    });
    

    再来一块。这是我生活的一部分索引.ts:

    import * as admin from 'firebase-admin'
    admin.initializeApp();
    
    if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === 'deleteAccount') {
        exports.deleteAccount = require('./deleteAccount');
    }
    
    0 回复  |  直到 5 年前
        1
  •  0
  •   Brian Begun    5 年前

    好吧,我想我解决了问题。问题似乎是在httpscalable()完全发送身份验证信息之前,我将用户注销了。

        deleteAccount(firebaseLocalCache.thisAdminFromCache());
        session.logoutUser();
    

    相反,我可能需要在deleteAccount()方法返回一个Task对象之后进行某种延续。这样,我们只有在收到服务器的响应后才能注销用户。