IdentityServer4 - 如何从另一个 ApiResource 调用一个 ApiResource
Posted
技术标签:
【中文标题】IdentityServer4 - 如何从另一个 ApiResource 调用一个 ApiResource【英文标题】:IdentityServer4 - How to Call One ApiResource from Another ApiResource 【发布时间】:2019-01-07 07:23:02 【问题描述】:我有一个 spa 应用程序设置,它使用带有 OpenId Connect 的混合授权流程受 IdentityServer4 保护。
这个 spa 应用程序能够调用多个 ApiResources,作为登录用户,通过请求 access_token
HttpContextAccessor.HttpContext.GetTokenAsync("access_token")
这对于多个 ApiResources 非常有用。例如,我的 Spa 应用程序可以毫无问题地调用 ApiResource1、ApiResource2 和 ApiResource3。
但是,我添加了一个新的 ApiResource(即 ApiResource4),我需要能够从 ApiResource1 调用它。但是,当我尝试调用
HttpContextAccessor.HttpContext.GetTokenAsync("access_token")
来自 ApiResource1,access_token 为 null,因此调用失败。
如何使用已登录的用户令牌从 ApiResource1 调用 ApiResource2?
也许更好的提问方式是,如何从 ApiResource1 获取登录用户 access_token?
我的 SPA 应用程序是这样设置的:
services.AddAuthentication(options =>
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
)
.AddCookie("Cookies", options =>
options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
)
.AddOpenIdConnect("oidc", options =>
options.SignInScheme = "Cookies";
options.Authority = Configuration.GetSection("IdentityServerOptions").GetValue<string>("BaseUrl");
options.RequireHttpsMetadata = true;
options.ClientId = Configuration.GetSection("IdentityServerOptions").GetValue<string>("ClientId");
options.ClientSecret = Configuration.GetSection("IdentityServerOptions").GetValue<string>("ClientSecret");
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("ApiResource1");
options.Scope.Add("ApiResource2");
options.Scope.Add("ApiResource3");
options.Scope.Add("ApiResource4");
options.ResponseType = "code id_token";
);
我的 ApiResources 设置如下:
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
options.Authority = Configuration.GetSection("IdentityServer").GetValue<string>("BaseUrl");
options.RequireHttpsMetadata = true;
options.ApiName = _AppName;
);
【问题讨论】:
查看扩展授权委托docs.identityserver.io/en/release/topics/…。这听起来像你所追求的。另一种选择是转发当前用户access_token
,方法是从请求授权标头中提取它。
这听起来正是我想要的。我明天将尝试实施它并确保它有效。谢谢!
@Brad 如何获得您链接的文档中提到的“userToken”?我已经尝试了以下并且全部返回 null: string userToken = _contextAccessor.HttpContext != null ?等待 _contextAccessor.HttpContext?.GetTokenAsync("id_token") ??等待 _contextAccessor.HttpContext?.GetTokenAsync("token") ??等待_contextAccessor.HttpContext?.GetTokenAsync("access_token")
GetTokenAsync()
仅适用于 cookie 身份验证,不适用于使用 JWT 的 API。令牌位于 Authorization
标头中。它应该在_context.HttpContext.Request.Headers
。
谢谢布拉德。我没有意识到 GetTokenAsync 仅适用于 cookie 身份验证。我最终确实从 Auth 标头中手动检索了令牌,并且结合您的第一条评论解决了这个问题。谢谢!如果您提交答案,我会接受。
【参考方案1】:
HttpContext.GetTokenAsync("access_token")
扩展方法仅适用于 Cookie 身份验证。它将尝试提取存储在 cookie 中的令牌。当您拥有使用 JWT 身份验证的 API 时,此功能不可用。
你有两个选择。
使用扩展授权委托,如 Identity Server 文档 http://docs.identityserver.io/en/release/topics/extension_grants.html#example-simple-delegation-using-an-extension-grant 中所述。此选项实施起来更复杂,但它提供了更高的安全性。
从 Authorization
标头中提取并转发 JWT。这个选项就像从 Request 中获取 header 并在发出 API 请求之前将其设置在 HttpClient
的 header 中一样简单。
【讨论】:
以上是关于IdentityServer4 - 如何从另一个 ApiResource 调用一个 ApiResource的主要内容,如果未能解决你的问题,请参考以下文章
如何将 IdentityServer4 设置为外部身份提供者
如何测试我的令牌是不是使用 IdentityServer4 刷新?
IdentityServer4 如何在授权代码流中存储和更新令牌