关于使用Express Gateway访问Api和使用JWT进行用户身份验证的建议

关于使用Express Gateway访问Api和使用JWT进行用户身份验证的建议,express,jwt,api-key,express-gateway,Express,Jwt,Api Key,Express Gateway,我在Express中有一个服务器,它向web应用程序公开一些API。 我正在寻找一种管理最终用户和第三方身份验证的好方法 现在,当用户使用电子邮件和密码注册时,服务器会生成一个与该用户关联的JWT 函数createToken(用户、角色){ var usr={ 角色:角色,//管理员|客户|商店 电子邮件:user.email, 名称:user.name }; var expires=(Date.now()/1000)+60*60*24*365;//1年 var nbf=Date.now()/1

我在Express中有一个服务器,它向web应用程序公开一些API。 我正在寻找一种管理最终用户和第三方身份验证的好方法

现在,当用户使用电子邮件和密码注册时,服务器会生成一个与该用户关联的JWT

函数createToken(用户、角色){
var usr={
角色:角色,//管理员|客户|商店
电子邮件:user.email,
名称:user.name
};
var expires=(Date.now()/1000)+60*60*24*365;//1年
var nbf=Date.now()/1000;
usr['nbf']=nbf;
usr['exp']=到期;
var token=jwts.encode(usr,process.env.SECRET);
返回令牌;
}
当Web客户端接收到该令牌时,它将该令牌存储在cookie/Web_存储中,并将其用于对服务器的每个API调用以及自动登录。令牌还包含
角色
,因此当服务器收到请求时,它知道该用户/角色是否可以访问所请求的路由/资源

函数检查令牌(令牌、api\u名称){
//验证机密并检查exp
jwt.verify(令牌,process.env.SECRET,
功能(错误,已解码){
if(err){throw{msg:“令牌已过期或未经身份验证”,代码:errors.err_not_AUTH};}
否则{
var-role=已解码['role'];
return do_role_can_access_api(role,api_name);//true或false
}
});
}
现在,一些第三方希望访问我的一些API。我想创建一个Express网关,为希望使用我的服务器的应用程序生成api密钥,并为单个用户保留现有的JWT身份验证

所以我要

 |----------------|
 |   my Web-App   |
 |----------------|----> |------------|            |------------|
                         |   Express  |            | my Server  |
                         |   Gateway  |----------> |    APIs    |
 |----------------|----> |------------|            |------------|
 |    3rd party   |
 |----------------|
  • 我的Web应用程序应该可以访问所有API,因为我的Web应用程序正在使用 通过
    管理员
    s(像我一样),以及我们的用户(
    客户
    商店
  • 第三方应用程序应仅访问某些API,因为它们将 只有
    客户
    商店
所以我想做这样的事情:

 |----------------|
 |   my Web-App   |
 |     scopes:    |
 | [admin, user]  |
 |                |
 |----------------|----> |------------|            |------------|
                         |   Express  |            | my Server  |
                         |   Gateway  |----------> |    APIs    |
 |----------------|----> |------------|            |------------|
 |    3rd party   |
 |    scopes:     |
 |     [user]     |
 |----------------|
最后,我的Web应用程序将有一个包含所有作用域的ApiKey,而第三方ApiKey将只有
用户
作用域,因此我可以在该作用域上过滤路由。单个真实用户,无论使用何种应用程序,都将使用JWT令牌登录并发出请求

因此,每个请求都将有一个ApiKey(基于使用的应用程序)和一个JWT令牌(用于识别用户):

  • 第三方服务器将ApiKey添加到标头中
  • JWT令牌将由用户浏览器的web_存储器(检索并)添加到标头中

听起来好吗

首先祝贺您在开发安全应用程序方面所做的所有努力,因为我们并不是每天都看到开发人员走那么远

澄清可能的误解 在我深入讨论您的问题之前,我想首先澄清一个误解,即开发人员通常在什么访问其后端方面存在误解。在中详细讨论了这一点,我们可以阅读:

什么是向API服务器发出请求的东西。它真的是你的移动应用程序的真实实例,还是一个机器人、一个自动脚本或一个攻击者用Postman之类的工具在你的API服务器上手动戳来戳去

是移动应用程序的用户,我们可以通过多种方式进行身份验证、授权和识别,比如使用OpenID Connect或OAUTH2流

虽然本文以移动应用程序为背景,但为了理解访问API服务器的内容和用户之间的区别,对
移动应用程序
的引用可以替换为
web应用程序
。如果你有疑问,请去阅读链接文章的部分,其中还包括一个图形,以帮助理解这一点

你的问题 现在,当用户使用电子邮件和密码注册时,服务器会生成一个与该用户关联的JWT

var expires=(Date.now()/1000)+60*60*24*365;//一年
我的Web应用程序应该可以访问所有API,因为我的Web应用程序由管理员(如我)和用户(客户和商店)使用

这是对身份验证令牌的渴望,特别是当您说API由管理员访问时,但即使对于普通用户来说也太长了

根据您的使用情况,我建议它们在分钟范围内,因此我建议您切换到使用刷新令牌,这将使访问令牌保持短期,而刷新令牌可以是长期的,但在小时范围内,而不是天、周或年

刷新令牌流示例:

注意:虽然上图属于在移动API环境下编写的一系列文章,但其中有许多信息也适用于服务于web应用程序和第三方客户端的API

通过使用这种方法,短寿命访问令牌失败时的客户端需要通过发送刷新令牌来请求新的访问令牌,以便获得新的访问令牌

这里重要的一点是,刷新令牌不应发送到浏览器,只能发送访问令牌,因此您的第三方客户端必须非常清楚这一点,这样他们就不会试图直接从javascript访问API,而是应该将其委托给后端

API密钥和JWT 最后,我的Web应用程序将有一个包含所有作用域的ApiKey,而第三方ApiKey将只有用户作用域,因此我可以在上面筛选路由。单个真实用户,无论使用何种应用程序,都将使用JWT令牌登录并发出请求。 因此,每个请求都将有一个ApiKey(基于所使用的应用程序)和一个JWT令牌(用于标识用户):