首页 > 解决方案 > Identity Server 4 API 身份验证失败

问题描述

使用 .Net Core 2.1 和 Identity Server 4

我有 3 家初创公司,分别是 IS4、MVC App 和 API App。我能够很好地登录到我的 MVC 应用程序,并检索我的 access_token。我尝试使用此令牌访问 API,但无法授权该请求。

这是我的 IS4 Startup.cs localhost:5000

services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<IdentityContext>()
            .AddDefaultTokenProviders();

        services.AddMvc();

        services.Configure<IISOptions>(iis =>
        {
            iis.AuthenticationDisplayName = "Windows";
            iis.AutomaticAuthentication = false;
        });

        services.AddIdentityServer()
            .AddAspNetIdentity<ApplicationUser>()
            .AddConfigurationStore(configDb =>
            {
                configDb.ConfigureDbContext = db => db.UseNpgsql(Configuration.GetConnectionString("IdentityServer4ConfigurationContext"),
                    sql => sql.MigrationsAssembly(typeof(IdentityServer4Startup).GetTypeInfo().Assembly.GetName().Name));
            })
            .AddOperationalStore(operationDb =>
            {
                operationDb.ConfigureDbContext = db => db.UseNpgsql(Configuration.GetConnectionString("IdentityServer4PersistedGrantContext"),
                     sql => sql.MigrationsAssembly(typeof(IdentityServer4Startup).GetTypeInfo().Assembly.GetName().Name));
            })
            .AddDeveloperSigningCredential();

我的 MVC Startup.cs 本地主机:61000

services.AddMvc();

        services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<IdentityContext>()
            .AddDefaultTokenProviders();

        services.AddAuthentication(options =>
            {
                options.DefaultScheme = "Cookies";
                options.DefaultChallengeScheme = "oidc";
            })
            .AddCookie("Cookies")
            .AddOpenIdConnect("oidc", options =>
                {
                    options.SignInScheme = "Cookies";
                    options.Authority = "http://localhost:5000";
                    options.RequireHttpsMetadata = false;
                    options.ClientId = "mvc";
                    options.ClientSecret = "secret";
                    options.ResponseType = "code id_token";
                    options.SaveTokens = true;
                    options.GetClaimsFromUserInfoEndpoint = true;
                    options.Scope.Add("api1");
                    options.Scope.Add("offline_access");
                    options.Scope.Add("openid");
                    options.Scope.Add("email");
                });

还有我的 API Startup.cs localhost:62000

services.AddMvc();


        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = "oidc";
        })
            .AddIdentityServerAuthentication("oidc", options =>
            {
                options.Authority = "http://localhost:5000";
                options.RequireHttpsMetadata = false;
                options.ApiName = "api1";
            });

我的客户信息是

new Client {
                ClientId = "mvc",
                ClientName = "Example Mvc",
                AllowedGrantTypes = GrantTypes.Hybrid,
                AllowedScopes = new List<string>
                {
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile,
                    IdentityServerConstants.StandardScopes.Email,
                    "role",
                    "api1"
                },
                RedirectUris = new List<string> {"http://localhost:61000/signin-oidc"},
                PostLogoutRedirectUris = new List<string> { "http://localhost:61000/signout-callback-oidc" }
            }

和 API 资源

new ApiResource {
                Name = "api1",
                DisplayName = "Custom API",
                Description = "Custom API Access",
                UserClaims = new List<string> {"role"},
                ApiSecrets = new List<Secret> {new Secret("scopeSecret".Sha256())},
                Scopes = new List<Scope> {
                    new Scope("api1"),
                }
            }

每当我以客户端身份登录时尝试调用 API 时,我都无法访问它。它要么给出错误

[10:40:11 ERR] Invalid redirect_uri: http://localhost:62000/signin-oidc
{
  "ClientId": "mvc",
  "ClientName": "MVC Client",
  "AllowedRedirectUris": [
    "http://localhost:61000/signin-oidc"
  ],
  "SubjectId": "anonymous",
  "RequestedScopes": "",
  "Raw": {
    "client_id": "mvc",
    "redirect_uri": "http://localhost:62000/signin-oidc",
    "response_type": "code id_token",
    "scope": "openid profile api1 offline_access email",
    "response_mode": "form_post",
    "nonce": "636778932114224044.N2M1YzZhMjktMThjMS00ZGEyLWI1OGQtZjM1YmZiMzViNDVkNDQ2NDhjZWMtNzk4Mi00NTc2LWI2YzctNjAwMzkwNjI5NGE5",
    "state": "CfDJ8EzT-5PsjT5Htj2FYGOkFvxTH4w-8q3uXGtc1wXYyvWMHyarfbV0cQz8cFh4ESIW33n4pwtIEmLhrTpX-0Y0-_HS24cWs05nR3npx1ZIAJsYr9hIqB9hj9Ic_QYkU2Z_bcjjnaynqfbF5KIyyQhYGNlDxDfknwZUTXpPzTFEhLTcnam7O-b-xV9a3e9iWARoFZRBLjGV5Hs5i-8jS5EGM9DpqwcvrUjSUlRVDP-TzBBhYPhswn2hKsjkhL26_Gp9lluoKNLOvUVM-yq1zHbbI9uTcZzS_2GtbQoPuuGTmCuOoV-c-K2IztzXP88W-osYaY9wQP2qi8aXD951hrAhYbo",
    "x-client-SKU": "ID_NETSTANDARD1_4",
    "x-client-ver": "5.2.0.0"
  }
}

我认为我不需要注册 redirect_uri。但是我还是尝试了,当我做同样的请求时,它只会返回登录屏幕。因为它无法验证我的请求。

这是我从 MVC 发送到 API 的 HttpClient 请求

var apiUrl = "http://localhost:62000/test/api";
        var authenticate = await HttpContext.AuthenticateAsync("Cookies");
        var accessToken = authenticate.Ticket.Properties.GetTokenValue("access_token");
        var client = new HttpClient();
        client.SetBearerToken(accessToken);
        var response = await client.GetAsync(apiUrl);
        return Json(response.Content.ReadAsStringAsync());

从所有示例和文档中,我看不出为什么这不起作用。任何帮助,将不胜感激。

这是我尝试使用不记名令牌调用 API 时 IS4 的输出。

[12:38:58 INF] Request starting HTTP/1.1 GET http://localhost:5000/connect/authorize?client_id=mvc&redirect_uri=http%3A%2F%2Flocalhost%3A62000%2Fsignin-oidc&response_type=code%20id_token&scope=openid%20profile%20api1%20offline_access%20email&response_mode=form_post&nonce=636779003387253889.MThjYjQ5MzItOTY3NS00NmM1LWJhZDItMzkxMzYyMWQzZTUwZThjNThmMjUtMmQyZC00M2YyLTk3OTktN2E3OTc1ZDcyNmM0&state=CfDJ8EzT-5PsjT5Htj2FYGOkFvzm1YFOhTLHlbLS3LpJd_xUBgDz8hWjGkXxSzfnWKqoVU5d4L7ESHCSDGxqmxqnMh1-j-IUGBLzt5uEYFi2M4QV6WmGN1Lv5bMkUDRbrE9pdCNc7vLDUDZY1OWlp4HfQ0vEMr8-OfUH4Q00fOn1v9zpcE6QlHI5Aye9xiFOshHRyMCNwEEcVrLz4Y06Hsa-40OKom3xb8sie09JtiSMZJL9WyKgKYGRgqUIpD6wqryBafzMl_t1tvegYWESq59TafnIpvrFd3ifdOzJx6cXul4ZCcFv0wfvsqpUgCF7t7xyMSwtheDSiE2AySkbnrpr_Dg&x-client-SKU=ID_NETSTANDARD1_4&x-client-ver=5.2.0.0
[12:38:58 INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.AuthorizeEndpoint for /connect/authorize
[12:38:58 INF] ValidatedAuthorizeRequest
{
  "ClientId": "mvc",
  "ClientName": "MVC Client",
  "RedirectUri": "http://localhost:62000/signin-oidc",
  "AllowedRedirectUris": [
    "http://localhost:62000/signin-oidc",
    "http://localhost:61000/signin-oidc"
  ],
  "SubjectId": "anonymous",
  "ResponseType": "code id_token",
  "ResponseMode": "form_post",
  "GrantType": "hybrid",
  "RequestedScopes": "openid profile api1 offline_access email",
  "State": "CfDJ8EzT-5PsjT5Htj2FYGOkFvzm1YFOhTLHlbLS3LpJd_xUBgDz8hWjGkXxSzfnWKqoVU5d4L7ESHCSDGxqmxqnMh1-j-IUGBLzt5uEYFi2M4QV6WmGN1Lv5bMkUDRbrE9pdCNc7vLDUDZY1OWlp4HfQ0vEMr8-OfUH4Q00fOn1v9zpcE6QlHI5Aye9xiFOshHRyMCNwEEcVrLz4Y06Hsa-40OKom3xb8sie09JtiSMZJL9WyKgKYGRgqUIpD6wqryBafzMl_t1tvegYWESq59TafnIpvrFd3ifdOzJx6cXul4ZCcFv0wfvsqpUgCF7t7xyMSwtheDSiE2AySkbnrpr_Dg",
  "Nonce": "636779003387253889.MThjYjQ5MzItOTY3NS00NmM1LWJhZDItMzkxMzYyMWQzZTUwZThjNThmMjUtMmQyZC00M2YyLTk3OTktN2E3OTc1ZDcyNmM0",
  "Raw": {
    "client_id": "mvc",
    "redirect_uri": "http://localhost:62000/signin-oidc",
    "response_type": "code id_token",
    "scope": "openid profile api1 offline_access email",
    "response_mode": "form_post",
    "nonce": "636779003387253889.MThjYjQ5MzItOTY3NS00NmM1LWJhZDItMzkxMzYyMWQzZTUwZThjNThmMjUtMmQyZC00M2YyLTk3OTktN2E3OTc1ZDcyNmM0",
    "state": "CfDJ8EzT-5PsjT5Htj2FYGOkFvzm1YFOhTLHlbLS3LpJd_xUBgDz8hWjGkXxSzfnWKqoVU5d4L7ESHCSDGxqmxqnMh1-j-IUGBLzt5uEYFi2M4QV6WmGN1Lv5bMkUDRbrE9pdCNc7vLDUDZY1OWlp4HfQ0vEMr8-OfUH4Q00fOn1v9zpcE6QlHI5Aye9xiFOshHRyMCNwEEcVrLz4Y06Hsa-40OKom3xb8sie09JtiSMZJL9WyKgKYGRgqUIpD6wqryBafzMl_t1tvegYWESq59TafnIpvrFd3ifdOzJx6cXul4ZCcFv0wfvsqpUgCF7t7xyMSwtheDSiE2AySkbnrpr_Dg",
    "x-client-SKU": "ID_NETSTANDARD1_4",
    "x-client-ver": "5.2.0.0"
  }
}
[12:38:58 INF] Showing login: User is not authenticated
[12:38:58 INF] Request finished in 138.5606ms 302
[12:38:58 INF] Request starting HTTP/1.1 GET http://localhost:5000/account/login?returnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3Dmvc%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%253A62000%252Fsignin-oidc%26response_type%3Dcode%2520id_token%26scope%3Dopenid%2520profile%2520api1%2520offline_access%2520email%26response_mode%3Dform_post%26nonce%3D636779003387253889.MThjYjQ5MzItOTY3NS00NmM1LWJhZDItMzkxMzYyMWQzZTUwZThjNThmMjUtMmQyZC00M2YyLTk3OTktN2E3OTc1ZDcyNmM0%26state%3DCfDJ8EzT-5PsjT5Htj2FYGOkFvzm1YFOhTLHlbLS3LpJd_xUBgDz8hWjGkXxSzfnWKqoVU5d4L7ESHCSDGxqmxqnMh1-j-IUGBLzt5uEYFi2M4QV6WmGN1Lv5bMkUDRbrE9pdCNc7vLDUDZY1OWlp4HfQ0vEMr8-OfUH4Q00fOn1v9zpcE6QlHI5Aye9xiFOshHRyMCNwEEcVrLz4Y06Hsa-40OKom3xb8sie09JtiSMZJL9WyKgKYGRgqUIpD6wqryBafzMl_t1tvegYWESq59TafnIpvrFd3ifdOzJx6cXul4ZCcFv0wfvsqpUgCF7t7xyMSwtheDSiE2AySkbnrpr_Dg%26x-client-SKU%3DID_NETSTANDARD1_4%26x-client-ver%3D5.2.0.0
[12:38:58 INF] Route matched with {action = "Login", controller = "Account"}. Executing action ASC.ADEX.Runtime.Controllers.AccountController.Login (ASC.ADEX.Runtime)
[12:38:58 INF] Executing action method ASC.ADEX.Runtime.Controllers.AccountController.Login (ASC.ADEX.Runtime) with arguments (["/connect/authorize/callback?client_id=mvc&redirect_uri=http%3A%2F%2Flocalhost%3A62000%2Fsignin-oidc&response_type=code%20id_token&scope=openid%20profile%20api1%20offline_access%20email&response_mode=form_post&nonce=636779003387253889.MThjYjQ5MzItOTY3NS00NmM1LWJhZDItMzkxMzYyMWQzZTUwZThjNThmMjUtMmQyZC00M2YyLTk3OTktN2E3OTc1ZDcyNmM0&state=CfDJ8EzT-5PsjT5Htj2FYGOkFvzm1YFOhTLHlbLS3LpJd_xUBgDz8hWjGkXxSzfnWKqoVU5d4L7ESHCSDGxqmxqnMh1-j-IUGBLzt5uEYFi2M4QV6WmGN1Lv5bMkUDRbrE9pdCNc7vLDUDZY1OWlp4HfQ0vEMr8-OfUH4Q00fOn1v9zpcE6QlHI5Aye9xiFOshHRyMCNwEEcVrLz4Y06Hsa-40OKom3xb8sie09JtiSMZJL9WyKgKYGRgqUIpD6wqryBafzMl_t1tvegYWESq59TafnIpvrFd3ifdOzJx6cXul4ZCcFv0wfvsqpUgCF7t7xyMSwtheDSiE2AySkbnrpr_Dg&x-client-SKU=ID_NETSTANDARD1_4&x-client-ver=5.2.0.0"]) - Validation state: Valid
[12:38:58 INF] Executed action method ASC.ADEX.Runtime.Controllers.AccountController.Login (ASC.ADEX.Runtime), returned result Microsoft.AspNetCore.Mvc.ViewResult in 41.3848ms.
[12:38:58 INF] Executing ViewResult, running view Login.
[12:38:58 INF] Executed ViewResult - view Login executed in 1.8018ms.
[12:38:58 INF] Executed action ASC.ADEX.Runtime.Controllers.AccountController.Login (ASC.ADEX.Runtime) in 78.939ms
[12:38:58 INF] Request finished in 83.6512ms 200 text/html; charset=utf-8

标签: c#postgresqlasp.net-coreidentityserver4

解决方案


AddJwtBearer我使用如下所示设置我的 API 身份验证。我看到你使用AddIdentityServerAuthentication. 可能是这个原因?

services.AddJwtBearer(o =>
               {
                   o.Authority = "<id-server>";
                   o.Audience = "<api-audience>";
                   o.RequireHttpsMetadata = true;
               });

并且 API 控制器具有AuthenticationSchemes如下所示的指定:

[Route("api/rates")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class RatesController : Controller
{
}

推荐阅读