首页 > 解决方案 > 使用个人用户帐户将 IdentityServer 添加到 Razor 应用程序 - 发现多个 DbContext

问题描述

我创建了一个将身份验证设置为个人用户帐户的 Razor Pages Web 应用程序。

然后我尝试将 IdentityServer4 添加到 Startup,以便我也可以支持 {{base_url}}/connect/token 来获取 access_token。

当我调用 {{base_url}}/connect/token 时,我收到 500 错误,并且控制台日志显示 Clients 表不存在。

然后我尝试进行添加迁移,但出现错误:找到了多个 DbContext。

下面是我的 Startup.cs 文件......这里有什么我应该修复的东西,以便没有(似乎)两个 DbContexts?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using MyIdentityServer.Data;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using MyIdentityServer.Entities;
using MyIdentityServer.Services;
using Microsoft.AspNetCore.Identity.UI.Services;
using MyIdentityServer.IdentityServer;
using System.Reflection;

namespace MyIdentityServer
{
    public class Startup
    {
        public Startup(IWebHostEnvironment environment, IConfiguration configuration)
        {
            Environment = environment;
            Configuration = configuration;
        }

        public IWebHostEnvironment Environment { get; }
        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)
        {
            var connectionString = Configuration.GetConnectionString("DefaultConnection");
            string migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(connectionString));

            services.AddIdentity<ApplicationUser, IdentityRole>(config =>
            {
                config.SignIn.RequireConfirmedEmail = false;
            })
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();

            var builder = services.AddIdentityServer(options =>
            {
                options.Events.RaiseErrorEvents = true;
                options.Events.RaiseInformationEvents = true;
                options.Events.RaiseFailureEvents = true;
                options.Events.RaiseSuccessEvents = true;
                options.EmitStaticAudienceClaim = true;
            })
            // .AddInMemoryPersistedGrants()
            /*
            .AddInMemoryIdentityResources(IdentityServerConfig.IdentityResources)
            .AddInMemoryApiScopes(IdentityServerConfig.ApiScopes)
            .AddInMemoryClients(IdentityServerConfig.Clients)
            */
            .AddConfigurationStore(options =>
            {
                options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
            })
            .AddOperationalStore(options =>
            {
                options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));                            
                options.EnableTokenCleanup = true; // this enables automatic token cleanup. this is optional. 
                options.TokenCleanupInterval = 30;
            })
            .AddAspNetIdentity<ApplicationUser>();

            services.Configure<SmtpSettings>(Configuration.GetSection("SmtpSettings"));
            services.AddTransient<IEmailSender, AuthMessageSender>();
            services.AddTransient<ISmsSender, AuthMessageSender>();
            services.AddScoped<IDecryptCookieService, DecryptCookieService>();
        
            services.AddAuthentication()
              .AddFacebook(facebookOptions =>
              {
                  facebookOptions.AppId = Configuration["Authentication:Facebook:AppId"];
                  facebookOptions.AppSecret = Configuration["Authentication:Facebook:AppSecret"];
                  facebookOptions.AccessDeniedPath = "/AccessDeniedPathInfo";
              })
              .AddTwitter(twitterOptions =>
              {
                  twitterOptions.ConsumerKey = Configuration["Authentication:Twitter:ConsumerAPIKey"];
                  twitterOptions.ConsumerSecret = Configuration["Authentication:Twitter:ConsumerSecret"];
                  twitterOptions.RetrieveUserDetails = true;
              });

            services.AddControllersWithViews();
            services.AddRazorPages();
        }

        // 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.UseDatabaseErrorPage();
            }
            else
            {
                app.UseExceptionHandler("/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.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseIdentityServer();

            app.UseAuthentication();
            app.UseAuthorization(); // <- allows the use of [Authorize] on controllers and action

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

此外,在数据文件夹中:

using System;
using System.Collections.Generic;
using System.Text;
using MyIdentityServer.IdentityServer;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

namespace MyIdentityServer.Data
{
    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {
        }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;

namespace MyIdentityServer.IdentityServer
{
    public class ApplicationUser : IdentityUser
    {
    }
}

标签: c#sql-serveridentityserver4razor-pagesasp.net-core-3.1

解决方案


好的......所以事实证明 IdentityServer4(如上实现时)确实添加了两个额外的上下文:

// add-migration -context ApplicationDbContext
// add-migration -context PersistedGrantDbContext
// add-migration -context ConfigurationDbContext

推荐阅读