【发布时间】:2018-12-24 19:15:17
【问题描述】:
我知道这个问题可能已经被问过好几次了,但所提出的解决方案都没有奏效。
基本上,我有一个 .NET Core 解决方案,我想用它来实现 Identity Core。我有3个项目
- 处理请求的 API 项目 (Web Api)
- 所有业务逻辑的核心项目(类库)
- 用于与 DB(类库)通信的 Dal 项目
所有设置都已正确完成,我已创建数据库并且初始种子已完成。我的问题是我无法登录,因为我的 LoginService 任务始终是 WaitForActivation。我的理解是我的代码中某处存在死锁,但我无法找到它。
LoginController 代码
[Route("api/[controller]")]
public class LoginController : Controller
{
private readonly ILoginService _loginService;
public LoginController(ILoginService loginService)
{
_loginService = loginService;
}
[AllowAnonymous]
[HttpPost]
public async Task<IActionResult> Login([FromBody] LoginDto login)
{
if (!ModelState.IsValid)
return BadRequest("Email or password missing");
var loginModel = Map(login);
var result = await _loginService.SignInAsync(loginModel);
return Ok();
}
private static LoginModel Map(LoginDto loginDto)
{
return new LoginModel
{
Email = loginDto.Email,
Password = loginDto.Password,
IsPersistent = loginDto.RememberMe
};
}
}
LoginService 接口
public interface ILoginService
{
Task<SignInResult> SignInAsync(LoginModel model);
}
LoginService接口的实现
public class LoginService : SignInManager<User>, ILoginService
{
public LoginService(UserManager<User> userManager,
IHttpContextAccessor contextAccessor,
IUserClaimsPrincipalFactory<User> claimsFactory,
IOptions<IdentityOptions> optionsAccessor,
ILogger<SignInManager<User>> logger,
IAuthenticationSchemeProvider schemes)
: base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes)
{
}
public async Task<SignInResult> SignInAsync(LoginModel model)
{
var result = await PasswordSignInAsync(model.Email, model.Password, model.IsPersistent, true);
return result;
}
}
我的创业班
public class Startup
{
private const string CORS_POLICY_NAME = "CORS";
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
Configuration = builder.Build();
}
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("IdentityServerConnectionString");
services.AddDbContext<IdentityServerDbContext>(options =>
{
options.UseSqlServer(connectionString);
options.UseOpenIddict();
});
ConfigureCors(services);
services.AddIdentity<User, IdentityRole>(o =>
{
o.Password.RequireDigit = true;
o.Password.RequireLowercase = true;
o.Password.RequireUppercase = true;
o.Password.RequireNonAlphanumeric = true;
o.Password.RequiredLength = 6;
o.Lockout.MaxFailedAccessAttempts = 3;
o.SignIn.RequireConfirmedEmail = true;
o.User.RequireUniqueEmail = true;
})
.AddEntityFrameworkStores<IdentityServerDbContext>()
.AddDefaultTokenProviders();
// Register the OpenIddict services.
services.AddOpenIddict()
.AddCore(options =>
{
// Configure OpenIddict to use the Entity Framework Core stores and entities.
options.UseEntityFrameworkCore()
.UseDbContext<IdentityServerDbContext>();
})
.AddServer(options =>
{
// Register the ASP.NET Core MVC binder used by OpenIddict.
// Note: if you don't call this method, you won't be able to
// bind OpenIdConnectRequest or OpenIdConnectResponse parameters.
options.UseMvc();
// Enable the token endpoint (required to use the password flow).
options.EnableTokenEndpoint("/connect/token");
// Allow client applications to use the grant_type=password flow.
options.AllowPasswordFlow();
// During development, you can disable the HTTPS requirement.
options.DisableHttpsRequirement();
// Accept token requests that don't specify a client_id.
options.AcceptAnonymousClients();
})
.AddValidation();
services.AddMvc(options =>
{
options.Filters.AddService(typeof(GlobalExceptionFilterAttribute));
options.Filters.Add(new CorsAuthorizationFilterFactory(CORS_POLICY_NAME));
});
services.AddSingleton<GlobalExceptionFilterAttribute>();
services.AddScoped<ILoginService, LoginService>();
services.AddScoped<UserManager<User>>();
services.AddScoped<UserStore<User>>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors(CORS_POLICY_NAME);
app.UseAuthentication();
app.UseMvc();
SeedData.Initialize(serviceProvider);
}
private void ConfigureCors(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(CORS_POLICY_NAME, policy =>
{
policy.AllowAnyHeader();
policy.AllowAnyMethod();
policy.AllowAnyOrigin();
if (Convert.ToBoolean(Configuration["AccessControlSettings:AllowCredentials"]))
{
policy.AllowCredentials();
}
else
{
policy.DisallowCredentials();
}
});
});
}
}
我希望这能提供足够的信息来找到解决方案。
【问题讨论】:
-
您的
PasswordSignInAsync实现是什么样的? -
这不是我的实现,是SignInManager中实现的Identity方法
标签: c# asynchronous async-await .net-core task