c# - .NET 4.5 中带有资源 API 的 IdentityServer4 (OWIN)

标签 c# asp.net .net identityserver4

我已经通读了大量示例以及 IdentityServer 4 文档,但我似乎仍然遗漏了一些东西。

基本上,我让 IdentityServer4 工作到可以向我证明 AccessTokenRefreshToken 的程度。然后我尝试使用那个 AccessToken 并向我的 WebAPI2(.NET 4.5,OWIN)发送一个 HTTP 请求,它使用 IdentityServer3.AccessTokenValidation 应该兼容基于示例/在 https://github.com/IdentityServer/CrossVersionIntegrationTests/ 进行测试

当我尝试访问需要授权的资源时,WebAPI2 在 HTTP 400 给我,我真的不知道为什么会这样。

代码如下:

QuickstartIdentityServer Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    var connectionString = @"server=(localdb)\mssqllocaldb;database=IdentityServer4.Quickstart.EntityFramework;trusted_connection=yes";
    var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

    // configure identity server with in-memory stores, keys, clients and scopes
    var identityServerConfig = services.AddIdentityServer()
        .AddConfigurationStore(builder =>
            builder.UseSqlServer(connectionString, options =>
                options.MigrationsAssembly(migrationsAssembly)))
        .AddOperationalStore(builder =>
            builder.UseSqlServer(connectionString, options =>
                options.MigrationsAssembly(migrationsAssembly)))
        .AddSigningCredential(new X509Certificate2(Path.Combine(_environment.ContentRootPath, "certs", "IdentityServer4Auth.pfx"), "test"));

    identityServerConfig.Services.AddTransient<IResourceOwnerPasswordValidator, ActiveDirectoryPasswordValidator>();
    identityServerConfig.Services.AddTransient<IProfileService, CustomProfileService>();
    services.AddMvc();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    InitializeDatabase(app);
    app.UseDeveloperExceptionPage();
    app.UseIdentityServer();
    app.UseMvcWithDefaultRoute();
}

QuickstartIdentityServer Config.cs(我用来为我的数据库做种)

public class Config
{
    // scopes define the API resources in your system
    public static IEnumerable<ApiResource> GetApiResources()
    {
        return new List<ApiResource>
        {
            new ApiResource("api1", "My API")
            {
                Scopes = new [] { new Scope("api1"), new Scope("offline_access") },
                UserClaims = { ClaimTypes.Role, "user" }
            }
        };
    }

    // client want to access resources (aka scopes)
    public static IEnumerable<Client> GetClients()
    {
        // client credentials client
        return new List<Client>
        {
            new Client
            {
                ClientId = "client",
                AllowedGrantTypes = GrantTypes.ClientCredentials,

                ClientSecrets =
                {
                    new Secret("secret".Sha256())
                },
                AllowedScopes = { "api1" }
            },

            // resource owner password grant client
            new Client
            {
                ClientId = "ro.client",
                AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,

                ClientSecrets = 
                {
                    new Secret("secret".Sha256())
                },
                UpdateAccessTokenClaimsOnRefresh = true,
                AllowedScopes = { "api1", "offline_access" },
                AbsoluteRefreshTokenLifetime = 86400,
                AllowOfflineAccess = true,
                RefreshTokenUsage = TokenUsage.ReUse
            }
        };
    }
}

WebAPI2 Startup.cs

public void Configuration(IAppBuilder app)
{
    HttpConfiguration config = new HttpConfiguration();
    config.MapHttpAttributeRoutes();
    app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
    {
        Authority = "http://localhost:44340/",
        RequiredScopes = new[] { "api1" },
        DelayLoadMetadata = true
    });

    WebApiConfig.Register(config);
    app.UseWebApi(config);
}

WebAPI2 测试 Controller

public class TestController : ApiController
{
    // GET: api/Test
    [Authorize]
    public async Task<IHttpActionResult> Get()
    {
        return Json(new { Value1 = "value1", Value2 = "value2" });
    }
}

ConsoleApplication 来测试这个:

private static async Task MainAsync()
{
    // discover endpoints from metadata
    //DiscoveryClient client = new DiscoveryClient("https://dev-ea-authapi");
    DiscoveryClient client = new DiscoveryClient("http://localhost:44340/");
    client.Policy.RequireHttps = false;
    var disco = await client.GetAsync();

    // request token
    var tokenClient = new TokenClient(disco.TokenEndpoint, "ro.client", "secret");
    var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync("likosto", "CrM75fnza%");

    if (tokenResponse.IsError)
    {
        Console.WriteLine(tokenResponse.Error);
        return;
    }



    Console.WriteLine(tokenResponse.Json);
    Console.WriteLine("\n\n");

    //var newTokenResponse = await tokenClient.RequestRefreshTokenAsync(tokenResponse.RefreshToken);

    // call api
    var httpClient = new HttpClient();
    httpClient.SetBearerToken(tokenResponse.AccessToken);

    var response = await httpClient.GetAsync("http://localhost:21715/api/test");
    if (!response.IsSuccessStatusCode)
    {
        Console.WriteLine(response.StatusCode);
        // HTTP StatusCode = 400 HERE <======================
    }
    else
    {
        var content = response.Content.ReadAsStringAsync().Result;
        Console.WriteLine(JArray.Parse(content));
    }
}

最佳答案

仔细查看后,这是因为我在我的 token 中添加了一些非常大的数据集作为实验。 IIS 正在发送 HTTP 400,因为请求 header 太长。

关于c# - .NET 4.5 中带有资源 API 的 IdentityServer4 (OWIN),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44079029/

相关文章:

c# - 在 EF Code First 中过滤导航属性

c# - 如何从 Team Foundation 获取工作项的用户帐户名?

c# - ASP.NET 网络表单 : display value coming from c# code-behind

c# - 如何在不使用 EF 的情况下使用 Breeze 保存更改?

c# - WinForms:无需转到 FormWindowState.Normal 即可找到最小化表单的大小

c# - 使用 Token 获取信息。 OAuth

c# - ASP.net连接MySql,无需安装DB

asp.net - 将动态数据添加到现有站点时出错 - 'Skip' 仅支持 LINQ to Entities 中的排序输入。 'OrderBy' 必须在 'Skip' 之前调用

c# - 结果显示 System.String[]

c# - 从触摸屏重定向/重新映射/预过滤光标输入