| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- /**
- * 云函数共享的 Parse 登录态工具。
- *
- * 浏览器侧为了兼容旧接口仍可能传入 userId,但用户私有数据归属必须由
- * Parse sessionToken 在服务端解析得到。不要信任前端传入的 request.userId。
- */
- const DEFAULT_PARSE_API_HOST = env('PARSE_API_HOST', env('PARSE_BASE_URL', 'https://server.fmode.cn'));
- const DEFAULT_PARSE_APP_ID = env('PARSE_APP_ID', env('PARSE_APPLICATION_ID', 'ncloudmaster'));
- async function requireSession(request, _psql) {
- const sessionToken = clean(pickParam(request, 'sessionToken') || headerValue(request, 'x-parse-session-token'));
- if (!sessionToken) {
- const error = new Error('请先登录');
- error.status = 401;
- throw error;
- }
- const user = await parseMe(sessionToken);
- if (!user || !user.objectId) {
- const error = new Error('登录已失效,请重新登录');
- error.status = 401;
- throw error;
- }
- return {
- sessionToken,
- user,
- userId: user.objectId,
- role: normalizeRole(user),
- };
- }
- async function optionalSession(request, psql) {
- try {
- return await requireSession(request, psql);
- } catch {
- return null;
- }
- }
- async function requireAdmin(request, psql) {
- const session = await requireSession(request, psql);
- if (session.role !== 'admin') {
- const error = new Error('需要管理员权限');
- error.status = 403;
- throw error;
- }
- return session;
- }
- function assertRequestedUserMatchesSession(request, session) {
- const requestedUserId = clean(pickParam(request, 'userId'));
- if (requestedUserId && requestedUserId !== session.userId) {
- const error = new Error('没有访问该账号数据的权限');
- error.status = 403;
- throw error;
- }
- }
- async function parseMe(sessionToken) {
- const base = String(DEFAULT_PARSE_API_HOST || '').replace(/\/+$/, '').replace(/\/parse$/i, '');
- const resp = await fetch(`${base}/parse/users/me?include=company`, {
- method: 'GET',
- headers: {
- 'Accept': 'application/json',
- 'X-Parse-Application-Id': DEFAULT_PARSE_APP_ID,
- 'X-Parse-Session-Token': sessionToken,
- },
- });
- const data = await resp.json().catch(() => ({}));
- if (!resp.ok) {
- const error = new Error(data.error || data.message || '登录已失效,请重新登录');
- error.status = resp.status || 401;
- error.detail = data;
- throw error;
- }
- return data;
- }
- function normalizeRole(user) {
- const raw = String(user?.role || user?.userRole || user?.type || '').toLowerCase();
- if (raw === 'admin' || user?.isAdmin === true || user?.admin === true) return 'admin';
- return 'user';
- }
- function pickParam(request, ...names) {
- const sources = [request?.params, request?.body, request?.query, request];
- for (const src of sources) {
- if (!src || typeof src !== 'object') continue;
- for (const name of names) {
- const value = src[name];
- if (value !== undefined && value !== null && value !== '') return value;
- }
- }
- return null;
- }
- function headerValue(request, name) {
- const headers = request?.headers || {};
- const target = String(name || '').toLowerCase();
- for (const key of Object.keys(headers)) {
- if (key.toLowerCase() === target) return headers[key];
- }
- return '';
- }
- function clean(value) {
- return String(value || '').trim();
- }
- function env(name, fallback = '') {
- if (typeof process !== 'undefined' && process.env && process.env[name] !== undefined) {
- return process.env[name];
- }
- return fallback;
- }
- module.exports = {
- requireSession,
- optionalSession,
- requireAdmin,
- assertRequestedUserMatchesSession,
- pickParam,
- clean,
- };
|