未使用 Nestjs 设置 HTTP Cookie
HTTP Cookie not being set with Nestjs
我有一个名为 login 的 GQL 突变,它 returns JWT 作为响应中的 cookie。
虽然 Set-Cookie
header 存在,但我的本地存储选项卡中没有显示任何内容。我的控制台也没有打印任何内容...
这是我的登录突变
@Mutation((returns) => AuthenticatedUser)
async login(
@Context() context: Auth.GqlContext,
@Args('payload', { type: () => UserLoginDto }) payload: UserLoginDto
): Promise<AuthenticatedUser> {
const authenticatedUser = await this.authService.login(payload)
context.res.cookie('jwt', authenticatedUser.jwt, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 1000 * 60 * 60 * 24 * 31, // one month
domain: process.env.NODE_ENV === 'production' ? '.herbievine.com' : undefined
})
return authenticatedUser
}
响应示例 JSON:
{
"data": {
"login": {
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjI0N2QyNmY3LTM3NzQtNGRiNS1hM2MzLTE2MTg3Mzk2ODdlMCIsImVtYWlsIjoidmluZWhlcmJpZUBnbWFpbC5jb20iLCJpYXQiOjE2MzYxMjkyMTksImV4cCI6MTYzODcyMTIxOX0.hHHAAgzs7wFjMP2C565fGGHAd0o-C9h-jA5qzm48OdE",
"user": {
"email": "email@gmail.com",
"name": "Some Name"
}
}
}
}
回复:
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: http://localhost:4000
Vary: Origin
Access-Control-Allow-Credentials: true
Set-Cookie: jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjI0N2QyNmY3LTM3NzQtNGRiNS1hM2MzLTE2MTg3Mzk2ODdlMCIsImVtYWlsIjoidmluZWhlcmJpZUBnbWFpbC5jb20iLCJpYXQiOjE2MzYxMjkyMTksImV4cCI6MTYzODcyMTIxOX0.hHHAAgzs7wFjMP2C565fGGHAd0o-C9h-jA5qzm48OdE; Max-Age=2678400; Path=/; Expires=Mon, 06 Dec 2021 16:06:11 GMT; HttpOnly; SameSite=Lax
Content-Type: application/json; charset=utf-8
Content-Length: 319
ETag: W/"13f-MuV4uipvL8ui1YJXuTSvJ1TM1H0"
Date: Fri, 05 Nov 2021 16:06:11 GMT
Connection: keep-alive
Keep-Alive: timeout=5
要求:
POST /graphql HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost:3000/graphql
content-type: application/json
Origin: http://localhost:3000
Content-Length: 195
Connection: keep-alive
目前,我还没有设置我的 front-end 代码库,它将设置为 http://localhost:4000。这一切都在 GraphQL 操场上进行测试
更新
gql playground 的配置:
{
"editor.cursorShape": "line",
"editor.fontFamily": "'Source Code Pro', 'Consolas', 'Inconsolata', 'Droid Sans Mono', 'Monaco', monospace",
"editor.fontSize": 14,
"editor.reuseHeaders": true,
"editor.theme": "dark",
"general.betaUpdates": false,
"prettier.printWidth": 80,
"prettier.tabWidth": 2,
"prettier.useTabs": false,
"request.credentials": "omit",
"schema.disableComments": true,
"schema.polling.enable": true,
"schema.polling.endpointFilter": "*localhost*",
"schema.polling.interval": 2000,
"tracing.hideTracingResponse": true,
"queryPlan.hideQueryPlanResponse": true
}
应用程序模块:
@Module({
imports: [
GraphQLModule.forRoot({
autoSchemaFile: join(process.cwd(), 'schema.gql'),
context: ({ req, res }) => ({ req, res }),
cors: {
origin:
process.env.NODE_ENV === 'production'
? '.herbievine.com'
: 'http://localhost:4000',
credentials: true,
}
}),
ThrottlerModule.forRoot({
ttl: 60,
limit: 20
}),
PostsModule,
CategoriesModule,
UsersModule,
AuthModule
],
controllers: [AppController],
providers: [AppService, PrismaService]
})
export class AppModule {}
授权模块:
@Module({
imports: [
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
secret: process.env.JWT_SECRET,
signOptions: {
expiresIn: '30d'
}
})
],
providers: [
PrismaService,
JwtStrategy,
LocalStrategy,
AuthService,
UsersService,
AuthResolver
],
controllers: [AuthController],
exports: [AuthService]
})
export class AuthModule {}
默认情况下,GQL playground 不发送凭据。在 GQL playground 的选项中,设置 request.credentials = 'include'
它应该有效
我有一个名为 login 的 GQL 突变,它 returns JWT 作为响应中的 cookie。
虽然 Set-Cookie
header 存在,但我的本地存储选项卡中没有显示任何内容。我的控制台也没有打印任何内容...
这是我的登录突变
@Mutation((returns) => AuthenticatedUser)
async login(
@Context() context: Auth.GqlContext,
@Args('payload', { type: () => UserLoginDto }) payload: UserLoginDto
): Promise<AuthenticatedUser> {
const authenticatedUser = await this.authService.login(payload)
context.res.cookie('jwt', authenticatedUser.jwt, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 1000 * 60 * 60 * 24 * 31, // one month
domain: process.env.NODE_ENV === 'production' ? '.herbievine.com' : undefined
})
return authenticatedUser
}
响应示例 JSON:
{
"data": {
"login": {
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjI0N2QyNmY3LTM3NzQtNGRiNS1hM2MzLTE2MTg3Mzk2ODdlMCIsImVtYWlsIjoidmluZWhlcmJpZUBnbWFpbC5jb20iLCJpYXQiOjE2MzYxMjkyMTksImV4cCI6MTYzODcyMTIxOX0.hHHAAgzs7wFjMP2C565fGGHAd0o-C9h-jA5qzm48OdE",
"user": {
"email": "email@gmail.com",
"name": "Some Name"
}
}
}
}
回复:
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: http://localhost:4000
Vary: Origin
Access-Control-Allow-Credentials: true
Set-Cookie: jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjI0N2QyNmY3LTM3NzQtNGRiNS1hM2MzLTE2MTg3Mzk2ODdlMCIsImVtYWlsIjoidmluZWhlcmJpZUBnbWFpbC5jb20iLCJpYXQiOjE2MzYxMjkyMTksImV4cCI6MTYzODcyMTIxOX0.hHHAAgzs7wFjMP2C565fGGHAd0o-C9h-jA5qzm48OdE; Max-Age=2678400; Path=/; Expires=Mon, 06 Dec 2021 16:06:11 GMT; HttpOnly; SameSite=Lax
Content-Type: application/json; charset=utf-8
Content-Length: 319
ETag: W/"13f-MuV4uipvL8ui1YJXuTSvJ1TM1H0"
Date: Fri, 05 Nov 2021 16:06:11 GMT
Connection: keep-alive
Keep-Alive: timeout=5
要求:
POST /graphql HTTP/1.1
Host: localhost:3000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost:3000/graphql
content-type: application/json
Origin: http://localhost:3000
Content-Length: 195
Connection: keep-alive
目前,我还没有设置我的 front-end 代码库,它将设置为 http://localhost:4000。这一切都在 GraphQL 操场上进行测试
更新
gql playground 的配置:
{
"editor.cursorShape": "line",
"editor.fontFamily": "'Source Code Pro', 'Consolas', 'Inconsolata', 'Droid Sans Mono', 'Monaco', monospace",
"editor.fontSize": 14,
"editor.reuseHeaders": true,
"editor.theme": "dark",
"general.betaUpdates": false,
"prettier.printWidth": 80,
"prettier.tabWidth": 2,
"prettier.useTabs": false,
"request.credentials": "omit",
"schema.disableComments": true,
"schema.polling.enable": true,
"schema.polling.endpointFilter": "*localhost*",
"schema.polling.interval": 2000,
"tracing.hideTracingResponse": true,
"queryPlan.hideQueryPlanResponse": true
}
应用程序模块:
@Module({
imports: [
GraphQLModule.forRoot({
autoSchemaFile: join(process.cwd(), 'schema.gql'),
context: ({ req, res }) => ({ req, res }),
cors: {
origin:
process.env.NODE_ENV === 'production'
? '.herbievine.com'
: 'http://localhost:4000',
credentials: true,
}
}),
ThrottlerModule.forRoot({
ttl: 60,
limit: 20
}),
PostsModule,
CategoriesModule,
UsersModule,
AuthModule
],
controllers: [AppController],
providers: [AppService, PrismaService]
})
export class AppModule {}
授权模块:
@Module({
imports: [
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
secret: process.env.JWT_SECRET,
signOptions: {
expiresIn: '30d'
}
})
],
providers: [
PrismaService,
JwtStrategy,
LocalStrategy,
AuthService,
UsersService,
AuthResolver
],
controllers: [AuthController],
exports: [AuthService]
})
export class AuthModule {}
默认情况下,GQL playground 不发送凭据。在 GQL playground 的选项中,设置 request.credentials = 'include'
它应该有效