在Node项目中使用Passport.js实现JWT
什么是JWT?
JSON Web Token(JWT)是一种开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于在各方之间安全地传输信息。该信息可以验证和信任,因为它是经过数字签名的。JWT通常用于身份验证和授权,因为它可以轻松地传递用户身份和角色信息。
JWT由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。头部包含JWT使用的算法和令牌类型。载荷包含实际的数据,如用户ID、角色等信息。签名使用头部和载荷以及密钥的组合生成,用于验证令牌是否被篡改。
JWT的优点包括:
- 简单:JWT是一种紧凑的、自包含的方式,易于使用和传输。
- 安全:JWT使用数字签名验证令牌是否被篡改。
- 通用:JWT标准被广泛支持,并可用于多种编程语言和框架中。
JWT的工作原理
JWT的工作原理可以简述如下:
- 用户使用用户名和密码进行身份验证。
- 服务器对用户进行身份验证,并生成JWT。
- JWT被返回给用户,以便将其存储在客户端中。
- 用户将JWT用于后续请求的身份验证和授权。
在JWT中,载荷包含用户信息,例如用户ID和角色,这些信息可以使用标准化的声明,例如“sub”(主题)、“exp”(到期时间)和“iss”(发行人)进行组织。这些声明以键值对的形式出现,并以Base64编码的字符串进行编码。
JWT的签名是使用头部和载荷以及密钥的组合生成的。这个过程可以使用各种加密算法完成,例如HMAC、RSA和ECDSA。签名的目的是确保令牌未被篡改,因此服务器可以信任令牌的内容。
使用Koa2和Passport.js实现JWT
现在,我们将使用Koa2和Passport.js来实现JWT。
1. 创建Koa2应用程序
我们首先需要创建一个Koa2应用程序。在您的终端中,使用以下命令创建一个名为“koa-jwt”的新目录:
mkdir koa-jwt
cd koa-jwt
然后,使用以下命令初始化新的npm项目:
npm init -y
接下来,使用以下命令安装必要的依赖项:
npm i koa koa-router koa-bodyparser koa-passport passport-jwt jsonwebtoken
在安装完依赖项之后,我们可以开始配置Koa2应用程序并实现JWT。
2. 配置Passport.js
我们需要使用Passport.js来验证JWT并保护我们的API路由。我们将使用Passport.js的JWT策略来验证JWT。
在项目文件夹中创建一个名为config
的文件夹,并在其中创建一个名为passport.js
的文件:
const passportJWT = require('passport-jwt');
const ExtractJwt = passportJWT.ExtractJwt;
const JwtStrategy = passportJWT.Strategy;
const jwtOptions = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'your_jwt_secret'
};
module.exports = passport => {
passport.use(
new JwtStrategy(jwtOptions, (jwtPayload, done) => {
// 检查数据库中是否存在用户(为了方便,写死123)
if (jwtPayload.id === 123) {
done(null, { id: 123,role: 'admin'})
} else {
done(null, false);
}
})
);
};
在这个文件中,我们首先导入了passport-jwt
和jsonwebtoken
模块。然后,我们定义了jwtOptions
对象,它包含从请求头中提取JWT的选项和JWT的密钥。我们使用ExtractJwt.fromAuthHeaderAsBearerToken()
方法从Bearer Token中提取JWT。
接下来,我们使用Passport.js的JwtStrategy
构造函数创建一个新的JWT策略。在策略的回调函数中,我们首先检查JWT有效载荷中的用户ID是否存在于数据库中。如果用户存在,则调用done(null, user)
函数。如果用户不存在,则调用done(null, false)
函数。
最后,我们使用module.exports
导出了一个函数,该函数将Passport.js作为参数并在其中定义了我们的JWT策略。
3. 配置Koa2服务器和中间件
接下来,我们需要配置Koa2服务器和中间件。在项目文件夹中创建一个名为app.js
的文件,并将以下代码添加到文件中:
const Koa = require('koa');
const bodyParser = require('koa-bodyparser');
const passport = require('koa-passport');
const jwtConfig = require('./config/passport');
const authRoutes = require('./routes/auth');
const app = new Koa();
app.use(bodyParser());
app.use(passport.initialize());
jwtConfig(passport);
app.use(authRoutes.routes());
app.listen(3000, () => {
console.log('Server listening on port 3000');
});
在这个文件中,我们首先导入了Koa、Koa BodyParser、Passport.js和authRoutes
路由。然后,我们创建了一个新的Koa实例,并使用app.use
中间件将Body Parser、Passport.js和我们的路由绑定到应用程序中。在jwtConfig
函数中,我们将Passport.js作为参数,并配置了JWT策略。
最后,我们使用app.listen
方法启动服务器并在端口3000上侦听连接。
4. 创建授权路由
现在我们需要创建一个授权路由,该路由将使用JWT保护我们的API路由。在项目文件夹中创建一个名为routes
的文件夹并在其中创建一个名为auth.js
的文件:
const Router = require('koa-router');
const jwt = require('jsonwebtoken');
const passport = require('koa-passport');
const router = new Router();
router.post('/login', async (ctx, next) => {
const { username, password } = ctx.request.body;
// 检查用户名和密码是否正确(这里为了方便,写死了username和password)
if (username === 'admin' && password === 'password') {
const payload = { id:123 };
const token = jwt.sign(payload, 'your_jwt_secret');
ctx.body = { token };
} else {
ctx.status = 401;
ctx.body = { error: '用户名或密码无效!' };
}
});
router.get('/protected', passport.authenticate('jwt', { session: false }), async (ctx, next) => {
const user = ctx.state.user;
// 检查用户是否存在
if (!user) {
ctx.status = 401;
ctx.body = { error: '无效token!' };
return;
}
// 检查用户是否有权访问资源
if (user.role !== 'admin') {
ctx.status = 403;
ctx.body = { error: '访问被拒绝!' };
return;
}
ctx.body = { message: '通过!' };
});
module.exports = router;
在这个文件中,我们首先导入了Koa Router、jsonwebtoken和Passport.js。然后,我们创建了一个新的路由,并定义了两个路由处理程序:/login
和/protected
。
/login
用于验证用户名和密码,并生成JWT。如果用户名和密码正确,则我们使用jwt.sign
方法生成JWT,并将其返回给客户端。否则,我们返回401错误和错误消息。
/protected
中,我们首先使用ctx.state.user
来获取JWT策略中传递的用户对象。然后,我们检查用户对象是否存在。如果不存在,则返回401错误和错误消息。这表示JWT验证不通过。
接下来,我们检查用户对象中的角色属性。如果用户角色不是“admin”,则返回403错误和错误消息。这表示用户不允许访问受保护的资源。
最后,如果JWT验证通过并且用户被授权访问受保护的资源,则返回受保护的资源。
5. 测试应用程序
现在,我们已经创建了一个Koa2应用程序,并使用Passport.js实现了JWT验证。让我们使用Postman测试我们的应用程序。
首先,我们需要使用以下JSON数据向/login
路由发出POST请求:
{
"username": "admin",
"password": "password"
}
如果用户名和密码正确,则服务器将返回一个JWT,例如:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTIzLCJpYXQiOjE2MTc1NjE2MDZ9.CjajG6SXrYJ8gU6_JK_OE92nH9Fk-6ScDjszgCkxKJw"
}
现在,我们可以使用此JWT向/protected
路由发出GET请求,并使用Bearer Token将JWT传递给服务器。如果JWT验证通过并且用户被授权访问受保护的资源,则服务器将返回:
{
message: '通过!'
}
如果JWT验证不通过,则服务器将返回:
{
error: '无效token!'
}
如果JWT验证通过但用户没有被授权访问受保护的资源,则服务器将返回:
{
error: '访问被拒绝!'
}
结论
本文详细介绍了JWT的工作原理以及如何使用Koa2和Passport.js实现JWT身份验证。我们通过创建Passport.js JWT策略和授权路由,保护了我们的API路由。如果您需要身份验证和授权解决方案,JWT和Passport.js是非常好的选择。
转载自:https://juejin.cn/post/7215153930472865853