【问题标题】:Unable to call Web API Secured with IdentityServer with valid Access token无法使用有效的访问令牌调用使用 IdentityServer 保护的 Web API
【发布时间】:2021-10-02 15:33:02
【问题描述】:

我申请调用使用 IdentityServer 保护的 Web API 的代码如下。

var accessToken = await HttpContext.GetTokenAsync("access_token");

var data = new List<WeatherForecast>();
using (var client = new HttpClient())
{
    client.SetBearerToken(accessToken);
    var result = await client.GetAsync("https://localhost:6001/WeatherForecast");
    if (result.IsSuccessStatusCode)
    {
        var model = await result.Content.ReadAsStringAsync();
        data = JsonConvert.DeserializeObject<List<WeatherForecast>>(model);
    }
    else
    {
        throw new Exception("Failed to get Data from API");
    }
}

此代码失败并在日志中显示用户未通过身份验证。此代码实际上是在用户通过 IdentityServer 进行身份验证后执行的。所以代码行:

var accessToken = await HttpContext.GetTokenAsync("access_token");

正在向我提供 accessToken。但是Web API没有被调用,为什么?? 我在 Postman 上测试了使用相同的访问令牌调用 web api,它能够调用 web api。

所以我认为我的 OpenID Connect 设置有问题。我使用的 OpenID 连接设置是:

services.AddAuthentication(options =>
{
    options.DefaultScheme = "Cookies";
    options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddJwtBearer(options =>
{
    options.Authority = "https://localhost:5001";
    options.Audience = "Bond";
})
.AddOpenIdConnect("oidc", options =>
{
    options.Authority = "https://localhost:5001";
    options.ClientId = "xena";
    options.ResponseType = "code";
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Scope.Add("fullaccess");
    options.SaveTokens = true;
}); 

我在 OpenID Connect 中尝试了许多设置,但似乎没有任何效果。我正在向您展示工作和问题。

这里可以看到认证部分:

在这里你可以看到问题。

身份验证后,我访问了调用 Web API 的 URL。我用这一行得到了令牌:

var accessToken = await HttpContext.GetTokenAsync("access_token")

但是当我使用令牌进行 api 调用时,我在控制台日志中得到 Showing login: User is not authenticated。见下图:

问题是用户已经通过身份验证,否则我无法获取访问令牌。

我对这个问题进行了深入研究,并在 api 调用代码上设置了断点。我发现对api的调用被重定向到这个url:

帐户/登录?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3Dzorro%26redirect_uri%3Dhttps%253A%252F%252Flocalhost%253A6001%252Fsignin-oidc%26response_type%3Dcode%26scope%3Dopenid%2520profile%2520fullaccess%26_code 3Dwd31qWo2SpjTuncroM6qkWSvhFg-rKDVcicPOrp3-6E%26code_challenge_method%3DS256%26response_mode%3Dform_post%26nonce%3D637629779176334831.MTUwZjRlODgtZmJhYi00Y2I3LWFlYmQtNGYzNWViZmM1NWNjOWI1NDg4YTItMGI5Yy00MTk3LTk0OTQtMDIxMWI5YTg1NGIw%26state%3DCfDJ8Cuukidn-CJOlLfkzyfYd36FVs9F-zMJ_0v67GE7qgtpnN8Zd10Gnkwbhm2VgMnLCt3pihVGA3jhXFF2rYrBaj8z-j1muaq8BgUcM4Ay3yjR1i2D4gm3JrXtAUGQAulW8CqC3XWbXvS8b3U8srEXVFP2qGW91jejBVJ9YCc1v-3gTYaRmRuf45DM3Kx1bDML7Yz7s1wKyXjvSE5aS5Bq78az3gXpqOC7GIciNJ2UELFtDSJF14GEYwtHM53Ehv3p_XvU86RCYwzH9jU9CzoCeIx6ScKbRi0hTp9nybNgj3PlOvzMZWg4taxiOK3yKxroFEK_GGAY9oK_ZzsRodVcoJp-2BGA_yceJbU0GeoPic111cjUC4_ml1r_gBiq-o7dDBWRRJsFyScGVRNDj8vyL7k%26X-客户SKU%3DID_NETSTANDARD2_0%26X-客户-VER% 3D6.7.1.0

很明显,该应用程序得出的结论是我未通过身份验证,因此我无法进行 api 调用。但是我已经通过了身份验证,那我该如何解决呢?

【问题讨论】:

  • 您的 API 获得了什么响应代码?

标签: asp.net-core jwt identityserver4


【解决方案1】:

我的建议是把WEB API放在自己的服务上,遵循关注点分离的原则。当您将 IdentityServer 与 Web 应用程序和 API 混合使用时,您就是在自找麻烦。

【讨论】:

  • 同意。这是避免麻烦的最佳方法,因为设置太多。
【解决方案2】:

据我所知,HttpContext.GetTokenAsync 方法会根据认证方案获取令牌。

我建议您可以尝试指定身份验证方案并重试。如下:

        var re = HttpContext.GetTokenAsync("oidc", "access_token");

【讨论】:

  • 我试过你的代码,但同样的问题。我正在做官方文档中显示的事情 - identityserver4.readthedocs.io/en/latest/quickstarts/…
  • 您能否分享一下您从 Web api 收到的详细 500 错误消息?您的身份服务器似乎有问题。
  • 我检查了控制台日志,发现当 API 调用发出时,它会收到“用户未通过身份验证”。所以 web api 给出了 500 错误。问题是用户已经通过身份验证,因为当我访问受保护端点的 url 时,我被重定向到登录页面,然后我登录,之后我可以访问这个受保护的端点。但是当我尝试调用 web api 时,我收到“用户未通过身份验证”消息,为什么???
  • 我已经用截图更新了问题。
【解决方案3】:

我通过将 Web API 中的 [Authorize] 属性更改为:

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

然后还在客户端项目的 Starup.cs 上添加授权(其中包含 Web API)。

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme);
// other authorization of oidc which is given in the question itself.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-20
    • 1970-01-01
    • 2013-03-27
    • 1970-01-01
    • 2021-03-15
    • 1970-01-01
    • 2019-04-25
    • 1970-01-01
    相关资源
    最近更新 更多