增加通用的登录接口
This commit is contained in:
parent
099f1a8135
commit
15bb27eefa
@ -1,15 +1,11 @@
|
||||
import BaseController, { ROLE_ANON } from 'common/base.controller'
|
||||
import { role, router } from 'decorators/router'
|
||||
import verifyAppleToken from 'verify-apple-id-token'
|
||||
import { Account, PlatEnum } from 'modules/Account'
|
||||
import axios from 'axios'
|
||||
import logger from 'logger/logger'
|
||||
var https = require('follow-redirects').https
|
||||
|
||||
const CLIENT_ID_DEBUG = 'com.jc.tebg'
|
||||
const CLIENT_ID_RELEASE = 'com.cege.games.release'
|
||||
const CLIEND_ID_ANDROID = 'wallet.cebggame.com'
|
||||
import { PlatApple } from 'plats/PlatApple'
|
||||
import { IPlat } from 'plats/IPlat'
|
||||
|
||||
const plat: IPlat = new PlatApple()
|
||||
class AppleController extends BaseController {
|
||||
@role(ROLE_ANON)
|
||||
@router('post /apple/login-notify')
|
||||
@ -21,23 +17,8 @@ class AppleController extends BaseController {
|
||||
@role(ROLE_ANON)
|
||||
@router('post /wallet/login/apple')
|
||||
async checkGoogleJwt(req, res) {
|
||||
const { token } = req.params
|
||||
logger.db('login', req)
|
||||
const payload = await verifyAppleToken({
|
||||
idToken: token,
|
||||
clientId: [CLIENT_ID_DEBUG, CLIENT_ID_RELEASE, CLIEND_ID_ANDROID],
|
||||
})
|
||||
const openId = payload.sub
|
||||
let data: any = {}
|
||||
if (payload.email) data.email = payload.email
|
||||
if (payload.email_verified !== undefined) data.emailVerified = payload.email_verified
|
||||
if (payload.locale) data.locale = payload.locale
|
||||
if (payload.name) data.nickname = payload.name
|
||||
if (payload.picture) data.avatar = payload.picture
|
||||
const { api_platform } = req.headers
|
||||
if (api_platform) {
|
||||
data.platform = api_platform
|
||||
}
|
||||
const { openId, data } = await plat.verifyToken(req)
|
||||
let user = await Account.insertOrUpdate({ plat: PlatEnum.APPLE, openId }, data)
|
||||
const ztoken = await res.jwtSign({
|
||||
id: user.id,
|
||||
|
@ -3,8 +3,10 @@ import { ZError } from 'common/ZError'
|
||||
import { role, router } from 'decorators/router'
|
||||
import logger from 'logger/logger'
|
||||
import { Account, PlatEnum } from 'modules/Account'
|
||||
import { FACEBOOK_APP_ID, fetchUserInfo, verifyFbUserAccessToken } from 'providers/facebook.provider'
|
||||
import { IPlat } from 'plats/IPlat'
|
||||
import { PlatFacebook } from 'plats/PlatFacebook'
|
||||
|
||||
const plat: IPlat = new PlatFacebook()
|
||||
class FacebookController extends BaseController {
|
||||
@role(ROLE_ANON)
|
||||
@router('post /wallet/login/facebook')
|
||||
@ -14,41 +16,16 @@ class FacebookController extends BaseController {
|
||||
if (!code) {
|
||||
throw new ZError(10, 'params mismatch')
|
||||
}
|
||||
const result = await verifyFbUserAccessToken(code)
|
||||
if (!!result.error) {
|
||||
throw new ZError(10, `${result.error?.message} (${result.error?.code})`)
|
||||
}
|
||||
const { data } = result
|
||||
if (!data) {
|
||||
throw new ZError(11, 'no data from facebook')
|
||||
}
|
||||
if (data.app_id !== FACEBOOK_APP_ID) {
|
||||
throw new ZError(12, 'app id mismatch')
|
||||
}
|
||||
if (!data.is_valid) {
|
||||
throw new ZError(13, 'access_token not valid')
|
||||
}
|
||||
const infoRes = await fetchUserInfo(code)
|
||||
if (!!infoRes.error) {
|
||||
throw new ZError(13, `${infoRes.error?.message} (${infoRes.error.code})`)
|
||||
}
|
||||
const openId = infoRes.id || data.user_id
|
||||
let user: any = {}
|
||||
let now = Date.now() / 1000
|
||||
user.accessToken = code
|
||||
user.accessTokenExpire = result.data['expires_at']
|
||||
user.scope = data['scopes']
|
||||
if (infoRes['name']) user.nickname = infoRes['name']
|
||||
if (infoRes['email']) user.email = infoRes['email']
|
||||
const { openId, data } = await plat.verifyToken(req)
|
||||
const { api_platform } = req.headers
|
||||
if (api_platform) {
|
||||
user.platform = api_platform
|
||||
data.platform = api_platform
|
||||
}
|
||||
let account = await Account.insertOrUpdate({ plat: PlatEnum.FACEBOOK, openId }, user)
|
||||
let account = await Account.insertOrUpdate({ plat: PlatEnum.FACEBOOK, openId }, data)
|
||||
const ztoken = await res.jwtSign({
|
||||
id: account.id,
|
||||
openid: user.openId,
|
||||
version: user.accountVersion || 0,
|
||||
openid: account.openId,
|
||||
version: account.accountVersion || 0,
|
||||
plat: PlatEnum.FACEBOOK,
|
||||
})
|
||||
return { token: ztoken }
|
||||
|
@ -1,54 +1,19 @@
|
||||
import BaseController, { ROLE_ANON } from 'common/base.controller'
|
||||
import { ZError } from 'common/ZError'
|
||||
import { role, router } from 'decorators/router'
|
||||
|
||||
import { OAuth2Client } from 'google-auth-library'
|
||||
import logger from 'logger/logger'
|
||||
import { Account, PlatEnum } from 'modules/Account'
|
||||
import { customAlphabet } from 'nanoid'
|
||||
import { IPlat } from 'plats/IPlat'
|
||||
import { PlatGoogle } from 'plats/PlatGoogle'
|
||||
|
||||
const nanoid = customAlphabet('1234567890abcdef', 10)
|
||||
const GOOGLE_OAUTH_ISS = 'https://accounts.google.com'
|
||||
const GOOGLE_OAUTH_ISS1 = 'accounts.google.com'
|
||||
const IOS_TEST = '53206975661-0d6q9pqljn84n9l63gm0to1ulap9cbk4.apps.googleusercontent.com'
|
||||
const plat: IPlat = new PlatGoogle()
|
||||
|
||||
class GoogleController extends BaseController {
|
||||
@role(ROLE_ANON)
|
||||
@router('post /wallet/login/google')
|
||||
async checkGoogleJwt(req, res) {
|
||||
const { token } = req.params
|
||||
logger.db('login', req)
|
||||
const CLIENT_ID = process.env.GOOGLE_OAUTH_CLIENT
|
||||
const CLIENT_ID2 = process.env.GOOGLE_OAUTH_CLIENT2
|
||||
const CLIENT_ID_IOS = process.env.GOOGLE_OAUTH_CLIENT_IOS
|
||||
const client = new OAuth2Client(CLIENT_ID)
|
||||
const ticket = await client.verifyIdToken({
|
||||
idToken: token,
|
||||
audience: [CLIENT_ID, CLIENT_ID2, CLIENT_ID_IOS, IOS_TEST], // Specify the CLIENT_ID of the app that accesses the backend
|
||||
// Or, if multiple clients access the backend:
|
||||
//[CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]
|
||||
})
|
||||
const payload = ticket.getPayload()
|
||||
if (!(payload.iss === GOOGLE_OAUTH_ISS || payload.iss === GOOGLE_OAUTH_ISS1)) {
|
||||
throw new ZError(10, 'id token error')
|
||||
}
|
||||
if (
|
||||
payload.aud !== CLIENT_ID &&
|
||||
payload.aud !== CLIENT_ID2 &&
|
||||
payload.aud !== CLIENT_ID_IOS &&
|
||||
payload.aud !== IOS_TEST
|
||||
) {
|
||||
throw new ZError(11, 'client id mismatch')
|
||||
}
|
||||
const openId = payload.sub
|
||||
let data: any = {}
|
||||
if (payload.email) data.email = payload.email
|
||||
if (process.env.NODE_ENV !== 'development') {
|
||||
if (payload.email_verified !== undefined) data.emailVerified = payload.email_verified
|
||||
}
|
||||
if (payload.locale) data.locale = payload.locale
|
||||
if (payload.name) data.nickname = payload.name
|
||||
if (payload.picture) data.avatar = payload.picture
|
||||
const { openId, data } = await plat.verifyToken(req)
|
||||
const { api_platform } = req.headers
|
||||
if (api_platform) {
|
||||
data.platform = api_platform
|
||||
|
43
src/controllers/login.controller.ts
Normal file
43
src/controllers/login.controller.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { ZError } from 'common/ZError'
|
||||
import BaseController, { ROLE_ANON } from 'common/base.controller'
|
||||
import { role, router } from 'decorators/router'
|
||||
import logger from 'logger/logger'
|
||||
import { Account, PlatEnum } from 'modules/Account'
|
||||
import { IPlat } from 'plats/IPlat'
|
||||
import { PlatApple } from 'plats/PlatApple'
|
||||
import { PlatFacebook } from 'plats/PlatFacebook'
|
||||
import { PlatGoogle } from 'plats/PlatGoogle'
|
||||
import { PlatTikTok } from 'plats/PlatTikTok'
|
||||
|
||||
const plats: Map<PlatEnum, IPlat> = new Map([
|
||||
[PlatEnum.GOOGLE, new PlatGoogle()],
|
||||
[PlatEnum.APPLE, new PlatApple()],
|
||||
[PlatEnum.FACEBOOK, new PlatFacebook()],
|
||||
[PlatEnum.TIKTOK, new PlatTikTok()],
|
||||
])
|
||||
|
||||
class LoginController extends BaseController {
|
||||
@role(ROLE_ANON)
|
||||
@router('post /wallet/login/general')
|
||||
async generalLogin(req, res) {
|
||||
const { channel, account } = req.params
|
||||
logger.db('login', req)
|
||||
const plat = plats.get(channel)
|
||||
if (!plat) {
|
||||
throw new ZError(10, 'plat not found')
|
||||
}
|
||||
const { openId, data } = await plat.verifyToken(req)
|
||||
const { api_platform } = req.headers
|
||||
if (api_platform) {
|
||||
data.platform = api_platform
|
||||
}
|
||||
let user = await Account.insertOrUpdate({ plat: channel, openId }, data)
|
||||
const ztoken = await res.jwtSign({
|
||||
id: user.id,
|
||||
openid: user.openId,
|
||||
version: user.accountVersion || 0,
|
||||
plat: user.plat,
|
||||
})
|
||||
return { token: ztoken }
|
||||
}
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
import BaseController, { ROLE_ANON } from 'common/base.controller'
|
||||
import { ZError } from 'common/ZError'
|
||||
import { role, router } from 'decorators/router'
|
||||
import BaseController from 'common/base.controller'
|
||||
import { router } from 'decorators/router'
|
||||
import logger from 'logger/logger'
|
||||
import { Account } from 'modules/Account'
|
||||
|
||||
class MainController extends BaseController {
|
||||
@router('post /wallet/account/reset')
|
||||
|
@ -3,36 +3,28 @@ import { ZError } from 'common/ZError'
|
||||
import { role, router } from 'decorators/router'
|
||||
import logger from 'logger/logger'
|
||||
import { Account, PlatEnum } from 'modules/Account'
|
||||
import { IPlat } from 'plats/IPlat'
|
||||
import { PlatTikTok } from 'plats/PlatTikTok'
|
||||
import { fetchAccessToken, refreshAccessToken } from 'service/tiktok.svr'
|
||||
// 在tiktok的过期时间中, 减少一个小时
|
||||
const EXPIRE_REDUCE_SECOND = 3600
|
||||
|
||||
const plat: IPlat = new PlatTikTok()
|
||||
class TiktokController extends BaseController {
|
||||
@role(ROLE_ANON)
|
||||
@router('post /wallet/login/tiktok')
|
||||
async checkTiktokCode(req, res) {
|
||||
let { code } = req.params
|
||||
logger.db('login', req)
|
||||
let result = await fetchAccessToken(code)
|
||||
if (!(result.message === 'success' && result.data?.error_code === 0)) {
|
||||
throw new ZError(10, `${result.message}: ${result.data?.description} (${result.data?.error_code})`)
|
||||
}
|
||||
const openId = result.data['open_id']
|
||||
let user: any = {}
|
||||
let now = Date.now() / 1000
|
||||
user.accessToken = result.data['access_token']
|
||||
user.refreshToken = result.data['refresh_token']
|
||||
user.accessTokenExpire = now + result.data['expires_in'] - EXPIRE_REDUCE_SECOND
|
||||
user.refreshTokenExpire = now + result.data['refresh_expires_in'] - EXPIRE_REDUCE_SECOND
|
||||
user.scope = result.data['scope']
|
||||
const { openId, data } = await plat.verifyToken(req)
|
||||
const { api_platform } = req.headers
|
||||
if (api_platform) {
|
||||
user.platform = api_platform
|
||||
data.platform = api_platform
|
||||
}
|
||||
let account = await Account.insertOrUpdate({ plat: PlatEnum.TIKTOK, openId }, user)
|
||||
let account = await Account.insertOrUpdate({ plat: PlatEnum.TIKTOK, openId }, data)
|
||||
const ztoken = await res.jwtSign({
|
||||
id: account.id,
|
||||
openid: user.openId,
|
||||
version: user.accountVersion || 0,
|
||||
openid: account.openId,
|
||||
version: account.accountVersion || 0,
|
||||
plat: PlatEnum.TIKTOK,
|
||||
})
|
||||
return { token: ztoken }
|
||||
|
3
src/plats/IPlat.ts
Normal file
3
src/plats/IPlat.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export interface IPlat {
|
||||
verifyToken(req: any): Promise<any>
|
||||
}
|
32
src/plats/PlatApple.ts
Normal file
32
src/plats/PlatApple.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { OAuth2Client } from 'google-auth-library'
|
||||
import { IPlat } from './IPlat'
|
||||
import verifyAppleToken from 'verify-apple-id-token'
|
||||
import { ZError } from 'common/ZError'
|
||||
|
||||
const CLIENT_ID_DEBUG = 'com.jc.tebg'
|
||||
const CLIENT_ID_RELEASE = 'com.cege.games.release'
|
||||
const CLIEND_ID_ANDROID = 'wallet.cebggame.com'
|
||||
|
||||
export class PlatApple implements IPlat {
|
||||
async verifyToken(req: any): Promise<any> {
|
||||
let { code, token } = req.params
|
||||
code = code || token
|
||||
const payload = await verifyAppleToken({
|
||||
idToken: code,
|
||||
clientId: [CLIENT_ID_DEBUG, CLIENT_ID_RELEASE, CLIEND_ID_ANDROID],
|
||||
})
|
||||
const openId = payload.sub
|
||||
let data: any = {}
|
||||
if (payload.email) data.email = payload.email
|
||||
if (payload.email_verified !== undefined) data.emailVerified = payload.email_verified
|
||||
if (payload.locale) data.locale = payload.locale
|
||||
if (payload.name) data.nickname = payload.name
|
||||
if (payload.picture) data.avatar = payload.picture
|
||||
const { api_platform } = req.headers
|
||||
if (api_platform) {
|
||||
data.platform = api_platform
|
||||
}
|
||||
|
||||
return { openId, data }
|
||||
}
|
||||
}
|
39
src/plats/PlatFacebook.ts
Normal file
39
src/plats/PlatFacebook.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { IPlat } from './IPlat'
|
||||
|
||||
import { ZError } from 'common/ZError'
|
||||
import { FACEBOOK_APP_ID, fetchUserInfo, verifyFbUserAccessToken } from 'providers/facebook.provider'
|
||||
|
||||
export class PlatFacebook implements IPlat {
|
||||
async verifyToken(req: any): Promise<any> {
|
||||
let { code, token } = req.params
|
||||
code = code || token
|
||||
const result = await verifyFbUserAccessToken(code)
|
||||
if (!!result.error) {
|
||||
throw new ZError(10, `${result.error?.message} (${result.error?.code})`)
|
||||
}
|
||||
const { data } = result
|
||||
if (!data) {
|
||||
throw new ZError(11, 'no data from facebook')
|
||||
}
|
||||
if (data.app_id !== FACEBOOK_APP_ID) {
|
||||
throw new ZError(12, 'app id mismatch')
|
||||
}
|
||||
if (!data.is_valid) {
|
||||
throw new ZError(13, 'access_token not valid')
|
||||
}
|
||||
const infoRes = await fetchUserInfo(code)
|
||||
if (!!infoRes.error) {
|
||||
throw new ZError(13, `${infoRes.error?.message} (${infoRes.error.code})`)
|
||||
}
|
||||
const openId = infoRes.id || data.user_id
|
||||
|
||||
let user: any = {}
|
||||
user.accessToken = code
|
||||
user.accessTokenExpire = result.data['expires_at']
|
||||
user.scope = data['scopes']
|
||||
if (infoRes['name']) user.nickname = infoRes['name']
|
||||
if (infoRes['email']) user.email = infoRes['email']
|
||||
|
||||
return { openId, data: user }
|
||||
}
|
||||
}
|
46
src/plats/PlatGoogle.ts
Normal file
46
src/plats/PlatGoogle.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { OAuth2Client } from 'google-auth-library'
|
||||
import { IPlat } from './IPlat'
|
||||
import { ZError } from 'common/ZError'
|
||||
|
||||
const GOOGLE_OAUTH_ISS = 'https://accounts.google.com'
|
||||
const GOOGLE_OAUTH_ISS1 = 'accounts.google.com'
|
||||
const IOS_TEST = '53206975661-0d6q9pqljn84n9l63gm0to1ulap9cbk4.apps.googleusercontent.com'
|
||||
const CLIENT_ID = process.env.GOOGLE_OAUTH_CLIENT
|
||||
const CLIENT_ID2 = process.env.GOOGLE_OAUTH_CLIENT2
|
||||
const CLIENT_ID_IOS = process.env.GOOGLE_OAUTH_CLIENT_IOS
|
||||
|
||||
export class PlatGoogle implements IPlat {
|
||||
async verifyToken(req: any): Promise<any> {
|
||||
let { code, token } = req.params
|
||||
code = code || token
|
||||
const client = new OAuth2Client(CLIENT_ID)
|
||||
const ticket = await client.verifyIdToken({
|
||||
idToken: code,
|
||||
audience: [CLIENT_ID, CLIENT_ID2, CLIENT_ID_IOS, IOS_TEST], // Specify the CLIENT_ID of the app that accesses the backend
|
||||
// Or, if multiple clients access the backend:
|
||||
//[CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]
|
||||
})
|
||||
const payload = ticket.getPayload()
|
||||
if (!(payload.iss === GOOGLE_OAUTH_ISS || payload.iss === GOOGLE_OAUTH_ISS1)) {
|
||||
throw new ZError(10, 'id token error')
|
||||
}
|
||||
if (
|
||||
payload.aud !== CLIENT_ID &&
|
||||
payload.aud !== CLIENT_ID2 &&
|
||||
payload.aud !== CLIENT_ID_IOS &&
|
||||
payload.aud !== IOS_TEST
|
||||
) {
|
||||
throw new ZError(11, 'client id mismatch')
|
||||
}
|
||||
let data: any = {}
|
||||
if (payload.email) data.email = payload.email
|
||||
if (process.env.NODE_ENV !== 'development') {
|
||||
if (payload.email_verified !== undefined) data.emailVerified = payload.email_verified
|
||||
}
|
||||
if (payload.locale) data.locale = payload.locale
|
||||
if (payload.name) data.nickname = payload.name
|
||||
if (payload.picture) data.avatar = payload.picture
|
||||
const openId = payload.sub
|
||||
return { openId, data }
|
||||
}
|
||||
}
|
28
src/plats/PlatTikTok.ts
Normal file
28
src/plats/PlatTikTok.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { fetchAccessToken } from 'service/tiktok.svr'
|
||||
import { IPlat } from './IPlat'
|
||||
|
||||
import { ZError } from 'common/ZError'
|
||||
|
||||
// 在tiktok的过期时间中, 减少一个小时
|
||||
const EXPIRE_REDUCE_SECOND = 3600
|
||||
|
||||
export class PlatTikTok implements IPlat {
|
||||
async verifyToken(req: any): Promise<any> {
|
||||
let { code, token } = req.params
|
||||
code = code || token
|
||||
let result = await fetchAccessToken(code)
|
||||
if (!(result.message === 'success' && result.data?.error_code === 0)) {
|
||||
throw new ZError(10, `${result.message}: ${result.data?.description} (${result.data?.error_code})`)
|
||||
}
|
||||
const openId = result.data['open_id']
|
||||
let user: any = {}
|
||||
let now = Date.now() / 1000
|
||||
user.accessToken = result.data['access_token']
|
||||
user.refreshToken = result.data['refresh_token']
|
||||
user.accessTokenExpire = now + result.data['expires_in'] - EXPIRE_REDUCE_SECOND
|
||||
user.refreshTokenExpire = now + result.data['refresh_expires_in'] - EXPIRE_REDUCE_SECOND
|
||||
user.scope = result.data['scope']
|
||||
|
||||
return { openId, data: user }
|
||||
}
|
||||
}
|
@ -1,19 +1,19 @@
|
||||
import {NetClient} from "net/NetClient";
|
||||
import { NetClient } from 'net/NetClient'
|
||||
|
||||
const FACEBOOK_API_HOST = 'https://graph.facebook.com'
|
||||
export const FACEBOOK_APP_ID = '1204701000119770';
|
||||
const FACEBOOK_APP_SECRET = '5a1deba64b30c7326f497fc52691207f';
|
||||
export const FACEBOOK_APP_ID = '1204701000119770'
|
||||
const FACEBOOK_APP_SECRET = '5a1deba64b30c7326f497fc52691207f'
|
||||
|
||||
export async function getAppAccessToken() {
|
||||
const url = `${FACEBOOK_API_HOST}/oauth/access_token?client_id=${FACEBOOK_APP_ID}&clent_secret=${FACEBOOK_APP_SECRET}&grant_type=client_credentials`;
|
||||
return new NetClient().httpGet(url);
|
||||
}
|
||||
export async function verifyFbUserAccessToken(accessToken: string){
|
||||
const url = `${FACEBOOK_API_HOST}/debug_token?input_token=${accessToken}&access_token=GG|${FACEBOOK_APP_ID}|${FACEBOOK_APP_SECRET}`;
|
||||
return new NetClient().httpGet(url);
|
||||
const url = `${FACEBOOK_API_HOST}/oauth/access_token?client_id=${FACEBOOK_APP_ID}&clent_secret=${FACEBOOK_APP_SECRET}&grant_type=client_credentials`
|
||||
return new NetClient().httpGet(url)
|
||||
}
|
||||
export async function verifyFbUserAccessToken(accessToken: string) {
|
||||
const url = `${FACEBOOK_API_HOST}/debug_token?input_token=${accessToken}&access_token=GG|${FACEBOOK_APP_ID}|${FACEBOOK_APP_SECRET}`
|
||||
return new NetClient().httpGet(url)
|
||||
}
|
||||
|
||||
export async function fetchUserInfo(accessToken: string) {
|
||||
const url = `${FACEBOOK_API_HOST}/me?fields=["email","id", "name"]&access_token=${accessToken}`;
|
||||
return new NetClient().httpGet(url);
|
||||
const url = `${FACEBOOK_API_HOST}/me?fields=["email","id", "name"]&access_token=${accessToken}`
|
||||
return new NetClient().httpGet(url)
|
||||
}
|
||||
|
@ -26,3 +26,17 @@ export async function reportPayResult(data: DocumentType<PayRecordClass>) {
|
||||
}
|
||||
return axios(reqConfig)
|
||||
}
|
||||
/**
|
||||
* TODO::向游戏服务查询guest账号和平台账号能否绑定
|
||||
*/
|
||||
export async function checkReleation() {
|
||||
let url = `${process.env.GAME_CHECK_RELATION_URL}`
|
||||
let reqConfig: any = {
|
||||
method: 'get',
|
||||
url,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
return axios(reqConfig)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user