Identity Server 4 API身份验证失败

时间:2018-11-15 15:46:31

标签: c# postgresql asp.net-core identityserver4

使用.Net Core 2.1和Identity Server 4

我有3个初创公司,分别是IS4,MVC App和API App。我可以正常登录MVC应用程序,并检索我的access_token。我尝试使用此令牌访问API,但无法授权该请求。

这是我的IS4 Startup.cs本地主机: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

2 个答案:

答案 0 :(得分:1)

我使用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
{
}

答案 1 :(得分:1)

通常,仅当 Client (即您的MVC应用)重定向到Identity Server时,您才能获得Invalid redirect_uri,以便用户可以进行身份​​验证,而不是在调用API时或由API本身,因此您应该从API的配置中删除挑战并将其留给UI。您的API还需要用于对Identity Server进行某些反向通道调用的秘密,因此请将您API的Startup.cs更改为:

        services.AddAuthorization();
        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddIdentityServerAuthentication(
                options =>
                {
                    options.Authority = "http://localhost:5000";
                    options.ApiName = "api1";
                    options.ApiSecret = "scopeSecret";
                    options.RequireHttpsMetadata = false;

                    // You will almost certainly want these at some point too,
                    // to prevent the API talking to the IS for every
                    // API call.  Adjust the duration as desired.
                    options.EnableCaching = true;
                    options.CacheDuration = TimeSpan.FromMinutes(10);
                });

您没有在API的Startup.cs中显示Configure()部分,但请确保它具有

.UseAuthentication();

呼叫之前

.AddMvc()

现在,您只需要用[Authorize]装饰受保护的API方法,并确保您通过用户的承载令牌传递对这些API方法的调用。