静默刷新将在OPTIONS预检前进行身份验证,但不会在GET到UserInfo端点上进行身份验证

时间:2019-02-19 21:58:30

标签: c# identityserver4 identityserver3 oidc-client-js

环境:

基本令牌发行和验证在我们的环境中运行良好。我现在正在尝试启用无提示刷新技术(如documented here)。启用automaticSilentRenew和简短的AccessTokenLifetime之后,我可以在浏览器控制台中看到静音请求,如我所愿。

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

enter image description here

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。我可以在失败的{{1 }}请求GET

我尝试指定的WWW-Authenticate: error="invalid_token"小于每个thisIdentityTokenLifetime,但没有成功。

这是两个请求的日志:

AccessTokenLifetime

问题:

如何在无提示刷新期间向UserInfo端点发送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的身份?

更新

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

<code>OPTIONS</code> request to UserInfo endpoint <code>GET</code> request to UserInfo endpoint resulting cookies in browser

2 个答案:

答案 0 :(得分:2)

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

我的猜测是该cookie已正确包含在OPTIONS请求中,但未包含在后续的GET请求中。您可以通过查看请求在浏览器开发工具中进行验证。

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

根据information I can find,AJAX Get请求中不允许使用带有samesite = lax的cookie。但是,如果OPTIONS请求中允许,则找不到任何内容。您可以验证(使用浏览器开发工具)从第一个请求到/connect/authorize的响应中,cookie头中是否存在相同的网站设置。

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

另一方面,Idsrv4存储库中有一个GitHub thread,表示他们已将Idsrv4会话cookie的默认值更改为“ none”。

我显然在这里有点猜测,但是验证我上面概述的假设应该相当简单。

答案 1 :(得分:2)

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

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

现在,当您发出实际的用户信息请求时,您正在尝试从HttpContext获取信息(通常使用cookie中的信息填充该信息),但是由于请求中未发送任何cookie,因此无法访问。该请求是在{get3son}方法(来自oidc-client-js库)中通过here发出的,您可以看到请求中未发送任何cookie(onCredentials属性将在(如果有的话)。

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