我可以跳过 Firebase 中无密码登录方法的第一步吗?
Can I skip the first step in the passwordless signin method in Firebase?
我有一份包含所有个人信息(姓名、名字、出生日期、电子邮件等)的人员名单。我想向这些人中的每个人发送一封电子邮件,其中包含 link允许他们在点击后直接连接到我们的网站。无需输入密码。
我按照 Firebase 程序进行无密码身份验证:
- 从后面回到 Python。 Generate email link for connexion
- 在AngularJs的前面。 Completing signin in a web page
- Fireship.io tutorial
但大多数示例不太适合我的用例。
大部分例子:
- 用户访问您的网站,要求无密码身份验证,输入他的电子邮件,(电子邮件存储在
window.location.href
)
- 用户收到一封包含 link 登录的电子邮件,他点击它
- 用户在您的网站上,已登录(感谢他在
window.location.href
中存储的电子邮件)。
我的用例:
- None。我已经有我的用户的电子邮件,所以我直接给他发送 link 连接。
- 用户收到一封包含 link 登录的电子邮件,他点击它
- 用户在我的网站上,但必须在提示中再次输入他的电子邮件(因为它显然没有存储在
window.location.href
中)。
在我的例子中,永远不会使用 window.location.href
变量。而且我不希望我的用户在单击 link 后必须重新输入他的电子邮件。既然我已经有他的邮箱了,何必再问他?
那我怎样才能跳过这一步呢?这样做有安全隐患吗?
到目前为止,这是我的代码:
返回:
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)
}
编辑
问题是当用户第一次使用link访问我们的网站时,前台不知道用户的电子邮件。有一种方法可以将 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
信息从后面传递到前面,这样用户在点击我的“魔法link重定向到我的网站时就不必再次输入了]" ?
要求用户键入 his/her 电子邮件与将其存储在 window
存储中没有安全风险,有人可能会争辩说它实际上 更多 确保这样做。就是说,您如何着手这样做:
- 确保您已启用电子邮件无密码身份验证。
- 使用管理 SDK,add each email address to your auth table(虽然我不会设置
emailVerified: true
- 当他们点击魔术 link 并在登录时验证自己时会发生这种情况。
- 再次使用管理 SDK,generate a magic link 为每个用户发送给他们。
- 在您的登录页面(魔术 link 带他们去的地方),提示他们输入他们的电子邮件地址,然后将其与魔术 link 一起使用以进行身份验证。 sample code provided from Firebase 向您展示了如何在代码的
if(!email){ ... }
部分执行此操作,它使用 window 提示收集用户的电子邮件,以防用户单击 link单独的设备或浏览器未t/couldn存储电子邮件地址。
如果您已经有用户的电子邮件,您可以在客户端 JavaScript SDK (docs), or generateSignInWithEmailLink
in the server-side Node.js SDK (docs) 中使用该电子邮件调用 firebase.auth().sendSignInLinkToEmail
。两个调用都将用户的电子邮件作为参数。
一旦用户点击 link 进入您的网站,您就可以 access their profile with an auth state listener 这样:
firebase.auth().onAuthStateChanged((user) => {
if (user) {
var uid = user.uid;
var email = user.email;
}
});
您可以做的一件事是在后端创建一个一次性令牌 links 到您用户的电子邮件(或 links 到 firestore 中的文档)并拥有在 url 中。当用户进入页面时,使用令牌(可以只是一个简单的 uuid)调用您的后端并让您的后端登录用户然后 expire/remove 使用该令牌。
例如
https://yoursite.com/44ed3716-2b8f-4068-a445-b05a8fee17c3
前端发送 44ed3716-2b8f-4068-a445-b05a8fee17c3
到后端...后端看到令牌,登录,然后使该令牌不再有效。
更新
在下面的评论中回答您关于不再需要通过 firebase 进行电子邮件 link 身份验证的问题:不一定。到那时,您有点像是在创建自己的电子邮件登录系统(实际上并不太难)并且有点重新发明轮子。向 url 添加令牌只是一种将用户与电子邮件相关联的方式,而无需实际将电子邮件放入 url 以便您的前端可以在您的 link 被点击。后台给你发邮件后,你可以把它存到本地,然后正常完成firebase登录。
我有一份包含所有个人信息(姓名、名字、出生日期、电子邮件等)的人员名单。我想向这些人中的每个人发送一封电子邮件,其中包含 link允许他们在点击后直接连接到我们的网站。无需输入密码。
我按照 Firebase 程序进行无密码身份验证:
- 从后面回到 Python。 Generate email link for connexion
- 在AngularJs的前面。 Completing signin in a web page
- Fireship.io tutorial
但大多数示例不太适合我的用例。
大部分例子:
- 用户访问您的网站,要求无密码身份验证,输入他的电子邮件,(电子邮件存储在
window.location.href
) - 用户收到一封包含 link 登录的电子邮件,他点击它
- 用户在您的网站上,已登录(感谢他在
window.location.href
中存储的电子邮件)。
我的用例:
- None。我已经有我的用户的电子邮件,所以我直接给他发送 link 连接。
- 用户收到一封包含 link 登录的电子邮件,他点击它
- 用户在我的网站上,但必须在提示中再次输入他的电子邮件(因为它显然没有存储在
window.location.href
中)。
在我的例子中,永远不会使用 window.location.href
变量。而且我不希望我的用户在单击 link 后必须重新输入他的电子邮件。既然我已经有他的邮箱了,何必再问他?
那我怎样才能跳过这一步呢?这样做有安全隐患吗?
到目前为止,这是我的代码:
返回:
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)
}
编辑
问题是当用户第一次使用link访问我们的网站时,前台不知道用户的电子邮件。有一种方法可以将 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
信息从后面传递到前面,这样用户在点击我的“魔法link重定向到我的网站时就不必再次输入了]" ?
要求用户键入 his/her 电子邮件与将其存储在 window
存储中没有安全风险,有人可能会争辩说它实际上 更多 确保这样做。就是说,您如何着手这样做:
- 确保您已启用电子邮件无密码身份验证。
- 使用管理 SDK,add each email address to your auth table(虽然我不会设置
emailVerified: true
- 当他们点击魔术 link 并在登录时验证自己时会发生这种情况。 - 再次使用管理 SDK,generate a magic link 为每个用户发送给他们。
- 在您的登录页面(魔术 link 带他们去的地方),提示他们输入他们的电子邮件地址,然后将其与魔术 link 一起使用以进行身份验证。 sample code provided from Firebase 向您展示了如何在代码的
if(!email){ ... }
部分执行此操作,它使用 window 提示收集用户的电子邮件,以防用户单击 link单独的设备或浏览器未t/couldn存储电子邮件地址。
如果您已经有用户的电子邮件,您可以在客户端 JavaScript SDK (docs), or generateSignInWithEmailLink
in the server-side Node.js SDK (docs) 中使用该电子邮件调用 firebase.auth().sendSignInLinkToEmail
。两个调用都将用户的电子邮件作为参数。
一旦用户点击 link 进入您的网站,您就可以 access their profile with an auth state listener 这样:
firebase.auth().onAuthStateChanged((user) => {
if (user) {
var uid = user.uid;
var email = user.email;
}
});
您可以做的一件事是在后端创建一个一次性令牌 links 到您用户的电子邮件(或 links 到 firestore 中的文档)并拥有在 url 中。当用户进入页面时,使用令牌(可以只是一个简单的 uuid)调用您的后端并让您的后端登录用户然后 expire/remove 使用该令牌。
例如
https://yoursite.com/44ed3716-2b8f-4068-a445-b05a8fee17c3
前端发送 44ed3716-2b8f-4068-a445-b05a8fee17c3
到后端...后端看到令牌,登录,然后使该令牌不再有效。
更新
在下面的评论中回答您关于不再需要通过 firebase 进行电子邮件 link 身份验证的问题:不一定。到那时,您有点像是在创建自己的电子邮件登录系统(实际上并不太难)并且有点重新发明轮子。向 url 添加令牌只是一种将用户与电子邮件相关联的方式,而无需实际将电子邮件放入 url 以便您的前端可以在您的 link 被点击。后台给你发邮件后,你可以把它存到本地,然后正常完成firebase登录。