控制器.ASP设置的用户不一致.asp.net身份识别.asp.net MVC 5
本文关键字:asp net 身份 MVC 识别 不一致 ASP 设置 用户 控制器 | 更新日期: 2023-09-27 17:52:16
我试图从我的控制器解耦我的身份验证,所以我煮了一个AuthenticationService
,我注入我的身份验证控制器(DefaultController
)使用Ninject。下面是AuthenticationService
的实现:
public sealed class AuthenticationService {
private IAuthenticationManager AuthenticationManager { get; set; }
private UserManager<Employee, int> EmployeeManager { get; set; }
public AuthenticationService(
IAuthenticationManager authenticationManager,
UserManager<Employee, int> employeeManager) {
this.AuthenticationManager = authenticationManager;
this.EmployeeManager = employeeManager;
}
public bool SignIn(
CredentialsInput credentials) {
Employee employee = this.EmployeeManager.Find(credentials.Email, credentials.Password);
if (employee != null) {
ClaimsIdentity identityClaim = this.EmployeeManager.CreateIdentity(employee, DefaultAuthenticationTypes.ApplicationCookie);
if (identityClaim != null) {
this.AuthenticationManager.SignIn(new AuthenticationProperties(), identityClaim);
return true;
}
}
return false;
}
public void SignOut() {
this.AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
}
}
下面是我如何配置Ninject来进行注入的:
private static void RegisterServices(
IKernel kernel) {
kernel.Bind<IUserStore<Employee, int>>().To<EmployeeStore>().InRequestScope();
kernel.Bind<IRoleStore<Role, int>>().To<RoleStore>().InRequestScope();
kernel.Bind<IAuthenticationManager>().ToMethod(
c =>
HttpContext.Current.GetOwinContext().Authentication).InRequestScope();
}
我是这样配置OWIN的:
public sealed class StartupConfig {
public void Configuration(
IAppBuilder app) {
this.ConfigureAuthentication(app);
}
public void ConfigureAuthentication(
IAppBuilder app) {
app.UseCookieAuthentication(new CookieAuthenticationOptions {
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/"),
ExpireTimeSpan = new TimeSpan(0, 60, 0)
});
}
}
哦,这里还有DefaultController
:
public sealed class DefaultController : Controller {
private AuthenticationService AuthenticationService { get; set; }
public DefaultController(
AuthenticationService authenticationService) {
this.AuthenticationService = authenticationService;
}
[HttpPost, AllowAnonymous, ValidateAntiForgeryToken]
public RedirectToRouteResult Default(
[Bind(Prefix = "Credentials", Include = "Email,Password")] CredentialsInput credentials) {
if (base.ModelState.IsValid
&& this.AuthenticationService.SignIn(credentials)) {
// Place of error. The IsInRole() method doesn't return
// the correct answer because the
// IUserStore<>.FindByIdAsync() method is not setting
// the correct data.
if (this.User.IsInRole("Technician")) {
return this.RedirectToAction<TechniciansController>(
c =>
c.Default());
}
return this.RedirectToAction(
c =>
c.Dashboard());
}
return this.RedirectToAction(
c =>
c.Default());
}
[HttpGet]
public RedirectToRouteResult SignOut() {
this.AuthenticationService.SignOut();
return this.RedirectToAction(
c =>
c.Default());
}
}
嗯,这都是可行的。我遇到的问题是UserManager
设置的会话不一致。例如,如果我构建应用程序,然后运行它(调试或不调试),会发生以下情况:
- 构建并运行
- 以user1@email.com登录
- 签署了
- 以user2@email.com登录
- 在第一个post请求中,user1仍然显示为身份
- 在第二个post请求(刷新)中,user2被正确地显示为身份
有人能指出为什么会这样吗?当然,我确实把SignIn
和SignOut
方法中的代码从控制器中拉出来,然后进入这个AuthenticationService
,但我不完全相信这是不一致的原因。因为所有的程序集都是由MVC应用程序处理的,所以它应该都是一样的,对吧?非常感谢你的帮助。
在谷歌搜索时发现了这个,虽然它被标记为已解决,但我对解决方案有点困惑。https://katanaproject.codeplex.com/workitem/201我不认为这和我的问题有任何关系了。
更新2
我相信问题的根源是调用管道中的异步,特别是在我注入UserManager<Employee, int>
的EmployeeStore
中。我有一个UserStore
的自定义实现,称为EmployeeStore
。实现IQueryableUserStore<Employee, int>
, IUserStore<Employee, int>
, IUserPasswordStore<Employee, int>
, IUserRoleStore<Employee, int>
。
当我调试FindByIdAsync(int employeeId)
方法时,我看到它由于某种原因触发了两次。第一次触发时,我看到正确的employeeId
传递给它。第二次触发时,employeeId
被设置为0。我认为这就是它出错的地方,因为它随后没有调用IsInRoleAsync(Employee employee, string roleName)
方法。
当它抛出UserId未找到的异常后刷新页面时,再次调用FindByIdAsync(...)
方法两次,但这一次employeeId
都是正确的,然后它继续调用IsInRoleAsync(...)
方法。
public Task<Employee> FindByIdAsync(
int employeeId) {
this.ThrowIfDisposed();
return this.Repository.FindSingleOrDefaultAsync<Employee, int>(employeeId);
}
public Task<bool> IsInRoleAsync(
Employee employee,
string roleName) {
this.ThrowIfDisposed();
if (employee == null) {
throw new ArgumentNullException("employee");
}
if (String.IsNullOrEmpty(roleName)) {
throw new ArgumentNullException("roleName");
}
return Task.FromResult<bool>(employee.Roles.Any(
r =>
(r.Name == roleName)));
}
好吧,我没有一个真正的解决方案,但我有一个工作。由于在登录过程中没有设置User
,因此我重定向到另一个名为DefaultRedirect
的操作,在那里我现在可以完全访问User
属性,并可以从那里重定向我真正想要的方式。这是一种让事情顺利进行的肮脏的欺骗,但这不是真正的解决方案。我仍然认为ASP。. NET身份不知何故不能正常工作。无论如何,这是我的小窍门:
[HttpPost, AllowAnonymous, ValidateAntiForgeryToken]
public RedirectToRouteResult Default(
[Bind(Prefix = "Credentials", Include = "Email,Password")] CredentialsInput credentials) {
if (base.ModelState.IsValid
&& this.AuthenticationService.SignIn(credentials)) {
return this.RedirectToAction(
c =>
c.DefaultRedirect());
}
return this.RedirectToAction(
c =>
c.Default());
}
[HttpGet]
public RedirectToRouteResult DefaultRedirect() {
if (this.User.IsInRole("Technician")) {
return this.RedirectToAction<TechniciansController>(
c =>
c.Default());
}
return this.RedirectToAction(
c =>
c.Dashboard());
}
我仍然在寻找一个真正的解决方案,如果有人知道一个!