IdentityServer4 + API на том же хосте - PullRequest
0 голосов
/ 06 декабря 2018

Итак, у меня есть проект, над которым я работаю.

Он предназначен для входа в систему и API.

Я использую Identity Server 4, ASP.NET Core Identity, MongoDBи OpenAPI.

Identity Server 4 использует ASP.NET Core Identity, которая реализована с MongoDB в качестве поставщика БД.

У меня также есть API, документированный с OpenAPI.API и IDS4 находятся на одном хосте.

Я сталкиваюсь со следующей проблемой: при входе в веб-интерфейс (по умолчанию Identity) метод SignInManager.IsSignedIn (User) возвращает false.

Я предполагаю, что я что-то упускаю / неправильно понимаю на уровне аутентификации (с тем фактом, что Identity использует Cookies, но для защиты API это токен.

My Startup.cs:

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.
    // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<CookiePolicyOptions>(options =>
        {
            // This lambda determines whether user consent for non-essential cookies is needed for a given request.
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });

        // Add the temp data provider
        services.AddSingleton<ITempDataProvider, CookieTempDataProvider>();

        // Add Identity with MongoDB
        services.AddIdentityMongoDbProvider<User>(options =>
        {
            options.ConnectionString = Configuration.GetValue<string>("Database:ConnectionString");
            options.DbType = Configuration.GetValue<DbType>("Database:DbType");
        });

        // Add EmailSender
        services.AddTransient<IEmailSender, EmailSender>();
        services.Configure<EmailSenderOptions>(Configuration.GetSection("MailSender"));

        // Add applications settings
        services.Configure<ApplicationOptions>(Configuration.GetSection("ApplicationOptions"));

        // Add IdentityServerClients configuration
        services.Configure<IdentityServerClientOptions>("EchinoManager", Configuration.GetSection("EchinoManagerOptions"));
        services.Configure<IdentityServerClientOptions>("EchinoProduct", Configuration.GetSection("EchinoProductOptions"));
        services.Configure<IdentityServerClientOptions>("WebInterface", Configuration.GetSection("WebInterfaceOptions"));

        // Add IdentityServerResources configuration
        services.Configure<APIOptions>(Configuration.GetSection("APIOptions"));
        services.Configure<APIScopeOptions>("ManageAPIScope", Configuration.GetSection("ManageAPIScopeOptions"));
        services.Configure<APIScopeOptions>("EchinoAPIScope", Configuration.GetSection("EchinoAPIScopeOptions"));
        services.Configure<APIScopeOptions>("WebInterfaceAPIScope", Configuration.GetSection("WebInterfaceAPIScopeOptions"));

        // Get X509Certificate
        X509Certificate2 cert = null;
        using (var certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine))
        {
            certStore.Open(OpenFlags.ReadOnly);
            var certCollection = certStore.Certificates.Find(
                X509FindType.FindByThumbprint,
                Configuration.GetValue<string>("ApplicationOptions:CertificateThumbprint"),
                false);

            if (certCollection.Count > 0)
            {
                cert = certCollection[0];
            }
        }

        // Add the protection of the API
        services.AddAuthentication(options =>
        {
            options.DefaultScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;                // = Bearer
            options.DefaultAuthenticateScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;    // = Bearer
        })
        .AddIdentityServerAuthentication(options =>
        {
            options.Authority = Configuration.GetValue<string>("ApplicationOptions:AuthorityServer");
            options.ApiName = Configuration.GetValue<string>("APIOptions:Name");
            options.ApiSecret = Configuration.GetValue<string>("APIOptions:Secret");
        });

        // Add Identity Server 4
        services.AddIdentityServer()
            .AddSigningCredential(cert)
            .AddInMemoryPersistedGrants()
            .AddClientStore<ClientStore>()
            .AddResourceStore<ResourceStore>()
            .AddAspNetIdentity<User>();

        // Add policies based on scopes
        services.AddAuthorization(options =>
        {
            options.AddPolicy("ManageAPIScope", builder =>
              builder.RequireClaim("scope", Configuration.GetValue<string>("ManageAPIScopeOptions:Name")));
            options.AddPolicy("EchinoAPIScope", builder =>
              builder.RequireClaim("scope", Configuration.GetValue<string>("EchinoAPIScopeOptions:Name")));
            options.AddPolicy("WebMVCAPIScope", builder =>
              builder.RequireClaim("scope", Configuration.GetValue<string>("WebInterfaceAPIScopeOptions:Name")));
        });

        // Add OpenAPI
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("manageapi", new Info
            {
                Version = "1",
                Title = "Manage API",
                Description = "The API for Echino Manager"
            });

            c.SwaggerDoc("echinoapi", new Info
            {
                Version = "1",
                Title = "Echino API",
                Description = "The API for Echino"
            });

            c.DescribeAllEnumsAsStrings();

            c.AddSecurityDefinition("oauth2", new OAuth2Scheme
            {
                Type = "oauth2",
                Flow = "application",
                TokenUrl = $"{Configuration.GetValue<string>("ApplicationOptions:AuthorityServer")}/connect/token",
                Scopes = new Dictionary<string, string>
                {
                    { "manageapi", "Access to the manage api" }
                }
            });

            c.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>>
            {
                { "oauth2", new[] { "manageapi" } }
            });

            // Set the comments path for the Swagger JSON and UI.
            var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
            var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
            c.IncludeXmlComments(xmlPath);
        });

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseCookiePolicy();

        // Enable middleware to serve generated Swagger as a JSON endpoint.
        app.UseSwagger();

        // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
        // specifying the Swagger JSON endpoint.
        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/manageapi/swagger.json", "Manage API");
            c.SwaggerEndpoint("/swagger/echinoapi/swagger.json", "Echino API");
        });

        //app.UseAuthentication(); // not needed, since UseIdentityServer adds the authentication middleware
        app.UseIdentityServer();

        app.UseMvcWithDefaultRoute();
    }
}

Вызов Identity с MongoDB:

        public static IServiceCollection AddIdentityMongoDbProvider<TUser, TRole>(this IServiceCollection services, Action<IdentityOptions> setupIdentityAction, Action<MongoIdentityOptions> setupDatabaseAction) where TUser : User where TRole : Role
    {
        services.AddIdentity<TUser, TRole>(setupIdentityAction ?? (x => { }))
            .AddRoleStore<RoleStore<TRole>>()
            .AddUserStore<UserStore<TUser, TRole>>()
            .AddDefaultTokenProviders();

        var dbOptions = new MongoIdentityOptions();
        setupDatabaseAction(dbOptions);

        var userCollection = new IdentityUserCollection<TUser>(dbOptions.DbType, dbOptions.ConnectionString);
        var roleCollection = new IdentityRoleCollection<TRole>(dbOptions.DbType, dbOptions.ConnectionString);

        // Add collections and stores in services for DI
        services.AddTransient<IIdentityUserCollection<TUser>>(x => userCollection);
        services.AddTransient<IIdentityRoleCollection<TRole>>(x => roleCollection);

        services.AddTransient<ITenantStore<Tenant, TUser>>(x => new TenantStore<Tenant, TUser>(dbOptions.DbType, dbOptions.ConnectionString, userCollection));
        services.AddTransient<ILicenseStore<License>>(x => new LicenceStore<License>(dbOptions.DbType, dbOptions.ConnectionString));

        // Identity Services
        services.AddTransient((Func<IServiceProvider, IUserStore<TUser>>)(x => new UserStore<TUser, TRole>(userCollection, roleCollection, x.GetService<ILookupNormalizer>())));
        services.AddTransient<IRoleStore<TRole>>(x => new RoleStore<TRole>(roleCollection));

        return services;
    }

Когда я комментирую часть «Добавить защиту API», логин работает хорошо.

Можете ли выребята, покажите мне / объясните мне, как заставить все это работать вместе?

Спасибо

1 Ответ

0 голосов
/ 06 декабря 2018

Это то, что у меня в стартапе.

services.AddAuthentication(IdentityServerConstants.DefaultCookieAuthenticationScheme)
        .AddIdentityServerAuthentication(options =>
            {
                options.Authority = authority;
                options.ApiName = "testapi";
                options.RequireHttpsMetadata = false;
            });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...