我正在创建一个带有express.js集成的apollo服务器v4 gql网关。 我有用户 typedef 和用户解析器工作并在创建用户时创建 jwt。 然后,我尝试在
jwtMiddleware
端点上使用我的 /graphql
中间件,以便它可以验证传入的不记名令牌,以防止对我创建的其他一些查询发出未经身份验证的请求。
在我的index.ts中:
import express, { Request, Response, Application } from 'express';
import gqlServerV1 from './gql/v1/gqlServerV1';
import { mongoClient } from './mongodb/mongoclient';
import cors from 'cors';
import pkg from 'body-parser';
import { expressMiddleware } from '@apollo/server/express4';
import jwtMiddleware from './middleware/verifyJwt';
const { json } = pkg;
// Create express app
const app: Application = express();
const port: number = 5950;
const startUp = async () => {
// Fire up mongodb client
await mongoClient();
// Apply gql server to work with express as middleware w/ apollo-server v4
// Migrate away from v3: https://www.apollographql.com/docs/apollo-server/migration/#migrate-from-apollo-server-express
await gqlServerV1.start();
app.use(
'/v1/graphql',
cors<cors.CorsRequest>(),
json(),
jwtMiddleware,
expressMiddleware(gqlServerV1, {
context: async ({ req }) => ({
token: req.headers.token,
user: req.user,
}),
})
);
console.log(`server started at http://localhost:${port}`);
};
app.listen(port, async () => {
await startUp();
});
jwt中间件文件
import jwt from 'jsonwebtoken';
import dotenv from 'dotenv';
dotenv.config();
const JWT_SECRET = process.env.JWT_SECRET || 'defaultSecret';
const jwtMiddleware = async (req, res, next, context) => {
const authorizationHeader = req.headers.authorization;
console.log('heress');
if (!authorizationHeader || !authorizationHeader.startsWith('Bearer ')) {
// Token is missing or in an invalid format
return next();
}
const token = authorizationHeader.replace('Bearer ', '');
try {
// Verify the JWT token
const decodedToken = jwt.verify(token, JWT_SECRET);
console.log(decodedToken);
// Get the user data from the request context
const user = context.user;
// Continue processing the request if the user is authenticated
if (user) {
next();
} else {
// The user is not authenticated, so return an error
return res.status(401).json({ message: 'Unauthorized' });
}
} catch (error) {
// The JWT token is invalid, so return an error
return res.status(401).json({ message: 'Invalid token' });
}
};
export default jwtMiddleware;
我面临的问题:
启动服务器时,我在通过
index.ts
时看到此错误来自
req.user
TSError: ⨯ Unable to compile TypeScript:
src/index.ts:37:19 - error TS2339: Property 'user' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'.
37 user: req.user,
这是我的 gql 服务器,位于单独的文件中:
import { ApolloServer } from '@apollo/server';
import addressTypeDefs from './typeDefs/addressTypeDefs';
import userTypeDef from './typeDefs/userTypeDef';
import resolvers from './resolvers';
interface MyContext {
token?: String;
user?: Object;
}
// Create gql server
const gqlServerV1 = new ApolloServer<MyContext>({
typeDefs: [addressTypeDefs, userTypeDef],
resolvers,
introspection: false,
});
export default gqlServerV1;
打包json脚本:
"scripts": {
"start": "ts-node-dev --watch src src/index.ts",
"dev:server": "nodemon --watch './**/*.ts' --exec 'node --experimental-specifier-resolution=node --loader ts-node/esm' src/index.ts",
"test": "jest --detectOpenHandles --config jest.config.ts ./__tests__",
"watch": "nodemon --watch './**/*.{ts,graphql}' --exec 'node --experimental-specifier-resolution=node --no-warnings --loader ts-node/esm' src/index.ts",
"dev": "tsc-watch --onSuccess \"npm run watch\""
},
我还有一个 custom.d.ts 文件来尝试扩展express:
interface JwtPayload {
// Customize the properties based on JWT payload
email: string;
}
// Extend the express request type
declare namespace Express {
interface Request {
user: JwtPayload;
}
}
req.user
?谢谢!
我找到了问题所在,并将问题发布出来,以便其他人可以学习。我面临的问题是因为 ts-node 无法解释我扩展的类型并将用户添加到即请求中。这就是我所做的。
root/src/@types/express/index.d.ts
创建一个新的 dir 和 d.ts 文件。typeRoot
配置中的任何其他类型之前。像这样:{
"compilerOptions": {
"rootDirs": ["src"],
"outDir": "dist",
"lib": ["es2020"],
"target": "es2020",
"module": "esnext",
"moduleResolution": "node",
"esModuleInterop": true,
"types": ["node", "jest", "express"],
"typeRoots": ["./src/@types", "./node_modules/@types"],
"skipLibCheck": true /* Skip type checking all .d.ts files. */
},
"include": ["src/**/*.ts"]
}
index.d.ts
内部,我从 mongodb 导入了在 models
中设置的自定义界面,并将其设置为如下类型:import * as express from 'express';
import { User } from '../../models/User';
declare global {
namespace Express {
interface Request {
user?: User;
}
}
}
context
,并将 context
的实例替换为 req
。此后,我重新启动了 ts 服务器以及本地服务器,瞧,它工作了,愚蠢的
Property 'user' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'.
错误消失了。我的中间件开始工作,我开始看到来自中间件的控制台日志作为验证。
希望这对其他人有帮助。