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'] || '' }