【问题标题】:Combine IdentityServer4 and ASP.NET Core Identity Framework结合 IdentityServer4 和 ASP.NET Core Identity Framework
【发布时间】:2021-04-11 17:10:20
【问题描述】:

大家好,我对 IdentityServer4 和 Identity Framework 的组合有疑问。 我的解决方案中有 3 个项目。 首先,它是一个带有 IdentityServer4 的 OAuth 项目。本项目有如下配置:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using IdentityServer4;
using IdentityServer4.Models;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Platform.OAuth.Data;
using Platform.OAuth.Data.Models;

namespace Platform.OAuth
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<ApplicationContext>(options =>
            {
                options.UseSqlServer(
                    Configuration.GetConnectionString("DefaultConnection"),
                    x => x.MigrationsAssembly(typeof(ApplicationContext).Assembly.FullName));
            });

            services.AddIdentity<ApplicationUser, ApplicationRole>()
                .AddEntityFrameworkStores<ApplicationContext>();

            services.AddControllers();
            services.AddIdentityServer()
                .AddDeveloperSigningCredential()
                .AddInMemoryPersistedGrants()
                .AddInMemoryClients(new List<Client>
                {
                    new Client
                    {
                        ClientId = "api-client",
                        ClientName = "API Client",
                        AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,

                        RequireConsent = false,

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

                        RedirectUris = { "http://localhost:5002/signin-oidc" },
                        PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },

                        AllowedScopes =
                        {
                            IdentityServerConstants.StandardScopes.OpenId,
                            IdentityServerConstants.StandardScopes.Profile,
                            "api1"
                        },
                        AllowOfflineAccess = true
                    }
                })
                .AddInMemoryApiScopes(new List<ApiScope>
                {
                    new ApiScope("api1", "My API")
                })
                .AddAspNetIdentity<ApplicationUser>();

            services.AddAuthentication();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseIdentityServer();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

其次,它是包含一些我想要保护的 API 的 API 项目。这个项目有下一个配置:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;

namespace Api
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.AddAuthorization(options =>
            {
                options.FallbackPolicy = new AuthorizationPolicyBuilder()
                    .RequireAuthenticatedUser()
                    .Build();
            });

            services.AddAuthentication("Bearer")
            .AddJwtBearer("Bearer", options =>
            {
                options.Authority = "https://localhost:44392"; /// <-- OAuth project url

                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateAudience = false
                };
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

第三,它是调用这两个 API 的客户端项目。

        static async Task Main(string[] args)
        {
            var client = new HttpClient();
            var disco = await client.GetDiscoveryDocumentAsync("https://localhost:44392");
            if (disco.IsError)
            {
                Console.WriteLine(disco.Error);
                return;
            }

            var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
            {
                Address = disco.TokenEndpoint,

                ClientId = "api-client",
                ClientSecret = "secret",
                Scope = "api1"
            });

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

            Console.WriteLine(tokenResponse.Json);

            client.SetBearerToken(tokenResponse.AccessToken);
            var testResponse = await client.GetAsync("https://localhost:44392/WeatherForecast");
            if(testResponse.IsSuccessStatusCode)
            {
                var content = await testResponse.Content.ReadAsStringAsync();
                Console.WriteLine(JArray.Parse(content));
            }

            var apiClient = new HttpClient();
            apiClient.SetBearerToken(tokenResponse.AccessToken);
            Console.WriteLine("==============================================================");
            var response = await apiClient.GetAsync("https://localhost:44369/WeatherForecast");
            if (!response.IsSuccessStatusCode)
            {
                Console.WriteLine(response.StatusCode);
            }
            else
            {
                var content = await response.Content.ReadAsStringAsync();
                Console.WriteLine(JArray.Parse(content));
            }
        }

这两个 Web API 项目都有默认的 WeatherForecastController,我受 AuthorizeAttribute 保护当客户端使用令牌向 API 发出请求时,操作会返回数据,但是当请求 OAuth 时,操作会返回 404 错误.我认为这对OAuth 项目有利,但对API 不利,因为API 和'OAuth' 项目没有授权用户。但是为什么API 返回数据呢?

【问题讨论】:

    标签: asp.net-core asp.net-identity identityserver4


    【解决方案1】:

    接收 404 不应与任何身份验证问题相关,因为它是 HTTP“未找到”代码,当您尝试访问的资源未通过使用的 URL 找到时准确检索。

    关于从 API 端点接收到的数据,它是一个成功的响应,对吧?我会假设是的。

    按照您的客户端代码 sn-p,在我看来,您从 Identity Server 获得了一个令牌,并使用该令牌集执行了一个 GET 请求。由于令牌有效,因此客户端通过身份验证,API 识别它。

    如果您设置 [Authorize] 属性但未指定任何策略,则应用默认值。默认为:if you are authenticated, you are also authorized;这意味着提供一个有效的令牌就足以获得授权——你可以这样做。

    我会说这就是您获得成功响应的原因。更多信息here.

    【讨论】:

    • @Алексей 这有帮助吗?
    猜你喜欢
    • 2019-07-19
    • 2019-05-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-20
    • 2018-03-06
    • 2019-01-12
    • 2017-03-20
    • 1970-01-01
    相关资源
    最近更新 更多