3

环境:

基本的令牌发行和验证在我们的环境中运行良好。我现在正在尝试启用静默刷新技术(如此所述)。在启用automaticSilentRenew和短之后AccessTokenLifetime,我可以看到在我的浏览器控制台中触发的静默请求,正如我所期望的那样。

我可以看到对 IS4 的 UserInfo 端点的两个后续调用(见下面的屏幕截图)。第一个是 CORS 预检OPTIONS请求。在我的自定义实现的断点处IProfileService.IsActiveAsync(),我可以看到这个请求成功地通过了身份验证(通过检查httpContext)。

在此处输入图像描述

public class ProfileService : IProfileService
{
    private readonly HttpContext _httpContext;

    public ProfileService(IHttpContextAccessor httpContextAccessor)
    {
        _httpContext = httpContextAccessor.HttpContext;
    }

    ...

    public async Task IsActiveAsync(IsActiveContext context)
    {
        var temp = _httpContext.User; // breakpoint here
        // call external API with _httpContext.User info to get isActive
    }
}

但是,对 UserInfo 端点的第二个请求 ( GET) 不会进行身份验证。我的断点IProfileService.IsActiveAsync()显示没有用户经过身份验证,因此我用于验证用户是否处于活动状态(调用另一个 API)的例程返回 false,它被转换为 401。我可以在失败的GET请求上看到此标头WWW-Authenticate: error="invalid_token"

我尝试指定一个IdentityTokenLifetime小于AccessTokenLifetimeper this的值,但没有成功。

以下是两个请求的日志:

Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 OPTIONS http://localhost:5000/connect/userinfo  
Microsoft.AspNetCore.Cors.Infrastructure.CorsService:Information: CORS policy execution successful.
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 8.5635ms 204 
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:5000/connect/userinfo  
Microsoft.AspNetCore.Cors.Infrastructure.CorsService:Information: CORS policy execution successful.
Microsoft.AspNetCore.Cors.Infrastructure.CorsService:Information: CORS policy execution successful.
IdentityServer4.Hosting.IdentityServerMiddleware:Information: Invoking IdentityServer endpoint: IdentityServer4.Endpoints.UserInfoEndpoint for /connect/userinfo
IdentityServer4.Validation.TokenValidator:Error: User marked as not active: f84db3aa-57b8-48e4-9b59-6deee3d288ad
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 94.7189ms 401

问题:

如何GET在静默刷新期间获取对 UserInfo 端点的请求以进行身份​​验证HttpContext

更新:

添加两个请求的所有标头和生成的浏览器 cookie 的屏幕截图,以调查 @Anders 的答案。

<code>OPTIONS</code> 对 UserInfo 端点的请求 <code>GET</code> 对 UserInfo 端点的请求 在浏览器中生成 cookie

4

2 回答 2

2

好吧,所以我想我知道发生了什么。您发出静默刷新令牌请求(从重定向到 oidc-silent-refresh.html 中我可以看到成功)并调用第一个 ProfileService 的“IsActiveAsync”(因为它需要通过配置文件服务生成令牌静默刷新)。您可以看到“HttpContext.User”,因为打开了一个 iframe,允许发送所有必要的 cookie。

用户信息预检请求甚至没有到达 ProfileService,正如您从日志中看到的那样,仅显示了一次“调用 IdentityServer 端点:IdentityServer4.Endpoints.UserInfoEndpoint for /connect/userinfo”。此外,UserInfoEndpoint 会阻止任何选项请求通过(您可以在此处的“ProcessAsync”方法的开头验证它是否为真)。

现在,当您发出实际的用户信息请求时,您正试图从 HttpContext 获取信息(通常使用来自 cookie 的信息填充),但由于请求中没有发送 cookie,因此无法访问。该请求是“getJson”方法(来自 oidc-client-js 库)中发出的,您可以看到请求中没有发送任何 cookie(如果请求中的“withCredentials”属性将设置为 true是)。

那么我们如何获取有关用户的必要信息呢?要获取此信息,我们可以参考传递给 ProfileService 的“IsActiveAsync”的“上下文”,其中包含由访问令牌声明填充的主体(此过程可以在此处的“ValidateAccessTokenAsync”方法中看到)。

于 2019-02-27T13:11:35.910 回答
2

请求/connect/userinfo由 IdentityServer 域/路径中的会话身份验证 cookie 进行身份验证。

我的猜测是 cookie 正确地包含在 OPTIONS 请求中,但没有包含在随后的 GET 请求中。您可以通过查看请求在浏览器开发工具中验证这一点。

如果我的猜测是正确的,原因可能是相同的站点属性。默认情况下,ASP.NET Core(IdentityServer4 使用)中的所有身份验证 cookie 都具有相同的站点属性,以防止跨站点请求伪造攻击。

根据信息,我可以从 AJAX Get 请求中找到一个带有 samesite=lax 的 cookie。但是,如果 OPTIONS 请求中允许,我找不到任何东西。您可以验证(使用浏览器开发工具)在从第一个请求到/connect/authorize.

设置本身位于Cookie调用 cookie 选项的部分中AddCookie()。MS 文档说它默认为lax.

另一方面,Idsrv4 存储库中有一个GitHub 线程,表示他们已将 Idsrv4 会话 cookie 的默认设置更改为“无”。

我显然在这里猜测了一下,但验证我的假设应该相当简单,如上所述。

于 2019-02-20T16:33:22.847 回答