使用 feathersjs oauth 调用承诺未处理的拒绝
Unhandled rejection at promise with feathersjs oauth call
我正在尝试创建一个带有 feathers-vuex 的前端 Vue(x) 应用程序和一个仅使用 oauth 进行身份验证的后端 feathers API。
如果我直接在 localhost:3030/oauth/google
上点击后端,那么正确的流程和重定向发生在 google 并且我最终回到 localhost:8080/#/access_token=ey....
并且有一个有效的 jwt 所以 oauth配置在后端和 google 处的 oauth 配置似乎很好。配置为..
"oauth": {
"redirect": "http://localhost:8080/",
"google": {
"key": "GOOGLE_CLIENT_KEY",
"secret": "GOOGLE_CLIENT_SECRET",
"scope": [
"email",
"profile",
"openid"
]
}
}
但是,当我在 localhost:8080
上从我的前端应用 运行 单击调用 login
方法的内容时..
login() {
this.$store.dispatch('auth/authenticate', {strategy: 'google'})
}
.. 我在后端收到拒绝的承诺。使用 DEBUG=feathers*,@feathersjs*
我看到以下输出:
@feathersjs/transport-commons Got 'create' call for service 'authentication' +0ms
@feathersjs/transport-commons Running method 'create' on service 'authentication' {
provider: 'socketio',
headers: {
host: 'localhost:3030',
connection: 'Upgrade',
pragma: 'no-cache',
'cache-control': 'no-cache',
'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36',
upgrade: 'websocket',
origin: 'http://localhost:8080',
'sec-websocket-version': '13',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'en-GB,en-US;q=0.9,en;q=0.8',
cookie: 'connect.sid=s%3ACZWmOVc_1gtoJwDYsb0kvJ7vx06U-Rmd.jbQnNQL1GlFLWsJzyDP312ALpnI32mmYK7BIRka9Ro4',
'sec-websocket-key': 'umfZAU0K/7k+sKUg1A/wvA==',
'sec-websocket-extensions': 'permessage-deflate; client_max_window_bits'
}
} [ { strategy: 'google' }, {}, [Function] ] +0ms
@feathersjs/authentication/base Running authenticate for strategy google [ 'jwt', 'google' ] +16s
@feathersjs/authentication-oauth/strategy getProfile of oAuth profile from grant-profile with { strategy: 'google' } +0ms
@feathersjs/transport-commons Error in method 'create' on service 'authentication' Error: 401 Unauthorized
at module.exports (/home/darren/projects/stbgfc/develop/admin-api/node_modules/request-compose/utils/error.js:3:15)
at /home/darren/projects/stbgfc/develop/admin-api/node_modules/request-compose/response/status.js:11:11
at processTicksAndRejections (internal/process/task_queues.js:93:5) {
message: '401 Unauthorized',
res: IncomingMessage {
_readableState: ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: null,
pipesCount: 0,
flowing: true,
ended: true,
endEmitted: true,
reading: false,
sync: false,
needReadable: false,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
paused: false,
emitClose: true,
autoDestroy: false,
destroyed: false,
defaultEncoding: 'utf8',
awaitDrain: 0,
readingMore: false,
decoder: null,
encoding: null
},
readable: false,
_events: [Object: null prototype] {
end: [Array],
data: [Function],
error: [Function]
},
_eventsCount: 3,
_maxListeners: undefined,
socket: TLSSocket {
_tlsOptions: [Object],
_secureEstablished: true,
_securePending: false,
_newSessionPending: false,
_controlReleased: true,
_SNICallback: null,
servername: 'openidconnect.googleapis.com',
alpnProtocol: false,
authorized: true,
authorizationError: null,
encrypted: true,
_events: [Object: null prototype],
_eventsCount: 11,
connecting: false,
_hadError: false,
_parent: null,
_host: 'openidconnect.googleapis.com',
_readableState: [ReadableState],
readable: false,
_maxListeners: undefined,
_writableState: [WritableState],
writable: false,
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: undefined,
_server: null,
ssl: null,
_requestCert: true,
_rejectUnauthorized: true,
timeout: 5000,
parser: null,
_httpMessage: [ClientRequest],
write: [Function: writeAfterFIN],
[Symbol(res)]: [TLSWrap],
[Symbol(asyncId)]: 125,
[Symbol(kHandle)]: null,
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: Timeout {
_idleTimeout: -1,
_idlePrev: null,
_idleNext: null,
_idleStart: 19758,
_onTimeout: null,
_timerArgs: undefined,
_repeat: null,
_destroyed: true,
[Symbol(refed)]: null,
[Symbol(asyncId)]: 135,
[Symbol(triggerId)]: 133
},
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kBytesRead)]: 689,
[Symbol(kBytesWritten)]: 150,
[Symbol(connect-options)]: [Object]
},
connection: TLSSocket {
_tlsOptions: [Object],
_secureEstablished: true,
_securePending: false,
_newSessionPending: false,
_controlReleased: true,
_SNICallback: null,
servername: 'openidconnect.googleapis.com',
alpnProtocol: false,
authorized: true,
authorizationError: null,
encrypted: true,
_events: [Object: null prototype],
_eventsCount: 11,
connecting: false,
_hadError: false,
_parent: null,
_host: 'openidconnect.googleapis.com',
_readableState: [ReadableState],
readable: false,
_maxListeners: undefined,
_writableState: [WritableState],
writable: false,
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: undefined,
_server: null,
ssl: null,
_requestCert: true,
_rejectUnauthorized: true,
timeout: 5000,
parser: null,
_httpMessage: [ClientRequest],
write: [Function: writeAfterFIN],
[Symbol(res)]: [TLSWrap],
[Symbol(asyncId)]: 125,
[Symbol(kHandle)]: null,
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: Timeout {
_idleTimeout: -1,
_idlePrev: null,
_idleNext: null,
_idleStart: 19758,
_onTimeout: null,
_timerArgs: undefined,
_repeat: null,
_destroyed: true,
[Symbol(refed)]: null,
[Symbol(asyncId)]: 135,
[Symbol(triggerId)]: 133
},
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kBytesRead)]: 689,
[Symbol(kBytesWritten)]: 150,
[Symbol(connect-options)]: [Object]
},
httpVersionMajor: 1,
httpVersionMinor: 1,
httpVersion: '1.1',
complete: true,
headers: {
pragma: 'no-cache',
date: 'Thu, 02 Jan 2020 22:13:43 GMT',
'cache-control': 'no-cache, no-store, max-age=0, must-revalidate',
expires: 'Mon, 01 Jan 1990 00:00:00 GMT',
'content-type': 'application/json; charset=utf-8',
vary: 'X-Origin, Referer, Origin,Accept-Encoding',
server: 'ESF',
'x-xss-protection': '0',
'x-frame-options': 'SAMEORIGIN',
'x-content-type-options': 'nosniff',
'alt-svc': 'quic=":443"; ma=2592000; v="46,43",h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000',
'accept-ranges': 'none',
connection: 'close'
},
rawHeaders: [
'Pragma',
'no-cache',
'Date',
'Thu, 02 Jan 2020 22:13:43 GMT',
'Cache-Control',
'no-cache, no-store, max-age=0, must-revalidate',
'Expires',
'Mon, 01 Jan 1990 00:00:00 GMT',
'Content-Type',
'application/json; charset=utf-8',
'Vary',
'X-Origin',
'Vary',
'Referer',
'Server',
'ESF',
'X-XSS-Protection',
'0',
'X-Frame-Options',
'SAMEORIGIN',
'X-Content-Type-Options',
'nosniff',
'Alt-Svc',
'quic=":443"; ma=2592000; v="46,43",h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000',
'Accept-Ranges',
'none',
'Vary',
'Origin,Accept-Encoding',
'Connection',
'close'
],
trailers: {},
rawTrailers: [],
aborted: false,
upgrade: false,
url: '',
method: null,
statusCode: 401,
statusMessage: 'Unauthorized',
client: TLSSocket {
_tlsOptions: [Object],
_secureEstablished: true,
_securePending: false,
_newSessionPending: false,
_controlReleased: true,
_SNICallback: null,
servername: 'openidconnect.googleapis.com',
alpnProtocol: false,
authorized: true,
authorizationError: null,
encrypted: true,
_events: [Object: null prototype],
_eventsCount: 11,
connecting: false,
_hadError: false,
_parent: null,
_host: 'openidconnect.googleapis.com',
_readableState: [ReadableState],
readable: false,
_maxListeners: undefined,
_writableState: [WritableState],
writable: false,
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: undefined,
_server: null,
ssl: null,
_requestCert: true,
_rejectUnauthorized: true,
timeout: 5000,
parser: null,
_httpMessage: [ClientRequest],
write: [Function: writeAfterFIN],
[Symbol(res)]: [TLSWrap],
[Symbol(asyncId)]: 125,
[Symbol(kHandle)]: null,
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: Timeout {
_idleTimeout: -1,
_idlePrev: null,
_idleNext: null,
_idleStart: 19758,
_onTimeout: null,
_timerArgs: undefined,
_repeat: null,
_destroyed: true,
[Symbol(refed)]: null,
[Symbol(asyncId)]: 135,
[Symbol(triggerId)]: 133
},
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kBytesRead)]: 689,
[Symbol(kBytesWritten)]: 150,
[Symbol(connect-options)]: [Object]
},
_consuming: true,
_dumped: false,
req: ClientRequest {
_events: [Object: null prototype],
_eventsCount: 5,
_maxListeners: undefined,
outputData: [],
outputSize: 0,
writable: true,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: false,
useChunkedEncodingByDefault: false,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: 0,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
socket: [TLSSocket],
connection: [TLSSocket],
_header: 'GET /v1/userinfo HTTP/1.1\r\n' +
'user-agent: grant-profile 0.0.8\r\n' +
'authorization: Bearer undefined\r\n' +
'Host: openidconnect.googleapis.com\r\n' +
'Connection: close\r\n' +
'\r\n',
_onPendingData: [Function: noopPendingOutput],
agent: [Agent],
socketPath: undefined,
timeout: 5000,
method: 'GET',
path: '/v1/userinfo',
_ended: true,
res: [Circular],
aborted: false,
timeoutCb: [Function: emitRequestTimeout],
upgradeOrConnect: false,
parser: null,
maxHeadersCount: null,
[Symbol(kNeedDrain)]: false,
[Symbol(isCorked)]: false,
[Symbol(kOutHeaders)]: [Object: null prototype]
}
},
body: {
error: 'invalid_request',
error_description: 'Invalid Credentials'
},
raw: '{\n' +
' "error": "invalid_request",\n' +
' "error_description": "Invalid Credentials"\n' +
'}',
hook: {
type: 'before',
arguments: [ [Object], [Object] ],
service: {
app: [EventEmitter],
strategies: [Object],
configKey: 'authentication',
create: [Function: newMethod],
remove: [Function: newMethod],
methods: [Object],
hooks: [Function: hooks],
_events: [Object: null prototype],
_eventsCount: 2,
_maxListeners: undefined,
setMaxListeners: [Function: setMaxListeners],
getMaxListeners: [Function: getMaxListeners],
emit: [Function: emit],
addListener: [Function: addListener],
on: [Function: addListener],
prependListener: [Function: prependListener],
once: [Function: once],
prependOnceListener: [Function: prependOnceListener],
removeListener: [Function: removeListener],
off: [Function: removeListener],
removeAllListeners: [Function: removeAllListeners],
listeners: [Function: listeners],
rawListeners: [Function: rawListeners],
listenerCount: [Function: listenerCount],
eventNames: [Function: eventNames],
publish: [Function: publish],
registerPublisher: [Function: registerPublisher],
_super: undefined,
[Symbol(@feathersjs/transport-commons/publishers)]: [Object]
},
app: [Function: app] EventEmitter {
_events: [Object: null prototype],
_eventsCount: 6,
_maxListeners: undefined,
setMaxListeners: [Function: setMaxListeners],
getMaxListeners: [Function: getMaxListeners],
emit: [Function: emit],
addListener: [Function: addListener],
on: [Function: addListener],
prependListener: [Function: prependListener],
once: [Function: once],
prependOnceListener: [Function: prependOnceListener],
removeListener: [Function: removeListener],
off: [Function: removeListener],
removeAllListeners: [Function: removeAllListeners],
listeners: [Function: listeners],
rawListeners: [Function: rawListeners],
listenerCount: [Function: listenerCount],
eventNames: [Function: eventNames],
init: [Function: init],
defaultConfiguration: [Function: defaultConfiguration],
lazyrouter: [Function: lazyrouter],
handle: [Function: handle],
use: [Function: newMethod],
route: [Function: route],
engine: [Function: engine],
param: [Function: param],
set: [Function: set],
path: [Function: path],
enabled: [Function: enabled],
disabled: [Function: disabled],
enable: [Function: enable],
disable: [Function: disable],
acl: [Function],
bind: [Function],
checkout: [Function],
connect: [Function],
copy: [Function],
delete: [Function],
get: [Function],
head: [Function],
link: [Function],
lock: [Function],
'm-search': [Function],
merge: [Function],
mkactivity: [Function],
mkcalendar: [Function],
mkcol: [Function],
move: [Function],
notify: [Function],
options: [Function],
patch: [Function],
post: [Function],
propfind: [Function],
proppatch: [Function],
purge: [Function],
put: [Function],
rebind: [Function],
report: [Function],
search: [Function],
source: [Function],
subscribe: [Function],
trace: [Function],
unbind: [Function],
unlink: [Function],
unlock: [Function],
unsubscribe: [Function],
all: [Function: all],
del: [Function],
render: [Function: render],
listen: [Function: newMethod],
request: [IncomingMessage],
response: [ServerResponse],
cache: {},
engines: {},
settings: [Object],
locals: [Object: null prototype],
mountpath: '/',
configure: [Function: configure],
service: [Function: service],
setup: [Function: newMethod],
version: '4.4.3',
methods: [Array],
mixins: [Array],
services: [Object],
providers: [Array],
_setup: false,
hookTypes: [Array],
hooks: [Function: hooks],
eventMappings: [Object],
_super: undefined,
_router: [Function],
rest: [Object],
channel: [Function: channel],
publish: [Function: publish],
registerPublisher: [Function: registerPublisher],
lookup: [Function: lookup],
defaultAuthentication: [Function],
logger: [DerivedLogger],
io: [Server],
_isSetup: true,
[Symbol(@feathersjs/transport-commons/channels)]: [Object],
[Symbol(@feathersjs/transport-commons/publishers)]: [Object],
[Symbol(@feathersjs/transport-commons/router)]: [Object]
},
method: 'create',
path: 'authentication',
data: { strategy: 'google' },
params: {
query: {},
route: {},
connection: [Object],
provider: 'socketio',
headers: [Object]
}
}
} +2s
error: Unhandled Rejection at: Promise
然后几秒钟后,由于调用未返回导致前端超时错误:
Timeout {type: "FeathersError", name: "Timeout", message: "Timeout of 5000ms exceeded calling create on authentication", code: 408, className: "timeout", …}
type: "FeathersError"
name: "Timeout"
message: "Timeout of 5000ms exceeded calling create on authentication"
code: 408
className: "timeout"
data: {timeout: 5000, method: "create", path: "authentication"}
errors: {}
hook: {type: "before", arguments: Array(2), service: {…}, app: {…}, method: "create", …}
stack: "Timeout: Timeout of 5000ms exceeded calling create on authentication↵ at new Timeout (webpack-internal:///./node_modules/@feathersjs/errors/lib/index.js:135:17)↵ at eval (webpack-internal:///./node_modules/@feathersjs/transport-commons/lib/client.js:60:55)"
__proto__: FeathersError
似乎在抱怨 authentication
服务上对 create
的调用本身需要身份验证(我阅读了后端调试输出顶部附近可以看到的 401 响应消息).
我在前端的 feathers-client.js
几乎是从文档中逐字记录的..
import feathers from '@feathersjs/feathers'
import socketio from '@feathersjs/socketio-client'
import auth from '@feathersjs/authentication-client'
import io from 'socket.io-client'
import { iff, discard } from 'feathers-hooks-common'
import feathersVuex from 'feathers-vuex'
const socket = io('http://localhost:3030', { transports: ['websocket'] })
const feathersClient = feathers()
.configure(socketio(socket))
.configure(auth({
storageKey: 'auth',
storage: window.localStorage
}))
.hooks({
before: {
all: [
iff(
context => ['create', 'update', 'patch'].includes(context.method),
discard('__id', '__isTemp')
)
]
}
})
export default feathersClient
// Setting up feathers-vuex
const { makeServicePlugin, makeAuthPlugin, BaseModel, models, FeathersVuex } = feathersVuex(
feathersClient,
{
serverAlias: 'api', // optional for working with multiple APIs (this is the default value)
idField: '_id', // Must match the id field in your database table/collection
whitelist: ['$regex', '$options']
}
)
export { makeAuthPlugin, makeServicePlugin, BaseModel, models, FeathersVuex }
.. 并且考虑到后端被调用表明 vuex auth 插件也被正确配置和使用,但这可能是推测。
任何人都可以就如何进行提出建议吗?不幸的是,我在任何地方都没有遇到这种工作的例子(我看到的所有使用羽毛身份验证的例子都只使用本地策略)。
对于碰巧遇到类似问题的任何人:我似乎在项目中安装了旧的且不兼容的 feathers-vuex
版本。更新到 3.3.0 使其工作。
我正在尝试创建一个带有 feathers-vuex 的前端 Vue(x) 应用程序和一个仅使用 oauth 进行身份验证的后端 feathers API。
如果我直接在 localhost:3030/oauth/google
上点击后端,那么正确的流程和重定向发生在 google 并且我最终回到 localhost:8080/#/access_token=ey....
并且有一个有效的 jwt 所以 oauth配置在后端和 google 处的 oauth 配置似乎很好。配置为..
"oauth": {
"redirect": "http://localhost:8080/",
"google": {
"key": "GOOGLE_CLIENT_KEY",
"secret": "GOOGLE_CLIENT_SECRET",
"scope": [
"email",
"profile",
"openid"
]
}
}
但是,当我在 localhost:8080
上从我的前端应用 运行 单击调用 login
方法的内容时..
login() {
this.$store.dispatch('auth/authenticate', {strategy: 'google'})
}
.. 我在后端收到拒绝的承诺。使用 DEBUG=feathers*,@feathersjs*
我看到以下输出:
@feathersjs/transport-commons Got 'create' call for service 'authentication' +0ms
@feathersjs/transport-commons Running method 'create' on service 'authentication' {
provider: 'socketio',
headers: {
host: 'localhost:3030',
connection: 'Upgrade',
pragma: 'no-cache',
'cache-control': 'no-cache',
'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36',
upgrade: 'websocket',
origin: 'http://localhost:8080',
'sec-websocket-version': '13',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'en-GB,en-US;q=0.9,en;q=0.8',
cookie: 'connect.sid=s%3ACZWmOVc_1gtoJwDYsb0kvJ7vx06U-Rmd.jbQnNQL1GlFLWsJzyDP312ALpnI32mmYK7BIRka9Ro4',
'sec-websocket-key': 'umfZAU0K/7k+sKUg1A/wvA==',
'sec-websocket-extensions': 'permessage-deflate; client_max_window_bits'
}
} [ { strategy: 'google' }, {}, [Function] ] +0ms
@feathersjs/authentication/base Running authenticate for strategy google [ 'jwt', 'google' ] +16s
@feathersjs/authentication-oauth/strategy getProfile of oAuth profile from grant-profile with { strategy: 'google' } +0ms
@feathersjs/transport-commons Error in method 'create' on service 'authentication' Error: 401 Unauthorized
at module.exports (/home/darren/projects/stbgfc/develop/admin-api/node_modules/request-compose/utils/error.js:3:15)
at /home/darren/projects/stbgfc/develop/admin-api/node_modules/request-compose/response/status.js:11:11
at processTicksAndRejections (internal/process/task_queues.js:93:5) {
message: '401 Unauthorized',
res: IncomingMessage {
_readableState: ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: null,
pipesCount: 0,
flowing: true,
ended: true,
endEmitted: true,
reading: false,
sync: false,
needReadable: false,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
paused: false,
emitClose: true,
autoDestroy: false,
destroyed: false,
defaultEncoding: 'utf8',
awaitDrain: 0,
readingMore: false,
decoder: null,
encoding: null
},
readable: false,
_events: [Object: null prototype] {
end: [Array],
data: [Function],
error: [Function]
},
_eventsCount: 3,
_maxListeners: undefined,
socket: TLSSocket {
_tlsOptions: [Object],
_secureEstablished: true,
_securePending: false,
_newSessionPending: false,
_controlReleased: true,
_SNICallback: null,
servername: 'openidconnect.googleapis.com',
alpnProtocol: false,
authorized: true,
authorizationError: null,
encrypted: true,
_events: [Object: null prototype],
_eventsCount: 11,
connecting: false,
_hadError: false,
_parent: null,
_host: 'openidconnect.googleapis.com',
_readableState: [ReadableState],
readable: false,
_maxListeners: undefined,
_writableState: [WritableState],
writable: false,
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: undefined,
_server: null,
ssl: null,
_requestCert: true,
_rejectUnauthorized: true,
timeout: 5000,
parser: null,
_httpMessage: [ClientRequest],
write: [Function: writeAfterFIN],
[Symbol(res)]: [TLSWrap],
[Symbol(asyncId)]: 125,
[Symbol(kHandle)]: null,
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: Timeout {
_idleTimeout: -1,
_idlePrev: null,
_idleNext: null,
_idleStart: 19758,
_onTimeout: null,
_timerArgs: undefined,
_repeat: null,
_destroyed: true,
[Symbol(refed)]: null,
[Symbol(asyncId)]: 135,
[Symbol(triggerId)]: 133
},
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kBytesRead)]: 689,
[Symbol(kBytesWritten)]: 150,
[Symbol(connect-options)]: [Object]
},
connection: TLSSocket {
_tlsOptions: [Object],
_secureEstablished: true,
_securePending: false,
_newSessionPending: false,
_controlReleased: true,
_SNICallback: null,
servername: 'openidconnect.googleapis.com',
alpnProtocol: false,
authorized: true,
authorizationError: null,
encrypted: true,
_events: [Object: null prototype],
_eventsCount: 11,
connecting: false,
_hadError: false,
_parent: null,
_host: 'openidconnect.googleapis.com',
_readableState: [ReadableState],
readable: false,
_maxListeners: undefined,
_writableState: [WritableState],
writable: false,
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: undefined,
_server: null,
ssl: null,
_requestCert: true,
_rejectUnauthorized: true,
timeout: 5000,
parser: null,
_httpMessage: [ClientRequest],
write: [Function: writeAfterFIN],
[Symbol(res)]: [TLSWrap],
[Symbol(asyncId)]: 125,
[Symbol(kHandle)]: null,
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: Timeout {
_idleTimeout: -1,
_idlePrev: null,
_idleNext: null,
_idleStart: 19758,
_onTimeout: null,
_timerArgs: undefined,
_repeat: null,
_destroyed: true,
[Symbol(refed)]: null,
[Symbol(asyncId)]: 135,
[Symbol(triggerId)]: 133
},
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kBytesRead)]: 689,
[Symbol(kBytesWritten)]: 150,
[Symbol(connect-options)]: [Object]
},
httpVersionMajor: 1,
httpVersionMinor: 1,
httpVersion: '1.1',
complete: true,
headers: {
pragma: 'no-cache',
date: 'Thu, 02 Jan 2020 22:13:43 GMT',
'cache-control': 'no-cache, no-store, max-age=0, must-revalidate',
expires: 'Mon, 01 Jan 1990 00:00:00 GMT',
'content-type': 'application/json; charset=utf-8',
vary: 'X-Origin, Referer, Origin,Accept-Encoding',
server: 'ESF',
'x-xss-protection': '0',
'x-frame-options': 'SAMEORIGIN',
'x-content-type-options': 'nosniff',
'alt-svc': 'quic=":443"; ma=2592000; v="46,43",h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000',
'accept-ranges': 'none',
connection: 'close'
},
rawHeaders: [
'Pragma',
'no-cache',
'Date',
'Thu, 02 Jan 2020 22:13:43 GMT',
'Cache-Control',
'no-cache, no-store, max-age=0, must-revalidate',
'Expires',
'Mon, 01 Jan 1990 00:00:00 GMT',
'Content-Type',
'application/json; charset=utf-8',
'Vary',
'X-Origin',
'Vary',
'Referer',
'Server',
'ESF',
'X-XSS-Protection',
'0',
'X-Frame-Options',
'SAMEORIGIN',
'X-Content-Type-Options',
'nosniff',
'Alt-Svc',
'quic=":443"; ma=2592000; v="46,43",h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000',
'Accept-Ranges',
'none',
'Vary',
'Origin,Accept-Encoding',
'Connection',
'close'
],
trailers: {},
rawTrailers: [],
aborted: false,
upgrade: false,
url: '',
method: null,
statusCode: 401,
statusMessage: 'Unauthorized',
client: TLSSocket {
_tlsOptions: [Object],
_secureEstablished: true,
_securePending: false,
_newSessionPending: false,
_controlReleased: true,
_SNICallback: null,
servername: 'openidconnect.googleapis.com',
alpnProtocol: false,
authorized: true,
authorizationError: null,
encrypted: true,
_events: [Object: null prototype],
_eventsCount: 11,
connecting: false,
_hadError: false,
_parent: null,
_host: 'openidconnect.googleapis.com',
_readableState: [ReadableState],
readable: false,
_maxListeners: undefined,
_writableState: [WritableState],
writable: false,
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: undefined,
_server: null,
ssl: null,
_requestCert: true,
_rejectUnauthorized: true,
timeout: 5000,
parser: null,
_httpMessage: [ClientRequest],
write: [Function: writeAfterFIN],
[Symbol(res)]: [TLSWrap],
[Symbol(asyncId)]: 125,
[Symbol(kHandle)]: null,
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: Timeout {
_idleTimeout: -1,
_idlePrev: null,
_idleNext: null,
_idleStart: 19758,
_onTimeout: null,
_timerArgs: undefined,
_repeat: null,
_destroyed: true,
[Symbol(refed)]: null,
[Symbol(asyncId)]: 135,
[Symbol(triggerId)]: 133
},
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kBytesRead)]: 689,
[Symbol(kBytesWritten)]: 150,
[Symbol(connect-options)]: [Object]
},
_consuming: true,
_dumped: false,
req: ClientRequest {
_events: [Object: null prototype],
_eventsCount: 5,
_maxListeners: undefined,
outputData: [],
outputSize: 0,
writable: true,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: false,
useChunkedEncodingByDefault: false,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: 0,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
socket: [TLSSocket],
connection: [TLSSocket],
_header: 'GET /v1/userinfo HTTP/1.1\r\n' +
'user-agent: grant-profile 0.0.8\r\n' +
'authorization: Bearer undefined\r\n' +
'Host: openidconnect.googleapis.com\r\n' +
'Connection: close\r\n' +
'\r\n',
_onPendingData: [Function: noopPendingOutput],
agent: [Agent],
socketPath: undefined,
timeout: 5000,
method: 'GET',
path: '/v1/userinfo',
_ended: true,
res: [Circular],
aborted: false,
timeoutCb: [Function: emitRequestTimeout],
upgradeOrConnect: false,
parser: null,
maxHeadersCount: null,
[Symbol(kNeedDrain)]: false,
[Symbol(isCorked)]: false,
[Symbol(kOutHeaders)]: [Object: null prototype]
}
},
body: {
error: 'invalid_request',
error_description: 'Invalid Credentials'
},
raw: '{\n' +
' "error": "invalid_request",\n' +
' "error_description": "Invalid Credentials"\n' +
'}',
hook: {
type: 'before',
arguments: [ [Object], [Object] ],
service: {
app: [EventEmitter],
strategies: [Object],
configKey: 'authentication',
create: [Function: newMethod],
remove: [Function: newMethod],
methods: [Object],
hooks: [Function: hooks],
_events: [Object: null prototype],
_eventsCount: 2,
_maxListeners: undefined,
setMaxListeners: [Function: setMaxListeners],
getMaxListeners: [Function: getMaxListeners],
emit: [Function: emit],
addListener: [Function: addListener],
on: [Function: addListener],
prependListener: [Function: prependListener],
once: [Function: once],
prependOnceListener: [Function: prependOnceListener],
removeListener: [Function: removeListener],
off: [Function: removeListener],
removeAllListeners: [Function: removeAllListeners],
listeners: [Function: listeners],
rawListeners: [Function: rawListeners],
listenerCount: [Function: listenerCount],
eventNames: [Function: eventNames],
publish: [Function: publish],
registerPublisher: [Function: registerPublisher],
_super: undefined,
[Symbol(@feathersjs/transport-commons/publishers)]: [Object]
},
app: [Function: app] EventEmitter {
_events: [Object: null prototype],
_eventsCount: 6,
_maxListeners: undefined,
setMaxListeners: [Function: setMaxListeners],
getMaxListeners: [Function: getMaxListeners],
emit: [Function: emit],
addListener: [Function: addListener],
on: [Function: addListener],
prependListener: [Function: prependListener],
once: [Function: once],
prependOnceListener: [Function: prependOnceListener],
removeListener: [Function: removeListener],
off: [Function: removeListener],
removeAllListeners: [Function: removeAllListeners],
listeners: [Function: listeners],
rawListeners: [Function: rawListeners],
listenerCount: [Function: listenerCount],
eventNames: [Function: eventNames],
init: [Function: init],
defaultConfiguration: [Function: defaultConfiguration],
lazyrouter: [Function: lazyrouter],
handle: [Function: handle],
use: [Function: newMethod],
route: [Function: route],
engine: [Function: engine],
param: [Function: param],
set: [Function: set],
path: [Function: path],
enabled: [Function: enabled],
disabled: [Function: disabled],
enable: [Function: enable],
disable: [Function: disable],
acl: [Function],
bind: [Function],
checkout: [Function],
connect: [Function],
copy: [Function],
delete: [Function],
get: [Function],
head: [Function],
link: [Function],
lock: [Function],
'm-search': [Function],
merge: [Function],
mkactivity: [Function],
mkcalendar: [Function],
mkcol: [Function],
move: [Function],
notify: [Function],
options: [Function],
patch: [Function],
post: [Function],
propfind: [Function],
proppatch: [Function],
purge: [Function],
put: [Function],
rebind: [Function],
report: [Function],
search: [Function],
source: [Function],
subscribe: [Function],
trace: [Function],
unbind: [Function],
unlink: [Function],
unlock: [Function],
unsubscribe: [Function],
all: [Function: all],
del: [Function],
render: [Function: render],
listen: [Function: newMethod],
request: [IncomingMessage],
response: [ServerResponse],
cache: {},
engines: {},
settings: [Object],
locals: [Object: null prototype],
mountpath: '/',
configure: [Function: configure],
service: [Function: service],
setup: [Function: newMethod],
version: '4.4.3',
methods: [Array],
mixins: [Array],
services: [Object],
providers: [Array],
_setup: false,
hookTypes: [Array],
hooks: [Function: hooks],
eventMappings: [Object],
_super: undefined,
_router: [Function],
rest: [Object],
channel: [Function: channel],
publish: [Function: publish],
registerPublisher: [Function: registerPublisher],
lookup: [Function: lookup],
defaultAuthentication: [Function],
logger: [DerivedLogger],
io: [Server],
_isSetup: true,
[Symbol(@feathersjs/transport-commons/channels)]: [Object],
[Symbol(@feathersjs/transport-commons/publishers)]: [Object],
[Symbol(@feathersjs/transport-commons/router)]: [Object]
},
method: 'create',
path: 'authentication',
data: { strategy: 'google' },
params: {
query: {},
route: {},
connection: [Object],
provider: 'socketio',
headers: [Object]
}
}
} +2s
error: Unhandled Rejection at: Promise
然后几秒钟后,由于调用未返回导致前端超时错误:
Timeout {type: "FeathersError", name: "Timeout", message: "Timeout of 5000ms exceeded calling create on authentication", code: 408, className: "timeout", …}
type: "FeathersError"
name: "Timeout"
message: "Timeout of 5000ms exceeded calling create on authentication"
code: 408
className: "timeout"
data: {timeout: 5000, method: "create", path: "authentication"}
errors: {}
hook: {type: "before", arguments: Array(2), service: {…}, app: {…}, method: "create", …}
stack: "Timeout: Timeout of 5000ms exceeded calling create on authentication↵ at new Timeout (webpack-internal:///./node_modules/@feathersjs/errors/lib/index.js:135:17)↵ at eval (webpack-internal:///./node_modules/@feathersjs/transport-commons/lib/client.js:60:55)"
__proto__: FeathersError
似乎在抱怨 authentication
服务上对 create
的调用本身需要身份验证(我阅读了后端调试输出顶部附近可以看到的 401 响应消息).
我在前端的 feathers-client.js
几乎是从文档中逐字记录的..
import feathers from '@feathersjs/feathers'
import socketio from '@feathersjs/socketio-client'
import auth from '@feathersjs/authentication-client'
import io from 'socket.io-client'
import { iff, discard } from 'feathers-hooks-common'
import feathersVuex from 'feathers-vuex'
const socket = io('http://localhost:3030', { transports: ['websocket'] })
const feathersClient = feathers()
.configure(socketio(socket))
.configure(auth({
storageKey: 'auth',
storage: window.localStorage
}))
.hooks({
before: {
all: [
iff(
context => ['create', 'update', 'patch'].includes(context.method),
discard('__id', '__isTemp')
)
]
}
})
export default feathersClient
// Setting up feathers-vuex
const { makeServicePlugin, makeAuthPlugin, BaseModel, models, FeathersVuex } = feathersVuex(
feathersClient,
{
serverAlias: 'api', // optional for working with multiple APIs (this is the default value)
idField: '_id', // Must match the id field in your database table/collection
whitelist: ['$regex', '$options']
}
)
export { makeAuthPlugin, makeServicePlugin, BaseModel, models, FeathersVuex }
.. 并且考虑到后端被调用表明 vuex auth 插件也被正确配置和使用,但这可能是推测。
任何人都可以就如何进行提出建议吗?不幸的是,我在任何地方都没有遇到这种工作的例子(我看到的所有使用羽毛身份验证的例子都只使用本地策略)。
对于碰巧遇到类似问题的任何人:我似乎在项目中安装了旧的且不兼容的 feathers-vuex
版本。更新到 3.3.0 使其工作。