本来想使用oauth来实现登录,但是国内提供oauth服务要么比较小众,要么居然收费的?传统的用户注册登录使用起来过于繁琐了,很容易把用户挡在最开始的地方,最后决定添加邮箱验证码登录。
Parse Platform的文档中提到了一个Parse.User.become()
方法,但是需要传递一个session token进去,翻了很多遍文档也没发现该如何获取这个session_token,最后在Github仓库的issue中搜到2023年Parse增加了一个loginAs
方法,可以通过传递一个userId来将用户登陆进系统,那么通过云函数和Parse.User.become()
就可以实现邮箱验证码登录了。
服务端
1. 创建发送验证码函数
const VerifyCode = Parse.Object.extend('VerifyCode')
/**
* 发送邮件验证码
*/
Parse.Cloud.define('verifyCode', async (request) => {
const email = request.params.email
const code = generateRandomString(6)
// 记录验证码
const verifyCode = new VerifyCode()
verifyCode.set('email', email)
verifyCode.set('code', code)
verifyCode.set('expiredAt', new Date(Date.now() + 1000 * 60 * 5))
await verifyCode.save(null, { useMasterKey: true })
// 删除过期的验证码记录
const query = new Parse.Query(VerifyCode)
query.lessThan('expiredAt', new Date())
await Parse.Object.destroyAll(await query.find({ useMasterKey: true }), { useMasterKey: true })
// 发送邮件
await Parse.Cloud.sendEmail({
templateName: "verifyCode",
placeholders: { code },
recipient: email
});
}, {
fields: {
email: {
required: true,
type: String
}
},
requireUser: false
})
2. 创建登录函数
const VerifyCode = Parse.Object.extend('VerifyCode')
Parse.Cloud.define('login', async (request) => {
if (!request.params.email) {
throw new Parse.Error(Parse.Error.OTHER_CAUSE, '缺少email字段');
}
if (!request.params.code) {
throw new Parse.Error(Parse.Error.OTHER_CAUSE, '缺少code字段');
}
const query = new Parse.Query(Parse.User)
query.equalTo('email', request.params.email)
let user = await query.first({ useMasterKey: true })
if (user === undefined) {
throw new Parse.Error(Parse.Error.OTHER_CAUSE, '用户不存在');
}
// 验证
const codeQuery = new Parse.Query(VerifyCode)
codeQuery.equalTo('email', request.params.email)
codeQuery.equalTo('code', request.params.code)
codeQuery.greaterThan('expiredAt', new Date())
const code = await codeQuery.first({ useMasterKey: true })
if (code === undefined) {
throw new Parse.Error(Parse.Error.OTHER_CAUSE, '验证码已过期');
}
// 修改邮箱验证字段为验证通过状态
user.set('emailVerified', true)
user.save(null, { useMasterKey: true })
// 登录用户
user = await Parse.User.loginAs(user.id)
return user.getSessionToken()
}, {
fields: {
email: {
required: true,
type: String
},
code: {
required: true,
type: String
}
}
})
客户端
export async function emailLogin(email: string, code: string) {
const token = await Parse.Cloud.run('login', { email, code })
return await Parse.User.become(token)
}