Laravel 5.6 - Passport JWT httponly cookie单页应用程序身份验证自我消费API?

69

注意:我在这个问题上有4个赏金,但是下面所有得到投票的答案都不是这个问题所需的答案。所有需要的信息都在更新3中,只是寻找实现Laravel代码的方法。


更新3:这个流程图正是我想要实现的流程,下面所有内容都是原始问题加一些旧的更新。这个流程图总结了所需的所有内容。

下面流程图中的绿色部分是我知道如何做的部分。红色部分及其侧注是我正在寻求帮助使用Laravel代码完成的部分。

enter image description here


我做了很多研究,但当涉及到使用Laravel与JWT httponly cookie进行自包含API时,信息总是不完整(大多数在线教程只显示在本地存储中存储JWT,这不是非常安全)。看起来应该使用Passport中包含JWT的httponly cookie来识别用户在Javascript端,并发送每个请求以验证用户是否为其所说的用户。

还需要一些其他内容,才能完整地了解如何使此设置工作,但我在单个教程中还没有遇到过这些内容:

  1. Laravel Passport(不是tymon auth)生成加密JWT并将其作为httponly cookie发送到JS端响应后的登录。使用什么中间件?如果刷新令牌增加了更多安全性,如何实现?
  2. JavaScript(例如axios)API伪代码,调用认证端点时httponly cookie如何传递到后端,后端如何验证令牌是否有效。
  3. 如果从多个设备登录了单个帐户,然后一个设备被盗,如何撤销所有经过身份验证的用户设备的访问权限(假设用户从他们控制的已登录设备更改密码)?
  4. 登录/注册、注销、更改密码、忘记密码控制器方法通常看起来像什么,以处理令牌的创建/验证/撤销?
  5. CSRF令牌集成。

我希望对这个问题的答案能够成为未来读者和那些目前正在寻找关于自包含API上述问题的答案而苦苦挣扎的人们的易于跟随的指南。

更新1:

  1. 请注意,我之前尝试过CreateFreshApiToken,但是当涉及到撤销用户令牌(以上第3和第4点)时,它不起作用。这基于Laravel核心开发人员这条评论,谈论了CreateFreshApiToken中间件:

此中间件创建的JWT令牌未存储在任何位置。它们无法被吊销或“不存在”。它们只是提供一种方式,通过laravel_token cookie进行您的API调用进行验证。它与访问令牌无关。 此外:通常情况下,您不会在同一个应用程序中使用客户端发行的令牌来使用它们。您将在第一方或第三方应用程序中使用它们。同时使用中间件或客户

headerswindow.axios.defaults.headers.common = {
    'X-Requested-With': 'XMLHttpRequest',
    'X-CSRF-TOKEN': (csrf_token goes here)
};

这也是我寻找涵盖以上所有要点的解决方案的原因。抱歉,我正在使用Laravel 5.6而不是5.5。

更新2:

看起来密码授权/刷新令牌授权组合是正确的选择。寻找一个易于跟进实现指南,使用密码授权/刷新令牌授权组合。

密码授权: 当处理我们信任的客户端时,例如用于我们自己网站的移动应用程序,此授权适用。在这种情况下,客户端将用户的登录凭据发送到授权服务器,服务器直接发出访问令牌。

刷新令牌授权: 当服务器发出访问令牌时,它也设置了访问令牌的到期时间。当访问令牌到期时,使用刷新令牌授权进行刷新。在这种情况下,授权服务器将在发放访问令牌时发送一个刷新令牌,可以用该刷新令牌请求新的访问令牌。

我正在寻找一个易于实现、简单明了、全面覆盖以上原始5个要点的答案,包括httpOnly安全cookie、创建/撤销/刷新令牌、登录cookie创建、注销cookie撤销、控制器方法、CSRF等,使用密码授权/刷新令牌授权组合。


我在Laravel中使用了Luca Desgasperi的Passport和Oauth2。当涉及到移动应用和Javascript时,密码授权类型并不安全。只有授权码流程是可以的。但是令牌不能持续超过2分钟到60分钟或更长时间,这取决于数据的敏感性。Facebook令牌现在是2分钟+1次使用。使用授权码授权类型,浏览器会要求输入用户名和密码,并请求访问您的应用程序或您自己的网站(您可以默认允许),然后仅发送一个带有过期时间的令牌,该令牌每段时间都会刷新。 - KeitelDOG
2
@KeitelDOG 感谢您的建议,但是那个包只支持 Laravel 5.3,而且官方已经弃用它,推荐使用 Passport。正如所述,我正在寻找一种全面的方法/解决方案/实现指南,涵盖上述所有点。 - Wonka
我知道,这就是为什么我转向使用Passport的原因。Passport更好,并且最新版本甚至可以根据你在第三点所希望的那样控制撤销特定客户端中用户令牌的功能。 - KeitelDOG
@HilmiErdemKEREN 我添加了一条更新,关于为什么 CreateFreshApiToken 对我无效。无法撤销这些令牌...正在寻找一个涵盖所有上述点并能良好、协调地一起工作的解决方案。 - Wonka
1
对我来说,这种论点应该在官方文档中得到处理...如果护照旨在成为一种安全的身份验证方式,那么这种情况应该被清楚地解释。经过几天的研究,我发现几乎没有人以正确的方式处理这个问题。 - Wanny Miarelli
显示剩余15条评论
4个回答

42
我会尝试以通用的方式回答这个问题,以便该答案适用于各种框架、实现和语言,因为所有问题的答案都可以从一般协议或算法规范中得出。
应使用哪种OAuth 2.0授权类型?
这是要决定的第一件事。当涉及到SPA时,有两种可能的选择:
1.授权码授予(推荐,前提是客户端秘钥存储在服务器端) 2.资源所有者密码凭据授予
我没有提到隐式授权类型作为选项的原因是:
1.未通过提供客户端秘钥和授权码进行客户端认证步骤。所以安全性较低。 2.访问令牌作为URL片段发送回来(以便令牌不会发送到服务器),这将继续留在浏览器历史记录中。 3.如果发生XSS攻击,恶意脚本可以将令牌发送到攻击者控制下的远程服务器。
(此讨论排除了客户端凭据授权类型,因为它用于客户端非代表用户操作的情况。例如,批量作业)
在授权码授予类型的情况下,授权服务器通常是不同于资源服务器的服务器。最好将授权服务器保持分离,并将其用作组织内所有SPA的常见授权服务器。这始终是推荐的解决方案。
在授权码授予类型中,流程如下所示:
  1. 用户在SPA登录页面上点击登录按钮
  2. 用户将被重定向到授权服务器登录页面。客户端ID提供在URL查询参数中
  3. 用户输入他/她的凭据并单击登录按钮。用户名和密码将通过HTTP POST发送到授权服务器。凭证应该在请求正文或头中发送,而不是在URL中(因为URL在浏览器历史记录和应用程序服务器中被记录)。此外,应设置适当的缓存HTTP标头,以便不缓存凭据:Cache-Control: no-cache, no-storePragma: no-cacheExpires: 0
  4. 授权服务器根据存储有随机盐的用户名和用户密码哈希(哈希算法如Argon2、PBKDF2、Bcrypt或Scrypt)对用户进行身份验证
  5. 在成功验证后,授权服务器将从其数据库检索针对URL查询参数中提供的客户端ID的重定向URL。重定向URL是资源服务器URL
  6. 然后,用户将被重定向到具有URL查询参数中的授权代码的资源服务器端点
  7. 资源服务器将然后对授权服务器进行HTTP POST请求以获取访问令牌。授权代码、客户端ID、客户端密钥应该在请求正文中。 (应使用适当的缓存标头,如上所述)
  8. 授权服务器将在响应正文或头中返回访问令牌和刷新令牌(带有上述适当的缓存标头)
  9. 资源服务器现在将通过设置适当的Cookie(将在下面详细解释)将用户重定向(HTTP响应代码302)到SPA URL
另一方面,对于资源所有者密码凭证授权类型,授权服务器和资源服务器是相同的。它更容易实现,并且如果符合要求和实施时间表,也可以使用。
此外,请参考我在这里的答案,以获取有关资源所有者授权类型的进一步详细信息。
在SPA中,重要的是要注意,只有在调用适当的服务以确保请求中存在有效令牌后,才应启用所有受保护的路由。同样,受保护的API也应具有适当的过滤器来验证访问令牌。
为什么不应该将令牌存储在浏览器本地存储或会话存储中?
许多SPA确实将访问令牌和/或刷新令牌存储在浏览器本地存储或会话存储中。我认为我们不应该将令牌存储在这些浏览器存储中的原因是:
1. 如果发生XSS攻击,则恶意脚本可以轻松地从那里读取令牌并将其发送到远程服务器。从那时起,远程服务器或攻击者将没有问题模拟受害用户。
2. localstorage和sessionstorage不在子域之间共享。因此,如果我们在不同子域上运行两个SPA,则不会获得SSO功能,因为一个应用程序存储的令牌将无法在组织内的另一个应用程序中使用。

然而,如果令牌仍存储在这些浏览器存储之一中,则必须包含适当的指纹。指纹是一个具有密码学强度的随机字节字符串。原始字符串的Base64字符串将存储在以名称前缀__Secure-命名的HttpOnly、Secure、SameSite cookie中。需要适当的Domain和Path属性值。字符串的SHA256哈希值也将在JWT的声明中传递。因此,即使XSS攻击将JWT访问令牌发送到攻击者控制的远程服务器,它也无法发送cookie中的原始字符串,因此服务器可以根据cookie的缺失拒绝请求。此外,可以通过使用适当的content-security-policy响应头来进一步减轻XSS和脚本注入的影响。

注意:

  1. SameSite=strict 确保给定的 cookie 不会随着来自其他站点(通过 AJAX 或跟踪超链接)的请求一起发送。简而言之,任何来自具有与目标站点相同的“注册域”名称的站点的请求都将被允许。例如,“http://www.example.com” 是站点名称,则注册域是“example.com”。有关详细信息,请参见下面最后一节中的参考资料 3。因此,它提供了一些防止 CSRF 的保护。但是,这也意味着如果 URL 所给出的是论坛,则经过身份验证的用户不能跟随该链接。如果这对应用程序来说是一个严重的限制,则可以使用 SameSite=lax,它将允许跨站点请求,只要 HTTP 方法是安全的,即 GET、HEAD、OPTIONS 和 TRACE。由于 CSRF 基于不安全的方法,如 POST、PUT、DELETE,因此 lax 仍提供保护措施,以防止 CSRF。

  2. 为了允许在 "example.com" 的任何子域中通过所有请求传递 cookie,cookie 的 domain 属性应设置为 "example.com"

为什么我应该将访问令牌和/或刷新令牌存储在 cookie 中?

  1. 将令牌存储在cookie中时,我们可以将cookie设置为securehttpOnly。因此,如果发生XSS攻击,恶意脚本无法读取并将其发送到远程服务器。 XSS仍然可以从用户的浏览器冒充用户,但是如果关闭浏览器,则脚本无法造成更多损害。 secure标志确保令牌不能通过不安全的连接发送- SSL / TLS是强制性的
  2. 在cookie中设置根域为domain=example.com,例如,可以确保所有子域都可以访问cookie。因此,组织内的不同应用程序和服务器可以使用相同的令牌。只需要登录一次

如何验证令牌?

令牌通常是JWT令牌。通常,令牌的内容不是机密的。因此,它们通常不加密。如果需要加密(也许因为令牌中还传递了一些敏感信息),则有一个单独的规范JWE。即使不需要加密,我们也需要确保令牌的完整性。没有人(用户或攻击者)应该能够修改令牌。如果他们这样做,服务器应该能够检测到并拒绝带有伪造令牌的所有请求。为了确保这种完整性,使用像HmacSHA256这样的算法对JWT令牌进行数字签名。为了生成此签名,需要一个秘密密钥。授权服务器将拥有和保护该秘密。每当调用授权服务器API以验证令牌时,授权服务器都会重新计算传递的令牌上的HMAC。如果它与输入的HMAC不匹配,则返回负面响应。 JWT令牌以Base64编码格式返回或存储。

然而,对于资源服务器上的每个API调用,授权服务器不参与验证令牌。资源服务器可以缓存授权服务器发出的令牌。资源服务器可以使用内存数据网格(如Redis)或者如果无法全部存储在RAM中,则使用基于LSM的数据库(如带有Level DB的Riak)来存储令牌。
对于每个API调用,资源服务器将检查其缓存。
  1. 如果访问令牌不在缓存中,则API应返回适当的响应消息和401响应代码,以便SPA可以将用户重定向到适当的页面,在该页面上要求用户重新登录。
  2. 如果访问令牌有效但已过期(请注意,JWT令牌通常包含用户名和到期日期等信息),则API应返回适当的响应消息和401响应代码,以便SPA可以调用适当的资源服务器API使用刷新令牌(具有适当的缓存标头)来更新访问令牌。然后,服务器将使用访问令牌、刷新令牌和客户端密钥调用授权服务器,授权服务器可以返回新的访问和刷新令牌,最终流向SPA(具有适当的缓存标头)。然后客户端需要重试原始请求。所有这些都将由系统处理,无需用户干预。可以创建一个单独的cookie来存储刷新令牌,类似于访问令牌,但具有适当的Path属性值,以便刷新令牌不随每个请求一起发送,而仅在更新请求中可用。
  3. 如果刷新令牌无效或已过期,则API应返回适当的响应消息和401响应代码,以便SPA可以将用户重定向到适当的页面,在该页面上要求用户重新登录。

为什么我们需要两个令牌-访问令牌和刷新令牌?

  1. 访问令牌通常具有短的有效期,例如30分钟。刷新令牌通常具有更长的有效期,例如6个月。如果访问令牌被攻击者获取,攻击者只能在访问令牌有效期内冒充受害用户。由于攻击者没有客户端密钥,因此无法请求授权服务器获取新的访问令牌。然而,攻击者可以请求资源服务器进行令牌更新(如上所述的设置中,更新请求通过资源服务器进行,以避免在浏览器中存储客户端密钥),但考虑到其他采取的步骤,这是不太可能的,而且服务器可以根据IP地址采取其他保护措施。

  2. 如果访问令牌的短暂有效期有助于授权服务器根据需要撤销已发出的令牌。授权服务器还可以维护已发出令牌的缓存。系统管理员可以标记某些用户的令牌已撤销,如果需要的话。在访问令牌过期时,当资源服务器访问授权服务器时,用户将被强制重新登录。

CSRF呢?

为了保护用户免受CSRF攻击,我们可以采用类似Angular框架的方法(在Angular HttpClient documentation中有解释),即服务器必须发送一个非HttpOnly cookie(也就是可读取的cookie),其中包含该特定会话的唯一不可预测值。它应该是一个具有密码强度的随机值。然后客户端将始终读取cookie并在自定义HTTP头中发送该值(除了不应具有任何状态更改逻辑的GET和HEAD请求之外。注意,由于同源策略,CSRF无法从目标Web应用程序读取任何内容),以便服务器可以验证来自头和cookie的值。由于跨域表单无法读取cookie或设置自定义头,在CSRF请求的情况下,自定义头值将缺失,服务器将能够检测到攻击。
为了保护应用程序免受登录CSRF攻击,请始终检查referer头,并仅在referer是受信任的域时接受请求。如果referer头不存在或者是非白名单域,则简单地拒绝该请求。当使用SSL/TLS时,referrer通常存在。着陆页面(主要是信息性的,不包含登录表单或任何安全内容)可能会放松,允许缺少referer头的请求。
服务器应该阻止TRACE HTTP方法,因为它可以用来读取httpOnly cookie。此外,还应设置头文件Strict-Transport-Security: max-age=<expire-time>; includeSubDomains​,以仅允许安全连接,以防止中间人覆盖子域名的CSRF cookies。另外,应使用上述提到的SameSite设置。
状态变量(Auth0使用它)-客户端将生成并传递一个具有密码强度的随机nonce,服务器将在其响应中回显该nonce,以允许客户端验证nonce。这在Auth0 doc中有解释。

最后,SSL/TLS对于所有通信都是强制性的 - 截至今天,PCI/DSS合规性不接受低于1.1版本的TLS。应使用适当的密码套件以确保前向保密和身份验证加密。此外,访问和刷新令牌应在用户明确单击“注销”时立即列入黑名单,以防止任何令牌误用的可能性。

参考资料

  1. RFC 6749 - OAuth2.0
  2. OWASP JWT Cheat Sheet
  3. SameSite Cookie IETF Draft
  4. Cookie Prefixes
  5. RFC 6265 - Cookie

@Saptarshi Basu “由于攻击者没有客户端密钥,因此它无法请求授权服务器获取新的访问令牌。” 如果可能的话,您能否为我详细解释一下。如果攻击者获得了刷新令牌,他们不能轻易地创建访问令牌吗? - Ujjwal Jung Thapa
1
通常,在所有实现中,您需要提供客户端密钥以及刷新令牌来获取新的访问令牌。请注意,您总是将刷新令牌交给连接到您的服务的浏览器或设备。任何可以访问该设备的人都可以获得刷新令牌。除非有一个密钥,否则任何人都可以生成一个新的令牌。 - Saptarshi Basu
@Saptarshi Basu,您能告诉我“client secret”的意思吗?因为对于JWT,密钥只存储在服务器上,是吗?我认为客户端只发送刷新令牌。 - Ujjwal Jung Thapa
请参考RFC 6749的2.3.1节(在参考部分中给出链接)。所有资源服务器都需要使用客户端ID和客户端密钥(您可以将其视为资源服务器拥有的用户名和密码)向授权服务器进行身份验证。 - Saptarshi Basu
1
@RahulMisra 你说得对。我在我的日常工作中已经使用了Okta相当长的时间,所以在我上次回复中忽略了这一点。在你的情况下,我认为调用资源服务器(该服务器具有访问令牌的权限)来获取用户详细信息应该是可以的。一旦API返回用户详细信息(而不是令牌),它可以被缓存。 - undefined
显示剩余4条评论

16

Laravel Passport JWT

  1. 使用此功能时,您需要禁用cookie序列化。 Laravel 5.5存在关于cookie值的序列化/反序列化问题。 您可以在此处阅读更多信息 (https://laravel.com/docs/5.5/upgrade)

  2. 确保

    • 您的blade模板head部分中有<meta name="csrf-token" content="{{ csrf_token() }}">

    • axios设置为在每个请求中使用csrf_token。

您的resources/assets/js/bootstrap.js应该像这样:

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
  window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
  console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}
  1. 在这里了解设置auth路由(https://laravel.com/docs/5.5/authentication)。
  2. 在这里了解设置passport (https://laravel.com/docs/5.5/passport)。

重要的部分包括:

  • Laravel\Passport\HasApiTokens trait添加到您的User模型中
  • 在您的config/auth.php中,将api身份验证守卫的driver选项设置为passport
  • app/Http/Kernel.php中的web中间件组中添加\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class, 中间件

请注意,您可能可以跳过迁移和创建客户端。

  1. /login发出POST请求,传递您的凭据。您可以进行AJAX请求或普通表单提交。

如果登录请求是AJAX(使用axios),则响应数据将是HTML,但您感兴趣的是状态代码。

axios.get(
  '/login, 
  {
    email: 'user@email.com',
    password: 'secret',
  },
  {
    headers: {
      'Accept': 'application/json', // set this header to get json validation errors.
    },
  },
).then(response => {
  if (response.status === 200) {
      // the cookie was set in browser
      // the response.data will be HTML string but I don't think you are interested in that
    }
    // do something in this case
}).catch(error => {
  if (error.response.status === 422) {
    // error.response.data is an object containing validation errors
  }
  // do something in this case
});

登录时,服务器通过提供的凭据查找用户,基于用户信息(id、电子邮件等)生成一个令牌(该令牌不会被保存在任何地方),然后服务器返回一个包含生成的令牌的加密cookie的响应。

  1. 调用受保护路由的API。

假设您有一个受保护的路由

Route::get('protected', 'SomeController@protected')->middleware('auth:api');

您可以像平常一样使用axios进行ajax调用。Cookies会自动设置。

axios.get('/api/protected')
  .then(response => {
    // do something with the response
  }).catch(error => {
    // do something with this case of error
  });

当服务器收到调用解密请求laravel_cookie并获取用户信息(例如:id,电子邮件...)然后使用该用户信息进行数据库查找以检查该用户是否存在。如果找到用户,则授权用户访问所请求的资源。否则返回401错误。
无效JWT令牌。如您在评论中提到的,不必担心这一点,因为此令牌未保存在服务器上的任何位置。
更新
关于第3点,Laravel 5.6 Auth有一个新方法logoutOtherDevices。您可以在此处了解更多信息(https://laracasts.com/series/whats-new-in-laravel-5-6/episodes/7),因为文档非常简单。
如果您无法更新Laravel版本,则可以查看5.6中的实现方式,并为5.5构建自己的实现方式。
来自您问题的第4点。查看app/Http/Controllers/Auth中的控制器。
关于access_tokens和refresh_tokens,这是一种完全不同且更复杂的方法。您可以在网上找到很多教程来解释如何做到这一点。
我希望对您有所帮助。
顺便说一句,新年快乐! :)

感谢您的回复;解决我的问题,需要关注第三点和第四点。例如,如果设备丢失或被盗,我们需要能够通过更改密码来撤销访问权限,这将撤销与用户设备相关联的所有令牌。CreateFreshApiToken的问题在于我们无法撤销该用户的令牌,因此丢失/被盗的设备将始终处于活动状态,无法撤销。如果您也考虑“从所有设备注销”的功能,则需要相同类型的功能,其中将为给定用户撤销活动令牌。我们该如何做到这一点? - Wonka
感谢您的更新,我正在使用Passport身份验证实现最佳安全性。似乎使用access_tokenrefresh_token组合的密码授权是推荐的方法。这样,即使应用程序管理员也可以撤销用户令牌,立即使其下一个请求令牌无效并提示注销应用程序。您的方法存在的问题是,如果有人获取了另一个用户的CreateFreshApiToken令牌,那么他们就可以永远代表该用户,对吗?管理员无法撤销该令牌,因此他们可以无限制地访问。是否有一种处理这种情况的方法? - Wonka
新年快乐 :) 你对我上一条评论有什么想法吗? - Wonka
嘿@Wonka!抱歉我回复慢了。我不确定我理解你的要求。你想要一个使用某些oauth授权(如密码授权)而不是JWT的流程吗?在这种情况下,如果你有更多的客户端,你将如何在浏览器上存储客户端ID和客户端密钥? - Mirceac21
1
@Wonka,我不确定如何帮助你,因为我对你的应用程序了解不多,但也许这篇文章https://medium.com/lightrail/getting-token-authentication-right-in-a-stateless-single-page-application-57d0c6474e3会给你一些提示。 - Mirceac21
显示剩余5条评论

8
  • Laravel Passport是The PHP League的OAuth服务器的实现
  • 密码授权类型可用于用户名+密码身份验证
  • 记得通过代理进行身份验证请求以隐藏客户端凭据
  • 将刷新令牌保存在HttpOnly cookie中,以最小化XSS攻击的风险

更多信息请参见此处


谢谢Alex,但我已经看过这个教程了。我对它的问题是它说“6.客户端将访问令牌保存在存储中,例如浏览器应用程序将其保存在localStorage中”,而我只是想让cookie自动发送回来,有点像laravel_token的工作方式,但laravel_token不能使我们销毁其中的jwt。所以只是尝试使用http cookie,否则如果有人可以访问您的本地存储,他们可以获取您的访问令牌,使cookie无用。此外,该文章没有涉及CSRF集成。 - Wonka
是的,我理解你需要的就是这样的东西,它没有使用 Laravel Passport,但你可以看到如何防范网络攻击的示例。 - Ismoil Shifoev
希望使用Laravel 5.5和Passport,在不使用本地存储进行API调用的情况下,只使用cookie + CSRF集成来完成原始问题中的5个点,有更简单的方法。我认为应该有更好/更简单的方法来使用Passport和Laravel 5.5实现这5个点。我会保持问题开放,希望我们能得到一个回答,解决所有上述问题。我知道很多人都在寻找同样的东西,但是所有的东西似乎都已经过时或者不完整100%,没有一个来源/指南/laracast/SO问题展示如何使用L5.5 / Passport完全正确/完整地完成此操作。 - Wonka
我认为这是一个好主意,如果你想要其他人获得完整的信息,我很乐意帮助你。谢谢。 - Ismoil Shifoev

8

我在我的项目中还实现了Laravel Passport,我认为我已经涵盖了你在问题中提到的大部分内容。

  1. 我使用密码授权生成访问令牌和刷新令牌。您可以按照这些步骤设置护照并实现护照授权。 在您的登录方法中,您必须验证用户凭据并生成令牌,并将cookie(将cookie附加到响应)附加到响应中。 如果需要,我可以给您一些示例。
  2. 我添加了两个中间件用于CORS(处理传入请求头)以及检查传入的访问令牌是否有效,如果无效,则从存储的刷新令牌生成访问令牌(刷新令牌)。 我可以向您展示示例。
  3. 登录后,所有来自客户端的请求都应包含Authorization标头(Authorization: Bearer <token>)。

如果您清楚以上要点,请告诉我。


1
我添加了一个更新,我相信更新中的第二点应该使用请求/响应头发送/接收安全的httpOnly cookie,而不是Authorization: Bearer <token>。我还在寻找一种解决方案,可以涵盖上述所有要点,并且可以良好地协同工作。 - Wonka
在我的第三个用例(设备被盗)中,应该让用户从其他已登录的设备注销账户,在他们活跃的设备上更改密码等等... 这些都是应用服务器应该能够立即撤销当前已登录用户的访问权限,并使他们的令牌无效的情况。这个问题以及针对这种情况制定解决方案的过程对我来说非常困惑。 - Wonka
如果用户已注销或更改了密码,那么您可以选择删除存储的令牌或将吊销标志设置为 true。如果您想完全控制自己的令牌,我建议您使用密码授权方法。 - Wellwisher
我同意密码授权方法应该是正确的选择,但我正在寻找一个答案,它可以实现原始问题的5个点的使用/实现,以便提供一个完整可用的指南,说明整个系统将如何从服务器到客户端再返回服务器。 - Wonka
你能分享一些关于你提到的点的代码吗?你能集成一个 httpOnly 安全 cookie 用于访问/刷新令牌和 CSRF 吗?我们正在尝试避免在本地存储中使用 Authorization: Bearer <token>,而是使用可撤销的令牌/CSRF 和安全的 httpOnly cookie 进行请求/响应。 - Wonka
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接