控制器.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被正确地显示为身份

有人能指出为什么会这样吗?当然,我确实把SignInSignOut方法中的代码从控制器中拉出来,然后进入这个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)));
}

控制器.ASP设置的用户不一致.asp.net身份识别.asp.net MVC 5

好吧,我没有一个真正的解决方案,但我有一个工作。由于在登录过程中没有设置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());
    }

我仍然在寻找一个真正的解决方案,如果有人知道一个!