文件
jw-beauty/cloud/functions/auth/index.js
T

137 行
3.8 KiB
JavaScript

var db = require('../../common/db')
var auth = require('../../common/auth')
var log = require('../../common/log')
var RESPONSE = require('../../common/response').RESPONSE
var ERROR_CODES = require('../../common/response').ERROR_CODES
exports.main_handler = async function (event) {
try {
var method = event.httpMethod || 'GET'
var path = event.path || ''
var body = parseBody(event)
if (method === 'POST' && path === '/api/v1/auth/login') {
return await wxLogin(body, event)
}
if (method === 'POST' && path === '/api/v1/auth/refresh') {
return await refreshToken(body)
}
return RESPONSE.error(ERROR_CODES.PARAM_ERROR.code, 'unknown route')
} catch (err) {
console.error('auth error:', err)
return RESPONSE.error(ERROR_CODES.SERVER_ERROR.code, err.message)
}
}
async function wxLogin(body, event) {
if (!body.code) {
return RESPONSE.error(ERROR_CODES.PARAM_ERROR.code, 'missing code')
}
var wxResult = await requestWxSession(body.code)
if (!wxResult || !wxResult.openid) {
return RESPONSE.error(ERROR_CODES.INVALID_TOKEN.code, 'wechat login failed')
}
var users = await db.query(
'SELECT id, openid, nickname, avatar_url, phone, status FROM users WHERE openid = ? AND deleted_at IS NULL LIMIT 1',
[wxResult.openid]
)
var userId
var isNew = false
if (users.length === 0) {
var result = await db.insert(
'INSERT INTO users (openid, nickname, avatar_url, status) VALUES (?, ?, ?, 1)',
[wxResult.openid, body.nickname || null, body.avatar_url || null]
)
userId = result.insertId
isNew = true
} else {
userId = users[0].id
if (body.nickname || body.avatar_url) {
await db.update(
'UPDATE users SET nickname = COALESCE(?, nickname), avatar_url = COALESCE(?, avatar_url) WHERE id = ?',
[body.nickname || null, body.avatar_url || null, userId]
)
}
}
var token = auth.generateToken(userId, wxResult.openid)
await log.writeLog({
operator_type: 2,
operator_id: userId,
target_type: 'user',
target_id: String(userId),
action: isNew ? 'create' : 'login',
ip_address: getClientIp(event)
})
return RESPONSE.success({
token: token,
user_id: String(userId),
user_info: {
id: userId,
nickname: body.nickname || null,
avatar_url: body.avatar_url || null
},
expires_in: 604800
})
}
async function refreshToken(body) {
if (!body.refresh_token) {
return RESPONSE.error(ERROR_CODES.PARAM_ERROR.code, 'missing refresh_token')
}
var decoded = auth.verifyToken(body.refresh_token)
if (!decoded || decoded.type === 'admin') {
return RESPONSE.error(ERROR_CODES.TOKEN_EXPIRED.code, 'invalid refresh_token')
}
var token = auth.generateToken(decoded.user_id, decoded.openid)
return RESPONSE.success({
token: token,
expires_in: 604800
})
}
async function requestWxSession(code) {
var appId = process.env.WX_APPID || ''
var appSecret = process.env.WX_APP_SECRET || ''
var url = 'https://api.weixin.qq.com/sns/jscode2session?appid=' + appId +
'&secret=' + appSecret +
'&js_code=' + code +
'&grant_type=authorization_code'
var https = require('https')
return new Promise(function (resolve) {
https.get(url, function (res) {
var data = ''
res.on('data', function (chunk) { data += chunk })
res.on('end', function () {
try {
resolve(JSON.parse(data))
} catch (e) {
resolve(null)
}
})
}).on('error', function () { resolve(null) })
})
}
function parseBody(event) {
if (event.body) {
try { return JSON.parse(event.body) } catch (e) { return {} }
}
return event.queryStringParameters || {}
}
function getClientIp(event) {
var headers = event.headers || {}
return headers['x-forwarded-for'] || headers['X-Forwarded-For'] || headers['x-real-ip'] || ''
}