До. NET Core 2.2 без проблем: я создал леса EF Core, в моем Web API был 1 контекст, а в Authenticate
методе, который я написал, например,
var user = _context.Users.SingleOrDefault(x => x.UserName == username);
В Чтобы найти пользователя в пользовательской таблице (AspNetUsers
), пароль был проверен путем проверки user.PassWordHash
и user.PasswordSalt
с параметром пароля.
С 3.1 У меня есть работающий веб-API, использующий 2 контексты: 1, полученные с помощью скаффолдинга, как и раньше, который вызывает скаффолдинг таблиц аутентификации (AspNetRoleClaims
, AspNetRoles
...), но я не смог использовать эти таблицы, как раньше в моих UsersControllers
, были различные ошибки.
Поэтому я вручную создал ApplicationDbContext
:
using IdentityServer4.EntityFramework.Options;
using Microsoft.AspNetCore.ApiAuthorization.IdentityServer;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
namespace SampleWebApi.Dtos
{
public class ApplicationDbContext : ApiAuthorizationDbContext<ApplicationUser>
{
public ApplicationDbContext(
DbContextOptions options,
IOptions<OperationalStoreOptions> operationalStoreOptions) : base(options, operationalStoreOptions)
{
}
}
}
Тогда в моем Startup.cs
у меня есть
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddDbContext<coreusersContext>(options =>
options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection")
), ServiceLifetime.Transient);
services.AddDbContext<ApplicationDbContext>(options =>
options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection")
), ServiceLifetime.Transient);
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = false)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddCors(options =>
{
options.AddPolicy("AllowAll",
builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
services.AddAutoMapper(typeof(Startup));
var appSettingsSection = Configuration.GetSection("AppSettings");
services.Configure<AppSettings>(appSettingsSection);
//configure jwt authentication
var appSettings = appSettingsSection.Get<AppSettings>();
var key = Encoding.ASCII.GetBytes(appSettings.Secret);
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.Events = new JwtBearerEvents
{
OnTokenValidated = context =>
{
var userService = context.HttpContext.RequestServices.GetRequiredService<IUserService>();
// not parseInt, Id no nore an Int but a Guid
var userId = context.Principal.Identity.Name;
var user = userService.GetByIdAsync(userId);
if (user == null)
{
// return unauthorized if user no longer exists
context.Fail("Unauthorized");
}
return Task.CompletedTask;
}
};
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
};
});
services.AddMvc().AddJsonOptions(options =>
{
// Use the default property (Pascal) casing.
options.JsonSerializerOptions.PropertyNamingPolicy = null;
options.JsonSerializerOptions.IgnoreNullValues = true;
}).SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
//configure DI for application services
services.AddScoped<IUserService, UserService>();
services.AddScoped<ICompanyService, CompanyService>();
services.AddScoped<IRepository, RepositoryService>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.UseRouting();
app.UseCors("AllowAll");
app.UseAuthentication();
app.UseAuthorization();
//
app.UseEndpoints(endpoints => {
endpoints.MapControllers();
});
}
Из приведенного выше кода исключены некоторые мелочи как CORS и Политики. В конце UsersController
теперь у меня есть:
...
SignInResult result = await _signInManager.PasswordSignInAsync(username, password, rememberme, lockoutOnFailure: false);
if (result.Succeeded)
{
var user = await _userManager.FindByNameAsync(username);
return user;
}
if (result.RequiresTwoFactor)
{
throw new Exception("auth-requirestwofactor");
}
if (result.IsLockedOut)
{
throw new Exception("auth-lockout");
}
...
_signInManager
- это внедренный экземпляр SignInManager<ApplicationUser>
, ApplicationUser
определяется как
using Microsoft.AspNetCore.Identity;
namespace SampleWebApi.Dtos
{
public class ApplicationUser : IdentityUser
{
}
}
UserManager
это экземпляр UserManager<ApplicationUser>
.
При использовании приведенного выше кода аутентификация работает отлично: в UsersController
я использую только ApplicationDbContext
; для других таблиц базы данных я использую в других контроллерах контекст, сгенерированный из скаффолдинга EF Core.
Так что все работает, но я сомневаюсь, что этот подход действительно правильный.
Если Я закомментирую в Startup.cs
, ConfigureServices
:
services.AddDbContext<ApplicationDbContext>(options =>
options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection")
), ServiceLifetime.Transient);
явно бесполезно, я получаю ошибку:
Некоторые службы не могут быть построены