重新认证用户导致https.onCall()Firestore云功能不接收经过认证的用户信息

时间:2019-05-20 03:54:47

标签: android firebase-authentication google-cloud-firestore google-cloud-functions firebase-admin

这是一个真正的抓头人。我有一个使用https.onCall()的云函数。此功能调用是从 Android应用程序上的受密码保护的区域触发的(我将 Firestore 用作服务器)。为了访问此区域,我强迫用户重新输入密码,然后调用FirebaseAuth.getInstance()。getCurrentUser()。reauthenticate()。

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

我在功能日志中收到的错误消息是: “ TypeError:无法读取未识别对象的属性'uid'”。具体来说,这是在我尝试通过以下方法获取经过身份验证的用户的uid时发生的:

id

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

为了更好地说明正在发生的事情,这是我的流程/过程:

用户从选项菜单中选择“帐户”。这将启动一个dialogFragment,要求输入用户密码:

dialogFragment中的按钮代码:

const adminUID = context.auth.uid;

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

重新验证代码:

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

重新认证成功后,我们将运行意图并将其带到AccountSettingsActivity。在此活动中,我具有方法:deleteAccount(),该方法由buttonDialog中的buttonClick触发,以确认操作。

以下是触发该方法的buttonClick:

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

这是发出云功能请求的deleteAccount()方法:

调用云函数的方法:

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

最后,这是执行请求的Cloud Firestore代码。 云函数https.onCall():

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

再一张。这是我的index.ts:

// 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."
    };
});

1 个答案:

答案 0 :(得分:0)

好的,所以我认为我解决了这个问题。看来问题是我在httpsCallable()可以完全发送身份验证信息之前注销了用户。

我正在做以下事情:

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

相反,在deleteTask()方法返回Task对象之后,我可能不得不做某种继续。这样,只有从服务器获得响应后,我们才注销用户。