我可以跳过 Firebase 中无密码登录方法的第一步吗?
Posted
技术标签:
【中文标题】我可以跳过 Firebase 中无密码登录方法的第一步吗?【英文标题】:Can I skip the first step in the passwordless signin method in Firebase? 【发布时间】:2021-10-13 01:02:03 【问题描述】:我有一个包含所有个人信息(姓名、名字、出生日期、电子邮件等)的人员列表。我想向每个人发送一封电子邮件,其中包含允许他们点击的链接,直接连接到我们的网站。无需输入密码。
我按照 Firebase 程序进行无密码身份验证:
在 Python 中从后面返回。 Generate email link for connexion 用于 Angular Js 中的前端。 Completing signin in a web page Fireship.io tutorial但大多数示例不太适合我的用例。
大部分例子:
-
用户访问您的网站,要求进行无密码身份验证,输入他的电子邮件,(电子邮件存储在
window.location.href
)
用户收到一封包含登录链接的电子邮件,他点击它
用户在您的网站上,已登录(感谢他存储在window.location.href
中的电子邮件)。
我的用例:
-
无。我已经有了用户的电子邮件,所以我直接将链接发送给他。
用户收到一封包含登录链接的电子邮件,他点击它
用户在我的网站上,但必须在提示符中再次输入他的电子邮件(因为它显然没有存储在
window.location.href
中)。
在我的例子中,window.location.href
变量永远不会被使用。而且我不希望我的用户在单击链接后必须重新输入他的电子邮件。既然我已经有了他的邮箱,为什么还要再问他呢?
那么我该如何跳过这一步呢?这样做有什么安全风险吗?
这是我目前的代码:
返回:
import firebase_admin
from firebase_admin import auth
from google.cloud import firestore
def create_new_auth(dictionary):
user = auth.create_user(
email=dictionary['email'],
email_verified=True,
phone_number=dictionary['phone'],
password='super_secure_password_007',
display_name=f"dictionary['firstName'] dictionary['lastName']",
disabled=False)
print('Sucessfully created new user: 0'.format(user.uid))
return user.uid
def create_new_pre_user(db, dictionary, uid):
dictionary =
'uid': uid,
'email': dictionary['email'],
'lastName': dictionary['lastName'],
'gender': dictionary['gender'],
'birthday': dictionary['birthday'],
'phone': dictionary['phone'],
'firstName': dictionary['firstName']
db.collection(u'users').document(uid).set(dictionary)
def main(dictionary):
firebase_admin.initialize_app()
db = firestore.Client()
uid = create_new_auth(dictionary)
create_new_pre_user(db, dictionary, uid)
action_code_settings = auth.ActionCodeSettings(
url=f'http://localhost:4200/login',
handle_code_in_app=True,
ios_bundle_id='com.example.ios',
android_package_name='com.example.android',
android_install_app=True,
android_minimum_version='12',
dynamic_link_domain='magic42.page.link',
)
link = auth.generate_sign_in_with_email_link(dictionary['email'], action_code_settings)
if __name__ == '__main__':
dictionary =
"firstName": "Jone",
"lastName": "Doe",
"birthday": 12345678,
"gender": "male",
"email": "john.doe@gmail.com",
"phone": "+33611223344"
main(dictionary)
前面:
private signInWithEmail()
if (this.authService.isSignInWithEmailLink(window.location.href))
// Additional state parameters can also be passed via URL.
// This can be used to continue the user's intended action before triggering
// the sign-in operation.
// Get the email if available. This should be available if the user completes
// the flow on the same device where they started it.
let email = window.localStorage.getItem('emailForSignIn');
if (!email)
// User opened the link on a different device. To prevent session fixation
// attacks, ask the user to provide the associated email again. For example:
email = window.prompt('Please provide your email for confirmation');
// The client SDK will parse the code from the link for you.
this.authService.signInWithEmailLink(email, window.location.href)
.then((result) =>
// Clear email from storage.
window.localStorage.removeItem('emailForSignIn');
// You can access the new user via result.user
// Additional user info profile not available via:
// result.additionalUserInfo.profile == null
// You can check if the user is new or existing:
// result.additionalUserInfo.isNewUser
this.router.navigate(['/patient', 'quiz'])
)
.catch((error) =>
// Some error occurred, you can inspect the code: error.code
// Common errors could be invalid email and invalid or expired OTPs.
);
isSignInWithEmailLink(href)
return this.afAuth.auth.isSignInWithEmailLink(href);
signInWithEmailLink(email: string, href: string)
return this.afAuth.auth.signInWithEmailLink(email, href)
编辑
问题是,当他第一次使用链接访问我们的网站时,前台不知道用户的电子邮件。有一种方法可以将 email
信息从我们的服务器端传递到前端,但它在 URL 中很清楚:根据 Firebase 本身,这是有风险的并且不是一个好的做法 (link)
像这样:
def main(dictionary):
firebase_admin.initialize_app()
db = firestore.Client()
uid = create_new_auth(dictionary)
create_new_pre_user(db, dictionary, uid)
action_code_settings = auth.ActionCodeSettings(
url=f'http://localhost:4200/login/?email=john.doe@gmail.com',
handle_code_in_app=True,
ios_bundle_id='com.example.ios',
android_package_name='com.example.android',
android_install_app=True,
android_minimum_version='12',
dynamic_link_domain='magic42.page.link',
)
link = auth.generate_sign_in_with_email_link(dictionary['email'], action_code_settings)
那么如何将email
信息从后面传递到前面,以便用户在单击我的“魔术链接”后重定向到我的网站时不必再次输入?
【问题讨论】:
我不确定我是否理解问题所在。 “我已经有了用户的电子邮件,所以我直接将链接发送给他以进行连接。”在这种情况下,是什么阻止您立即使用用户的电子邮件地址调用 API? 调用哪个API?创建一个新的认证用户?或者将所有信息添加到 Firestore 集合中?我的问题是:我想创建一个链接,单击后立即登录用户,而无需输入电子邮件或密码,什么都没有。我认为深层链接已经以某种方式包含了用户的电子邮件。我想我可以使用它,而不是在我的网站上重定向时再次要求用户输入它。 【参考方案1】:您可以做的一件事是在后端创建一个一次性令牌,该令牌链接到您的用户电子邮件(或链接到 Firestore 中的文档),并将其放在 url 中。当用户进入页面时,使用令牌(可能只是一个简单的 uuid)调用您的后端,并让您的后端让用户登录,然后使该令牌过期/不再使用。
例如
https://yoursite.com/44ed3716-2b8f-4068-a445-b05a8fee17c3
前端将44ed3716-2b8f-4068-a445-b05a8fee17c3
发送到后端...后端看到令牌,将其登录,然后使该令牌不再有效。
更新
在下面的 cmets 中回答您关于不再需要通过 firebase 进行电子邮件链接身份验证的问题:不一定。那时,您正在创建自己的电子邮件登录系统(实际上并不太难),并且在某种程度上重新发明了***。向 url 添加令牌只是一种将用户与电子邮件相关联的方式,而无需将电子邮件实际放入 url,以便您的前端可以在单击链接后知道用户是谁。后端将邮件发送给您后,您可以将其存储在本地存储并正常使用 firebase 完成登录。
【讨论】:
好的,所以要清楚我不再需要email link
类型身份验证了吗?前端如何将令牌发送到后端?【参考方案2】:
要求用户键入他/她的电子邮件而不是将其存储在window
存储中没有安全风险,有人可能会争辩说这样做实际上更安全。也就是说,你可以如何去做:
-
确保您已启用电子邮件无密码身份验证。
使用管理 SDK,add each email address to your auth table(虽然我不会设置
emailVerified: true
- 当他们单击魔术链接并在登录时验证自己时会发生这种情况。
再次使用管理 SDK,generate a magic link 为每个用户发送给他们。
在您的登录页面(魔术链接将他们带到那里),提示他们输入他们的电子邮件地址,然后将其与魔术链接一起使用以进行身份验证。 sample code provided from Firebase 在代码的 if(!email) ...
部分向您展示了如何执行此操作,它使用窗口提示来收集用户的电子邮件,以防用户单击单独设备上的链接或浏览器没有/无法t 存储电子邮件地址。
【讨论】:
感谢您的回答,但我不希望用户再次输入他的电子邮件,因为我已经有了它。我希望我的用户单击魔术链接并登录 BOOM。【参考方案3】:如果您已经拥有用户的电子邮件,您可以在客户端 javascript SDK (docs) 中使用该电子邮件调用 firebase.auth().sendSignInLinkToEmail
,或在服务器端 Node.js SDK (docs) 中调用 generateSignInWithEmailLink
)。两个调用都将用户的电子邮件作为参数。
一旦用户点击链接后登陆您的网站,您可以像这样access their profile with an auth state listener:
firebase.auth().onAuthStateChanged((user) =>
if (user)
var uid = user.uid;
var email = user.email;
);
【讨论】:
我确实有用户的电子邮件,但只在服务器端。我的代码位于 GCP 云函数中。就像我的代码中描述的那样,我已经在使用generate_sign_in_with_email_link
(在 python 中)来生成链接。这可以。现在,由于用户从未访问过我的网站,当他点击我给他的链接时,它将被重定向到我的网站,而没有使用变量 window.location.href
。前线不知道他的电子邮件。所以他将不得不在提示中再次输入他的电子邮件。这是我想摆脱的额外步骤。 (如何将邮件传递到前台?)
如果用户在单击链接后访问您的网站,他们将登录,您可以使用身份验证状态侦听器访问他们的详细信息,如下所示:firebase.google.com/docs/auth/web/…
点击我给他的链接后,用户将被重定向到我的网站,但他不会自动登录。在他在提示中手动输入他的电子邮件之前不会。 (这是我想要摆脱的步骤)。 Auth 状态监听器在这里没有用。我只是测试了它,它没有帮助。当然我可以得到用户的uid
和email
,但是在他手动输入他的电子邮件到提示符之后。我怎样才能绕过它?以上是关于我可以跳过 Firebase 中无密码登录方法的第一步吗?的主要内容,如果未能解决你的问题,请参考以下文章
如果用户已经无密码登录,firebase 可以设置密码身份验证吗?
如何只允许我的应用在没有登录的情况下访问 firebase?
Linux centos 跳过管理员密码进行登录(单用户模式救援模式)