Firebase 用户的 context.auth 仍然存在 allAuthenticatedUsers secure Google function error with UNAUTHENTICAT
Posted
技术标签:
【中文标题】Firebase 用户的 context.auth 仍然存在 allAuthenticatedUsers secure Google function error with UNAUTHENTICATED【英文标题】:Firebase user's context.auth is present still allAuthenticatedUsers secured Google function error with UNAUTHENTICATED 【发布时间】:2020-06-03 04:27:07 【问题描述】:我写了一个简单的cloud函数:
import * as functions from 'firebase-functions';
export const repeat = functions.https.onCall( function (data, context)
// Authentication user information is automatically added to the request.
if (context.auth)
console.log(' context.auth is defined ');
console.log(' uid is ' + context.auth.uid);
else
console.log(' context.auth undefine. ');
if (context.auth)
return
repeat_message: context.auth.uid + ' ' + data.message,
repeat_count: data.count + 1,
;
else
return
repeat_message: ' noUID ' + data.message,
repeat_count: data.count + 1,
;
);
以及对应的 Flutter Client 应用:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:cloud_functions/cloud_functions.dart';
final FirebaseAuth _fAuth = FirebaseAuth.instance;
final GoogleSignIn _googleSignIn = GoogleSignIn(scopes: ['email'], signInOption: SignInOption.standard);
FirebaseUser _firebaseUser;
GoogleSignInAccount _googleSignInAccount;
void main()
runApp(new MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return MaterialApp(
theme: ThemeData(
textTheme: TextTheme(
caption: TextStyle(
fontSize: 20.0
),
body1: TextStyle(
fontSize: 20.0
),
),
),
title: 'calling function',
debugShowCheckedModeBanner: false,
home: LaunchScreen(),
);
class LaunchScreen extends StatefulWidget
@override
_LaunchScreenState createState()
return _LaunchScreenState();
// LoggingOptions to _LaunchScreenState
class _LaunchScreenState extends State<LaunchScreen>
String _response = 'no response';
int _responseCount = 1;
final HttpsCallable callable = CloudFunctions.instance.getHttpsCallable(functionName: 'repeat')
..timeout = const Duration(seconds: 90);
Future<FirebaseUser> _handleSignIn() async
try
GoogleSignInAccount googleSignInAccount = await _googleSignIn.signIn();
_googleSignInAccount = googleSignInAccount;
GoogleSignInAuthentication authentication = await googleSignInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.getCredential(
accessToken: authentication.accessToken, idToken: authentication.idToken,
);
AuthResult authResult;
authResult = await _fAuth.signInWithCredential( credential);
_firebaseUser = authResult.user;
setState(() );
return _firebaseUser;
catch (e)
print(e.toString());
return null;
Future<void> _handleSignOut() async
FirebaseAuth.instance.signOut();
_googleSignIn.signOut();
setState(()
_firebaseUser =null;
_googleSignInAccount= null;
);
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar( title: const Text('Sample Code'),),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
MaterialButton(
child: const Text( 'Sign in with Google', style: TextStyle(fontSize: 16.0),),
onPressed: ()
_handleSignIn().then((user)
// logggedIn
debugPrint('user ' + user.toString());
);
,
),
MaterialButton(
child: const Text( 'Sign out with Google', style: TextStyle(fontSize: 16.0),),
onPressed: ()
_handleSignOut();
,
),
Text( _firebaseUser != null ? _firebaseUser.uid : 'user logged off'),
Text('FromServer $_responseCount: $_response'),
MaterialButton(
child: const Text('SEND REQUEST', style: TextStyle(fontSize: 18.0),),
onPressed: () async
try
final HttpsCallableResult result = await callable.call(
<String, dynamic>
'message': 'hello',
'count': _responseCount,
,
);
print(result.data);
setState(()
_response = result.data['repeat_message'];
_responseCount = result.data['repeat_count'];
);
on CloudFunctionsException catch (e)
print('caught Firebase functions exception');
print(e.code);
print(e.message);
print(e.details);
catch (e)
print('caught generic exception');
print(e);
,
),
],
),
));
我可以在服务器日志和客户端看到Auth
被正确传递。
但是当我将allAuthenticatedUsers
添加到“Cloud Functions Invoker”角色from the function 并删除allUsers
时,应用程序开始使用未经身份验证的代码获取PlatformException
。
以下是更改前的设置:
加上allAuthenticatedUsers
之后:
删除allUsers
后:
那么当Flutter调用函数时(当用户登录时),Flutter报错与
PlatformException(functionsError, Cloud 函数失败 异常。,消息:未经身份验证,详细信息:空,代码: 未经身份验证)
它应该只在用户未登录时显示错误,但在任何一种情况下都会显示。
【问题讨论】:
【参考方案1】:allAuthenticatedUsers 的云配置与 Firebase 以及它对可调用类型函数的身份验证没有任何关系。 Firebase 可调用函数与您更改的配置分开处理自己的身份验证。如果您希望可调用对象正常工作,则应将其改回。
您删除的 allUsers 权限负责让公众(包括您的应用)可以访问您的函数。当您删除它时,您实际上删除了互联网上任何人都能够调用该函数的能力(这是可调用函数按设计运行所必需的)。
当您添加 allAuthenticatedUsers 时,您所做的只是要求调用者使用 Google 服务帐户进行身份验证。同样,这与 Firebase 或 Firebase Auth 无关。这是一个 Google Cloud IAM 概念。它不适用于可调用函数,因此您不应该使用它。我不清楚你为什么认为这是一个很好的配置。
如果您希望应用程序正常调用 Firebase 可调用函数,则应将权限保留为默认 allUsers,并让 Firebase SDK 处理最终用户的身份验证。
阅读有关Google Cloud access control lists 的更多信息,以了解您正在更改的云配置。
【讨论】:
它按设计工作。如果您不希望未经身份验证的 Firebase Auth 用户调用它,如果未定义context.auth
,则应尽早退出该函数。这是您唯一的选择。您无法阻止互联网上的任何人调用该函数,但您可以阻止他们在没有身份验证的情况下运行您的代码。
这个 callable 可以被调用 curl -X POST -d ' "data": "count":2,"message":"any message"' 'us-central1-xyz.cloudfunctions.net/repeat ' -H "Content-Type:application/json" 这就是我想要避免的
我知道 - 我理解您删除的最后一条评论,我是说无法完全切断未经身份验证的用户的访问。如果用户通过身份验证,您必须签入您的代码,如果没有,则提前返回。如果您想要不同的行为,请直接联系 Firebase 支持以提交功能请求。 support.google.com/firebase/contact/support
使用 allUsers 是一个 BAD 解决方案。 firebase express 功能的解决方案是什么? (不能context.auth
)。我正在通过 Flutter 使用短信验证以上是关于Firebase 用户的 context.auth 仍然存在 allAuthenticatedUsers secure Google function error with UNAUTHENTICAT的主要内容,如果未能解决你的问题,请参考以下文章