随着前端应用程序的复杂度的不断提高,我们需要更好的安全措施来保护我们的数据和应用程序。在 Web 应用程序中,常见的验证方式是使用 JSON Web Token(JWT)。
GraphQL 是现代 web 应用程序中的常用技术。GraphQL 能够帮助我们更好地管理和开发 API。在使用 GraphQL 时,我们需要添加一些措施来保护我们的 API。
本文将介绍如何在 GraphQL 中使用 JWT 权限验证的方式来保护我们的 API。
什么是 JWT ?
JWT 是一个基于 JSON 的开放标准,用于以安全的方式在两个应用程序间传递信息。它通过数字签名验证数据的真实性,并为数据提供了一定的加密保护。
JWT 具有以下三个部分:
- Header(头部):包含了 JWT 的类型和算法信息。
- Payload(负载):包含了要传输的数据。
- Signature(签名):基于 Header 和 Payload,使用内置算法生成加密签名。
当 JWT 传到服务器端时,服务器端可以轻松解密 JWT 并读取所需的信息。服务器端还可以检查签名,确保 JWT 没有被篡改。
在 GraphQL 中使用 JWT 权限验证的方式是一种安全措施。接下来,我们将介绍如何实现以上的方法。
步骤 1:生成 JWT
在服务器端,我们需要使用所选的 JWT 库生成包含用户信息和必要元数据的 JWT。
在javascript中,我们可以使用 jsonwebtoken 库来生成 JWT:
const jwt = require('jsonwebtoken');
const userData = { username: 'myuser', roles: ['admin'] };
const token = jwt.sign(userData, 'secretKey', { expiresIn: '1h' });在上面的代码中,我们创建了一个 userData 对象包含用户名和角色信息。然后,我们使用 jsonwebtoken 库的 sign() 方法来生成 JWT。在此,'secretKey' 是指定的密钥,{ expiresIn: '1h' } 是 JWT 的到期时间。在这种情况下,JWT 有效期为 1 小时。
步骤 2:在查询中使用 JWT
现在我们已经获得了 JWT,我们需要将其添加到每个 GraphQL 查询中。我们可以创建一个中间件在每个请求上自动添加 JWT。要完成此操作,我们需要使用 Apollo-Server 中的 context 对象。在 context 中,我们可以添加任何自定义数据,这些数据将在解析查询时传递给所有解析器。
// www.javascriptcn.com code example
const { ApolloServer, gql } = require('apollo-server');
const jwt = require('jsonwebtoken');
const typeDefs = gql`
type Query {
hello: String
}
`;
const resolvers = {
Query: {
hello: (parent, args, context) => {
const userData = context.user;
return `Hello ${userData.username}`;
}
}
};
const getUserFromToken = (req) => {
const token = req.headers.authorization;
if (token) {
try{
const user = jwt.verify(token, 'secretKey');
return user;
} catch(err) {
throw new Error('Invalid token');
}
}
};
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => {
const user = getUserFromToken(req);
return { user };
}
});
server.listen().then(({ url }) => {
console.log(`Server ready at ${url}`);
});在上面的代码中,我们使用 getUserFromToken() 函数从 HTTP 请求头中提取 JWT,并根据密钥验证签名。如果密钥正确,则返回用户数据。
我们将 user 对象添加到 context 中,然后在查询中使用该对象。
步骤 3:设置需要验证的查询
现在我们已经将 JWT 添加到查询中,并将其添加到了 context 对象中。接下来,我们需要确定哪些查询需要验证。
我们可以使用 GraphQL 的指令来定义 GraphQL 查询中需要验证的部分。在下面的示例中,我们将为需要身份验证的查询添加 @auth 指令。
// www.javascriptcn.com code example
const typeDefs = gql`
directive @auth(requires: Role = ADMIN) on OBJECT | FIELD_DEFINITION
enum Role {
ADMIN
USER
}
type Query @auth(requires: USER) {
myData: MyData
}
type MyData @auth(requires: ADMIN) {
data: String
}
`;使用指令 @auth 来确定需要验证的查询,在上面示例中,在 Query 和 MyData 类型的定义中都使用了 @auth 指令。@auth 指令接受一个参数 requires,该参数指定需要的用户角色。在本例中,USER 和 ADMIN 是要求的角色。
步骤 4:在解析查询时验证 JWT
现在我们已经定义了需要验证的查询,接下来在查询解析时验证 JWT。
我们可以创建一个称为 auth 的函数,并在每个查询中解析 GraphQL 类型时调用它。在此函数中,我们可以获取当前查询中的元数据 parent、args 和用户数据 userData。从 userData 中获取角色,并验证其是否具有指定角色。如果用户不具有要求的角色,则抛出错误。
// www.javascriptcn.com code example
const auth = (requires) => (resolver) => (parent, args, context, info) => {
const { user } = context;
if(!user) {
throw new Error('Not authorized');
}
const hasRole = requires && user.roles.includes(requires);
if(!hasRole) {
throw new Error('Requires authorization');
}
return resolver(parent, args, context, info);
}
const resolvers = {
Query: {
myData: auth('admin')((parent, args, context) => {
return { data: 'secret data' };
}),
},
MyData: {
data: auth('user')((parent, args, context) => {
return parent.data;
}),
},
};在上面的代码中,我们定义了 auth 中间件函数。其接受一个 requires 参数,以指定所需的角色。然后,它返回另一个函数,并接受 parent、args、context 和 info 参数。
我们在 MyData 类型的解析器函数上使用 auth 中间件,以强制用户必须拥有 user 角色。同样,我们在 Query 类型的解析器函数上使用中间件,以强制用户必须拥有 admin 角色。
小结
在本文中,我们已经介绍了在 GraphQL 中使用 JWT 权限验证的方式。我们可以将 JWT 添加到查询中,并将其作为 context 对象中的一部分传递给 GraphQL 解析器。我们还介绍了如何使用自定义验证函数来实现一个可配置的授权系统。
JWT 是一种经过验证的,可以帮助我们更好地保护我们的应用程序。在将其应用到您的 GraphQL API 中之前,您需要确保正确地实现了 JWT 并使用了固定的密钥来验证签名。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67cfd91ce46428fe9ebfea59