本来想使用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)
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注