带有 Spring Security 5 的 Spring Boot 2 可以配置为使用 openID 连接 ID 提供程序进行身份验证。我仅通过配置 Spring Security 就设法设置了我的项目 - 这适用于各种完美预配置的安全机制,例如缓解会话固定。
但是似乎 Spring Security 在令牌过期时不会自行刷新令牌(存储在会话中)。
是否有设置或我必须自己照顾刷新?
更新:Spring Boot 2.1 已经发布,所以是时候重新审视这个问题了。我仍然不知道 accessToken 现在是否可以自动刷新,或者我是否必须为此编写代码......
请参阅下面的代码以解决此问题
我正在尝试找到处理ASP.NET Core 2.1中已过期的刷新令牌的最佳和最有效的方法.
让我解释一下.
我正在使用OAUTH2和OIDC来请求授权代码授权流程(或使用OIDC的混合流程).此流/授权类型使我可以访问AccessToken和RefreshToken(授权代码,但这不适用于此问题).
访问令牌和刷新令牌由ASP.NET核心存储,并且可以分别使用HttpContext.GetTokenAsync("access_token");和检索HttpContext.GetTokenAsync("refresh_token");.
我可以刷新access_token没有任何问题.当问题refresh_token以某种方式过期,撤销或无效时,问题就会发挥作用.
正确的流程是让用户再次登录并再次返回整个身份验证流程.然后应用程序获得一组新的令牌返回.
我的问题是如何以最好和最正确的方法实现这一目标.我决定编写一个自定义中间件,access_token如果它已经过期,它会尝试续订.然后,中间件将新令牌设置AuthenticationProperties为HttpContext,以便以后管道中的任何调用都可以使用它.
如果由于任何原因刷新令牌失败,我需要再次调用ChallengeAsync.我从中间件调用ChallengeAsync.
这是我遇到一些有趣的行为的地方.然而,大部分时间这都有效,有时候我会得到500个错误而没有关于什么是失败的有用信息.几乎看起来中间件试图从中间件调用ChallengeAsync有问题,也许另一个中间件也试图访问上下文.
我不太清楚发生了什么事.我不太确定这是否是适合这种逻辑的地方.也许我不应该在中间件中使用它,也许在其他地方.也许Polly for HttpClient是最好的地方.
我愿意接受任何想法.
感谢您的任何帮助,您可以提供.
代码解决方案对我有用
感谢MickaëlDerriey的帮助和指导(请务必在此解决方案中查看他的答案以获取更多信息)这是我提出的解决方案,它为我工作:
options.Events = new CookieAuthenticationEvents
{
OnValidatePrincipal = context =>
{
//check to see if user is authenticated first
if (context.Principal.Identity.IsAuthenticated)
{
//get the users tokens
var tokens = context.Properties.GetTokens();
var refreshToken = tokens.FirstOrDefault(t => t.Name == "refresh_token");
var accessToken = tokens.FirstOrDefault(t => t.Name == "access_token");
var exp …Run Code Online (Sandbox Code Playgroud) oauth openid-connect asp.net-core refresh-token asp.net-core-2.1
我正在使用 JWT 对我的应用程序的用户进行身份验证。当用户登录时,他们会获得一个访问令牌和一个刷新令牌。为了保证刷新令牌的安全,我不会将其存储在客户端,而是将其与他们的帐户一起保存在后端,因此不容易访问。不过,我对刷新令牌的安全性感到困惑,这是我在阅读有关如何使用刷新令牌的在线资源时所理解的逻辑:
我担心的安全问题是,如果其他人(黑客)获得了访问令牌并使用它向 api 发送请求,如果令牌已过期,api 将使用刷新令牌来获得新的访问权限令牌 + 新的刷新令牌,并至少将访问令牌返回给黑客。
我读了这篇文章大约 5-6 次,我读了几遍这篇文章,以及一些关于这个主题的其他文章,他们都说了一些类似的话
确保安全地存储刷新令牌,因为它是长期存在的,access_token 是短暂的,所以没什么大不了的
但是根据我上面描述的流程,访问令牌是否是短暂的并不重要,刷新令牌将用于获取新的访问令牌并永久访问。
有什么我想念的吗?如果黑客持有过期的访问令牌,api 如何知道谁在发送请求?它仍然会使用刷新令牌发送一个新的。我应该以某种方式验证谁在发送请求吗?
更新
所以我明白,当请求新的访问令牌时,我需要发送刷新令牌、客户端 ID 和客户端机密。我遇到的问题是,像以前一样,黑客可以向我的 API 服务器发送请求,服务器从黑客那里获取被劫持的访问令牌,它会看到它已过期,因此它将发送刷新令牌,以及将 clientID/client 机密(存储为环境变量)发送到 Auth API 并取回新的访问令牌/刷新令牌,这使我们回到了同样的问题。
更新 2
关于这个主题的一些有趣的问题:
根据第二个问题和答案,似乎刷新令牌不是一种更安全的维护访问方式,只是更容易检测到黑客,因为不断请求身份验证/刷新令牌并使对方的令牌无效。问题是这只会在 2 个用户同时尝试访问资源时发生 - 如果只有黑客碰巧在给定时间段内处于活动状态,他将可以无限制地访问原始用户数据,直到原始用户尝试使用应用程序并访问受保护的资源
如果当前访问令牌已过期,我正在尝试刷新访问令牌。
我一次发送多个请求,我想创建一种队列,因此其他请求不会请求刷新令牌路由。
我在谷歌上搜索了一些最佳实践和示例,并找到了以下针对 Angular 6 和 rxjs v6 的解决方案,它使用了 BehaviourSubject 和 switchMaps。(请看附件代码)
但是我使用的是 Angular 8 (8.1) 和 rxjs v6.4,这个解决方案对我不起作用。
它根本没有达到switchMap在this.authService.requestAccessToken().pipe。(使用console.log测试)
但是,如果我发表评论return this.refreshTokenSubject.pipe并返回,next.handle(request)它会到达那个 switchMap,但我的其他请求都失败了。
您知道是否有任何更改,或者我应该尝试以其他方式执行此操作吗?
import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { AuthService } from './auth.service';
import { Observable, BehaviorSubject, Subject } from 'rxjs';
import { switchMap, take, filter } from 'rxjs/operators';
@Injectable()
export class TokenInterceptor implements HttpInterceptor {
private refreshTokenInProgress = …Run Code Online (Sandbox Code Playgroud) rxjs angular-http-interceptors refresh-token angular angular8
我有一个看起来像这样的政策
var retryPolicy = Policy
.Handle<HttpRequestException>()
.OrResult<HttpResponseMessage>(resp => resp.StatusCode == HttpStatusCode.Unauthorized)
.WaitAndRetryAsync(3,
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
onRetry: (resp, timeSpan, context) =>
{
// not sure what to put here
});
Run Code Online (Sandbox Code Playgroud)
然后我有一个指定的客户端,看起来像这样
services.AddHttpClient("MyClient", client =>
{
client.BaseAddress = new Uri("http://some-url.com");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authToken);
client.Timeout = 30000;
})
.AddPolicyHandler(retryPolicy);
Run Code Online (Sandbox Code Playgroud)
如果收到 401,我需要刷新 http 客户端上的不记名令牌。因此,在完美的世界中,以下代码将完全实现我想要完成的任务
var retryPolicy = Policy
.Handle<HttpRequestException>()
.OrResult<HttpResponseMessage>(resp => resp.StatusCode == HttpStatusCode.Unauthorized)
.WaitAndRetryAsync(3,
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
onRetry: (resp, timeSpan, context) =>
{
var newToken = GetNewToken();
//httpClient doesn't …Run Code Online (Sandbox Code Playgroud) 在过去的几天里,我一直在阅读有关使用刷新和访问令牌进行身份验证的内容,但这是我找不到答案的一件事。假设发送了过期的访问令牌。后端是否应该自动刷新它(如果提供了刷新令牌),或者刷新应该只在刷新端点完成?
作为示例,请考虑以下两个身份验证流程:
前端不必担心刷新令牌,但它仍然必须在每次请求后查找响应标头以检查是否发送了新令牌。
refresh/。API 检查令牌是否有效。如果一切正常,它会返回一个新的访问令牌。每次请求后,客户端都必须检查令牌是否过期,如果过期,则必须执行新请求来刷新令牌。正在向服务器发出更多请求,但另一方面,职责可以更好地分离,因为身份验证路由仅负责处理访问令牌,而刷新令牌处理则位于另一个路由中。
我很难找到有关该主题的资源,因此我不太确定哪种解决方案更好,或者即使我描述的解决方案完全正确。如果我必须选择一个,我会选择自动刷新,因为发出的请求更少,而且客户端可用性看起来更好,但正如我所说,我并不是 100% 同意这一点,因此我正在制作该线程。
访问令牌应该如何刷新?
我已经添加AddOpenIdConnect到ConfigureServices我的 ASP.NET Core 3.1 Razor 应用程序的方法中。在令牌过期之前,它运行良好,然后我从 IDP 收到 401 响应。
我看过一个例子,展示了一种手动连接刷新令牌的方法。
但我很犹豫要不要这样做。微软的人似乎不太可能没有考虑刷新令牌。
ASP.NET Core 3.1 是否有办法让刷新令牌自动更新访问令牌?
oauth-2.0 openid-connect asp.net-core refresh-token asp.net-core-3.1
在使用 OIDC 服务器进行身份验证的单页应用程序 (JavaScript) 的上下文中,保持会话活动(在过期后获取更多令牌)的标准和推荐方法是使用 HttpOnly Cookie 并在 iframe 中执行静默更新。太好了,不涉及刷新令牌,因为浏览器无法保守秘密。
\n现在看来,浏览器将阻止跨域 Cookie(Safari 和 Brave 已经这样做了,Chrome 似乎将是下一个),因此,如果服务器位于不同的域上,那么未来唯一的方法似乎是将刷新令牌与刷新令牌轮换(以及可能的重用检测)结合使用,这似乎可以缓解问题。但真的是这样吗?
\n场景 1)刷新令牌 (RT1) 被盗,用户请求新令牌并由于轮换而取回新的刷新令牌 (RT2)。RT1 现在无效,攻击者无法使用。伟大的。
\n场景 2)刷新令牌 (RT1) 被盗,攻击者执行获取新令牌 (RT2) 的请求,用户使用旧令牌 (RT1),现在所有内容都被丢弃,用户必须再次登录(重用检测)并且攻击者的令牌也无效。伟大的。好吧,我在这里看到了一个问题(用户必须再次登录并且不知道为什么),但至少问题已经解决了。
\n场景 3)这是我在任何地方都没有看到提到的场景。假设攻击者在不使用后续 RT 的情况下窃取了它们,因此它继续窃取 RT1。用户刷新,攻击者也窃取了RT2。一切工作正常,因为攻击者没有使用令牌,但也许他将所有令牌发送到其他地方进行存储。最后,用户关闭窗口,攻击者提取了 RT1 和 RT2。此时,攻击者可以使用最新的RT(RT2)来冒充用户,直到用户返回应用程序。假设他离开一周,攻击者拥有一周新的访问令牌(他可以不断刷新令牌)。直到最后没有人注意到任何事情。有了 Cookie,攻击者只能在浏览器会话期间进行操作,现在它有更多时间进行操作。
\n那么...具有重用检测功能的 RTR 真的足够安全吗?主要论点是“这始终是一个风险/收益的选择”,我明白,但怎么会到了 2020 年,我们仍然遇到浏览器问题呢?你发现我遗漏的第三个场景有什么问题吗?老实说,会话 cookie 一直是最好的选择,事实上浏览器会阻止我们在这种常见场景中使用它们,这一事实让我抓狂:)
\n谢谢。
\n附言。我将在这里复制我找到的有关此问题的一些资源:
\n\n“ RTR 并不是一种包罗万象的安全措施。如果攻击者设法在应用程序关闭之前获取最后一个刷新令牌,他们可能能够继续轮换被盗的刷新令牌。为了避免长期滥用被盗的刷新令牌,安全令牌服务可以将该刷新令牌的生命周期链接到具有安全令牌服务的 user\xe2\x80\x99s 会话的生命周期。这样做会在会话过期时使刷新令牌失效。 ”
\n这是我在场景 3 中提出的观点,但他建议的解决方案是将 RT 链接到用户的会话。那么,我们再次使用会话 …
security authentication access-token openid-connect refresh-token
我想在浏览器中存储oauth刷新令牌.我想将它存储在那里的原因是应用程序可以刷新访问令牌并让用户不间断地继续他们的会话.我还想消除服务器上存储令牌的任何缓存的需要,从而使其成为有状态的.
我被告知在浏览器中存储刷新令牌是错误的,因为它不安全.
我认为没关系,因为:
我认为它应该没问题我错了吗?请解释原因!
security authentication web-applications oauth2 refresh-token
在使用 OAuth 2.0 JWT 刷新令牌实现时,我遇到了一个问题,即在 Web 浏览器客户端实现可靠的刷新策略确实很困难。多个选项卡可能会导致请求出现竞争情况。
RFC没有明确提到服务器端的刷新令牌仅对一个(第一个)请求有效,但我认为在使用刷新令牌时使它们无效是个好主意。
关于堆栈溢出已经有多种“解决方案”,但似乎没有一个是直接的。
一种解决方案是在请求中添加 Jitter,并通过本地存储同步请求。
如果我理解正确,您会在请求启动时将一个变量放入本地存储中,其他选项卡检查是否设置了该变量,然后不开始刷新?您知道这个的示例实现吗?也许在反应中?
refresh-token ×10
oauth-2.0 ×4
access-token ×3
asp.net-core ×2
jwt ×2
security ×2
.net-core ×1
angular ×1
angular8 ×1
c# ×1
oauth ×1
oauth2 ×1
polly ×1
rxjs ×1