UNPKG

@cloudbase/node-sdk

Version:

tencent cloud base server sdk for node.js

241 lines (212 loc) 6.24 kB
import jwt from 'jsonwebtoken' import { E } from '../utils/utils' import { ERROR } from '../const/code' import { CloudBase } from '../cloudbase' import { SYMBOL_CURRENT_ENV, SYMBOL_DEFAULT_ENV } from '../const/symbol' import * as tcbapicaller from '../utils/tcbapirequester' import * as tcbopenapicommonrequester from '../utils/tcbopenapicommonrequester' import { IContextParam, ICustomReqOpts, IUserInfoQuery, IGetAuthContextResult, IGetUserInfoResult, IGetEndUserInfoResult } from '../../types' const checkCustomUserIdRegex = /^[a-zA-Z0-9_\-#@~=*(){}[\]:.,<>+]{4,32}$/ function validateUid(uid: string): void { if (typeof uid !== 'string') { throw E({ ...ERROR.INVALID_PARAM, message: 'uid must be a string' }) } if (!checkCustomUserIdRegex.test(uid)) { throw E({ ...ERROR.INVALID_PARAM, message: `Invalid uid: "${uid}"` }) } } export class Auth { private readonly cloudbase: CloudBase public constructor(cloudbase: CloudBase) { this.cloudbase = cloudbase } public async getAuthContext(context: IContextParam): Promise<IGetAuthContextResult> { const { TCB_UUID, LOGINTYPE, QQ_OPENID, QQ_APPID } = CloudBase.getCloudbaseContext(context) const result: any = { uid: TCB_UUID, loginType: LOGINTYPE } if (LOGINTYPE === 'QQ-MINI') { result.appId = QQ_APPID result.openId = QQ_OPENID } return result } public getClientIP(): string { const { TCB_SOURCE_IP } = CloudBase.getCloudbaseContext() return TCB_SOURCE_IP || '' } public getUserInfo(): IGetUserInfoResult { const { WX_OPENID, WX_APPID, TCB_UUID, TCB_CUSTOM_USER_ID, TCB_ISANONYMOUS_USER } = CloudBase.getCloudbaseContext() return { openId: WX_OPENID || '', appId: WX_APPID || '', uid: TCB_UUID || '', customUserId: TCB_CUSTOM_USER_ID || '', isAnonymous: TCB_ISANONYMOUS_USER === 'true' } } public async getEndUserInfo(uid?: string, opts?: ICustomReqOpts): Promise<IGetEndUserInfoResult> { const { WX_OPENID, WX_APPID, TCB_UUID, TCB_CUSTOM_USER_ID, TCB_ISANONYMOUS_USER } = CloudBase.getCloudbaseContext() const defaultUserInfo = { openId: WX_OPENID || '', appId: WX_APPID || '', uid: TCB_UUID || '', customUserId: TCB_CUSTOM_USER_ID || '', isAnonymous: TCB_ISANONYMOUS_USER === 'true' } if (uid === undefined) { return await Promise.resolve({ userInfo: defaultUserInfo }) } validateUid(uid) return await tcbapicaller.request({ config: this.cloudbase.config, params: { action: 'auth.getUserInfoForAdmin', uuid: uid }, method: 'post', opts, headers: { 'content-type': 'application/json' } }).then(result => { if (result.code) { return result } return { userInfo: { ...defaultUserInfo, ...result.data }, requestId: result.requestId } }) } public async queryUserInfo(query: IUserInfoQuery, opts?: ICustomReqOpts): Promise<any> { const { uid, platform, platformId } = query return await tcbapicaller.request({ config: this.cloudbase.config, params: { action: 'auth.getUserInfoForAdmin', uuid: uid, platform, platformId }, method: 'post', opts, headers: { 'content-type': 'application/json' } }).then(result => { if (result.code) { return result } return { userInfo: { ...result.data }, requestId: result.requestId } }) } public async getClientCredential(opts?: ICustomReqOpts): Promise<any> { // 如果有 accessKey 直接返回 accessKey,不用再去换取 token if (this.cloudbase.config.accessKey) { return this.cloudbase.config.accessKey } return await tcbopenapicommonrequester.request({ config: this.cloudbase.config, method: 'POST', opts, headers: { 'content-type': 'application/json' }, path: '/auth/v1/token/clientCredential', data: { grant_type: 'client_credentials' } }).then(result => { return result.body }) } public createTicket(uid: string, options: any = {}): string { validateUid(uid) const timestamp = new Date().getTime() const { TCB_ENV, SCF_NAMESPACE } = CloudBase.getCloudbaseContext() const { credentials } = this.cloudbase.config /* eslint-disable-next-line */ const { env_id } = credentials let { envName } = this.cloudbase.config if (!envName) { throw E({ ...ERROR.INVALID_PARAM, message: 'no env in config' }) } // 检查 credentials 是否包含 env if (!env_id) { throw E({ ...ERROR.INVALID_PARAM, message: '当前私钥未包含env_id 信息, 请前往腾讯云云开发控制台,获取自定义登录最新私钥' }) } // 使用symbol时替换为环境变量内的env if (envName === SYMBOL_CURRENT_ENV) { envName = TCB_ENV || SCF_NAMESPACE } else if (envName === SYMBOL_DEFAULT_ENV) { // nothing to do } // 检查 credentials env 和 init 指定 env 是否一致 if (env_id && env_id !== envName) { throw E({ ...ERROR.INVALID_PARAM, message: '当前私钥所属环境与 init 指定环境不一致!' }) } if (!Reflect.has(options, 'allowInsecureKeySizes')) { options.allowInsecureKeySizes = true } const { refresh = 3600 * 1000, expire = timestamp + 7 * 24 * 60 * 60 * 1000 } = options const token = jwt.sign( { alg: 'RS256', env: envName, iat: timestamp, exp: timestamp + 10 * 60 * 1000, // ticket十分钟有效 uid, refresh, expire }, credentials.private_key, { allowInsecureKeySizes: options.allowInsecureKeySizes === true, algorithm: 'RS256' } ) return credentials.private_key_id + '/@@/' + token } } export function auth(cloudbase: CloudBase): Auth { return new Auth(cloudbase) }