您如何将JWT传递给服务?

时间:2019-03-21 13:41:26

标签: c# asp.net-core oauth identityserver4 openid-connect

在使用code authorization flow的演示“客户端”网站中,当用户成功从我自己的本地身份提供者(IdentityServer4)登录时,我收到一个JWT声明用户的身份。它将存储为如下所示的Cookie(用...缩写):

  

ai_user = kFgLY | 2018-12-11T15:40:11.940Z; AMCV_700CFDC5570CBFE67F000101%40AdobeOrg = 2121618341%7CMCIDTS%7 ... ywuxL1PHcA

客户端站点的配置如下:

services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = "cookie";
        options.DefaultSignInScheme = "cookie";
        options.DefaultChallengeScheme = "oidc";
    })
    .AddCookie("cookie")
    .AddOpenIdConnect("oidc", options =>
    {
        options.Authority = "https://localhost:5005";
        options.RequireHttpsMetadata = false;
        options.RemoteAuthenticationTimeout = TimeSpan.FromMinutes(15);
        options.ClientId = "test_pkce_client";
        options.ClientSecret = "secret";
        options.ResponseType = "code";
        options.ResponseMode = "form_post";
        options.CallbackPath = "/signin-test";
        options.GetClaimsFromUserInfoEndpoint = true;
        options.Events.OnRedirectToIdentityProvider = context => HandleRedirectToIDP(context);

        options.Events.OnAuthorizationCodeReceived = context => HandleCodeReceived(context);

    });

但是,当用户进行身份验证时,我想捕获该JWT。当我向下游Web服务发出请求时,我希望传递该JWT,以便它们可以(独立)验证用户的身份验证,还可以独立查询该用户是否应有权执行给定的API操作。我还希望我的Web服务在必要时接受client credentials grant进行机器对机器的身份验证。

使用identityserver4和.NET Core,我该如何完成?如何使我的Web服务中的[Authorize]批注区分这两个流并妥善处理?在我的演示Web服务中,我的客户端凭据授予工作正常:

.AddIdentityServerAuthentication("token", options =>
                {
                    options.Authority = "https://localhost:5005";
                    options.RequireHttpsMetadata = false;

                    options.ApiName = "SomeAPI";
                    options.ApiSecret = "secret";
                });

1)在我的服务中,如何添加从客户端读取JWT的第二种身份验证方法?就像启动中的 AddJwtBearer()一样简单吗? 2)在我的“客户端”中,我如何捕获并发送(以保留)授权用户的JWT到其他服务?

我认为这是行不通的,只是为了展示我的意思,这是从我在客户端上尝试过的[授权]控制器中的“客户端”网站上进行的尝试

[Authorize]
public IActionResult SecurePage()
{
            var client = new System.Net.Http.HttpClient();
            client.BaseAddress = new System.Uri("https://localhost:3721/");
            client.DefaultRequestHeaders.Add("Cookie", Request.Headers["Cookie"].First());

            var apiTask = client.GetAsync("Test");
            apiTask.Wait();
            string response = apiTask.Result.Content.ReadAsStringAsync().Result;

这显然是我提供的401。

更新

在得到d_f的帮助之后,我将上面的伪劣想法翻译为:

[Authorize]
public async Task<IActionResult> SecurePage()
{
string accessToken = await HttpContext.GetTokenAsync("cookie", "access_token");
string idToken = await HttpContext.GetTokenAsync("cookie", "id_token");

var client = new System.Net.Http.HttpClient();
client.BaseAddress = new System.Uri("https://localhost:3721/");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var apiTask = client.GetAsync("Test");
apiTask.Wait();

string response = apiTask.Result.Content.ReadAsStringAsync().Result;

诀窍是将用户的accessToken视为客户端凭据授予令牌。另外,请确保客户端启动中的AddOpenIdConnect为 options.SaveTokens = true; ,并且确保您的ResponseType为 options.ResponseType =“ code id_token”; ,这将允许使用API具有 .AddIdentityServerAuthentication(“ token”,options => 来读取您的请求并根据IDP对其进行身份验证。

1 个答案:

答案 0 :(得分:1)

看起来,您搞砸了不同的事情。在.AddIdentityServerAuthentication()上的 API AddJwtBearer() is just a decorator中,因此对于您的情况(通过外部调用受[Authorize]保护的方法),它已经可以工作了。我猜您总是使用JWT并添加了一个秘密,以便能够直接从API请求新令牌,而不是用于参考令牌验证?在这种情况下,您需要参与TokenClient

在您的客户中,您只需要在SetBearerToken(apiAccessToken)实例上调用HttpClient,而不是发送Cookie,但是您必须先请求并保留该令牌。 This fresh article包含指向working example

的链接