【问题标题】:User is not authenticated identity server 4用户未通过身份验证服务器 4
【发布时间】:2020-07-24 08:42:34
【问题描述】:

问题

我有三个项目。

  1. 一个网络应用程序
  2. API
  3. 身份服务器

我遇到的问题是,当我将授权属性添加到 api 控制器时,我无法访问 API。

这是来自身份服务器的配置文件

public class Config
{
    public static List<TestUser> GetUsers()
    {
        return new List<TestUser>
        {
            new TestUser
            {
                SubjectId = "1",
                Username = "Stephen",
                Password = "Password",
                Claims = new List<Claim>
                {
                    new Claim(JwtClaimTypes.Role, "admin")
                }
            }
        };
    }

    public static IEnumerable<IdentityResource> GetIdentityResources()
    {
        return new List<IdentityResource>
        {
            new IdentityResources.OpenId(),
            new IdentityResources.Profile(),
             new IdentityResources.Email(),
            new IdentityResource
            {
                Name = "role",
                UserClaims = new List<string> {"role"}
            }
        };
    }

    public static IEnumerable<ApiResource> GetAllApiResources()
    {
        return new List<ApiResource>
        {
           new ApiResource
            {
                Name = "crmApi",
                DisplayName = "API #1",
                Description = "Allow the application to access API #1 on your behalf",
                Scopes = new List<string> {"crmApi"},
                ApiSecrets = new List<Secret> {new Secret("secret".Sha256())}, // change me!
                UserClaims = new List<string> {"role"}
                
            }
        };
    }

    public static IEnumerable<ApiScope> GetApiScopes()
    {
        return new[]
        {
            new ApiScope("crmApi", "Access to API #1"),
        };
    }

    public static IEnumerable<Client> GetClients()
    {
        return new List<Client>
        {
            new Client
            {
                ClientId = "client",
                AllowedGrantTypes = GrantTypes.ClientCredentials,
                ClientSecrets =
                {
                    new Secret("secret".Sha256())
                },
                AllowedScopes = { "crmApi" }
            },

              new Client
        {
            ClientId = "mvc",
            ClientName = "MVC Client",
            AllowedGrantTypes = GrantTypes.Implicit,
          RedirectUris = {"https://localhost:44315/signin-oidc"},
          PostLogoutRedirectUris = {"https://localhost:44315/signout-callback-oidc"},

           AllowedScopes =new List<string>
           {
               IdentityServerConstants.StandardScopes.OpenId,
               IdentityServerConstants.StandardScopes.Profile,
               IdentityServerConstants.StandardScopes.Email,
              "role",
              "crmApi"
           }
        },
    };


    }
}

这是身份服务器启动文件

   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.AddMvc(option => option.EnableEndpointRouting = false);

        var connectionString = Configuration.GetSection("ConnectionStrings:Database").Value;
        var migrationAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

        services.AddDbContext<ApplicationDbContext>(builder =>
         builder.UseSqlServer(connectionString, sqlOptions => sqlOptions.MigrationsAssembly(migrationAssembly)));
        services.AddIdentity<IdentityUser, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

        services.AddIdentityServer()
            .AddDeveloperSigningCredential()
            .AddConfigurationStore(options =>
            {
                options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationAssembly));
            })
            .AddOperationalStore(options =>
            {
                options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationAssembly));
            })
            .AddAspNetIdentity<IdentityUser>();

        services.AddCors();

        services.AddControllers();
    }

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

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseRouting();
        app.UseIdentityServer();
        app.UseAuthorization();
        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseCookiePolicy(new CookiePolicyOptions { MinimumSameSitePolicy = SameSiteMode.Lax });
        app.UseCors();
        app.UseMvcWithDefaultRoute();
    }

    private void InitialISDatabase(IApplicationBuilder app)
    {
        using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
        {
            serviceScope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();
            serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>().Database.Migrate();
            serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>().Database.Migrate();

            var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();

            if (!context.Clients.Any())
            {
                foreach (var client in Config.GetClients())
                {
                    context.Clients.Add(client.ToEntity());
                }

                context.SaveChanges();
            }


            if (!context.IdentityResources.Any())
            {
                foreach (var resource in Config.GetIdentityResources())
                {
                    context.IdentityResources.Add(resource.ToEntity());
                }

                context.SaveChanges();
            }

            if (!context.ApiScopes.Any())
            {
                foreach (var scope in Config.GetApiScopes())
                {
                    context.ApiScopes.Add(scope.ToEntity());
                }
                context.SaveChanges();
            }

            if (!context.ApiResources.Any())
            {
                foreach (var api in Config.GetAllApiResources())
                {
                    context.ApiResources.Add(api.ToEntity());
                }

                context.SaveChanges();
            }

            var userManager = serviceScope.ServiceProvider.GetRequiredService<UserManager<IdentityUser>>();
            if (!userManager.Users.Any())
            {
                foreach (var testUser in Config.GetUsers())
                {
                    var identityUser = new IdentityUser(testUser.Username)
                    {
                        Id = testUser.SubjectId
                    };

                    userManager.CreateAsync(identityUser, "Password123!").Wait();
                    userManager.AddClaimsAsync(identityUser, testUser.Claims.ToList()).Wait();
                }
            }

        }
    }
}

这里是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.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
            .AddIdentityServerAuthentication(options =>
            {
                options.Authority = "https://localhost:44302/";
                options.ApiName = "crmApi";
                options.RequireHttpsMetadata = false;
               
            });

        services.AddAuthorization();
        services.AddControllers();

      
    }

    // 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.UseRouting();

        app.UseAuthentication();

        app.UseAuthorization();
        app.UseHttpsRedirection();

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

这里是 web 项目的启动文件。

   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.AddControllersWithViews();

        JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

        services.AddAuthentication(options =>
        {
            options.DefaultScheme = "Cookies";
            options.DefaultChallengeScheme = "oidc";
        })
        .AddCookie("Cookies")
        .AddOpenIdConnect("oidc", options =>
        {
            options.SignInScheme = "Cookies";
            options.Authority = "https://localhost:44302/";
            options.RequireHttpsMetadata = false;
            options.ClientId = "mvc";
            options.SaveTokens = true;
        });
    }

    // 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())
        {
           
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }
        app.UseDeveloperExceptionPage();

        app.UseHttpsRedirection();

        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

【问题讨论】:

  • 发布您的 api 启动。
  • 我做到了。它说这是我的 api 启动
  • 尝试将 [Authorize(AuthenticationSchemes="Bearer")] 添加到控制器。
  • 我删除了 .AddTestUsers(Config.GetUsers()) 并将属性添加到控制器。身份服务器说用户未通过身份验证,但存在于数据库中
  • 看这里,像这里一样为启动添加身份验证,github.com/LalitaCode/IdentityServerSubdomainMultiTenant/blob/…

标签: c# identityserver4


【解决方案1】:

您需要将 ApiScopesApiResources 添加到 IdentityServer 设置中,无论是在数据库中还是在内存中

要将它们添加到内存中,您需要将代码更改为:

services.AddIdentityServer()
            .AddInMemoryApiScopes(Config.GetApiScopes())
            .AddInMemoryApiResources(Config.GetAllApiResources())`
            .AddDeveloperSigningCredential()
            .AddTestUsers(Config.GetUsers())
            .AddConfigurationStore(options =>
            {
                options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationAssembly));
            })
            .AddOperationalStore(options =>
            {
                options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationAssembly));
            })
            .AddAspNetIdentity<IdentityUser>(); ;

如果您将它们添加到 DB 中,您需要确保您的表为 ApiResourceScopesApiScopeProperties

阅读更多关于 IDS4 DB here

另一个选项是更改 API 以删除受众验证。只要您的 IdentityServer 发出 access_token,API 授权就可以工作。为此,将 API 上的代码更改为:

services.AddAuthentication("Bearer").AddJwtBearer("Bearer",
   options =>
   {
      options.Authority = "http://localhost:5000";
      options.Audience = "crmApi";
      options.RequireHttpsMetadata = false;
      options.TokenValidationParameters = new 
         TokenValidationParameters()
         {
            ValidateAudience = false
         };
   });

您可以尝试第二个选项来验证您是否正确设置了 api 范围。

在我的博客here了解更多信息

【讨论】:

  • 我有这些
  • 在数据库上吗?你可以发布你的数据库记录的快照吗? @PeterKennan
  • 发布的数据库记录
  • @PeterKennan 在回复中为你添加了另一个选项
  • @PeterKennan 如果您在 DB 上添加这些数据,我们会在 ApiResources ApiResourceScopes 上提供数据
【解决方案2】:

我有 2 个项目 1-身份服务器 2-电影客户端 当我将项目设置为 HTTPS 时一切正常 但是当我在HTTP中设置项目时,即使登录操作代码正确完成,但用户并没有登录。

【讨论】:

  • 这没有回答问题。如果需要,您可以提出新问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-28
  • 1970-01-01
  • 2017-08-25
  • 2013-08-21
  • 2020-10-08
相关资源
最近更新 更多