ASP.NET Identity 2 无效身份困难

ASP.NET Identity 2 Invalidate Identity Difficulties

我今天一整天都在更新 ASP.NET Identity 的实现,我觉得我已经到了最后一步,但就是无法让它发挥作用。我想要发生的只是让用户的当前会话(如果有的话)在他们的某些事情发生变化时无效,并将他们发送回登录页面。从我今天阅读的数十篇与身份相关的文章中,我已经确定我必须重写 OnValidateIdentity 委托,但它不起作用。下面是我的代码,如果有人能告诉我我遗漏了什么,我将不胜感激,因为我肯定没有看到它...

OwinConfiguration.cs

public static class OwinConfiguration {
    public static void Configuration(
        IAppBuilder app) {
        if (app == null) {
            return;
        }

        // SOLUTION: the line below is needed so that OWIN can
        // instance the UserManager<User, short>
        app.CreatePerOwinContext(() => DependencyResolver.Current.GetService<UserManager<User, short>>());

        // SOLUTION: which is then used here to invalidate
        app.UseCookieAuthentication(new CookieAuthenticationOptions {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/"),
            ExpireTimeSpan = new TimeSpan(24, 0, 0),
            Provider = new CookieAuthenticationProvider {
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<UserManager<User, short>, User, short>(
                    // SOLUTION: make sure this is set to 0 or it will take
                    // however long you've set it to before the session is
                    // invalidated which to me seems like a major security
                    // hole. I've seen examples set it to 30 minutes, in
                    // which time a disgruntled employee (say, after being
                    // fired) has plenty of opportunity to do damage in the
                    // system simply because their session wasn't expired
                    // even though they were disabled...
                    validateInterval: TimeSpan.FromMinutes(0),
                    regenerateIdentityCallback: (m, u) => u.GenerateUserIdentityAsync(m),
                    getUserIdCallback: (id) => short.Parse(id.GetUserId())
                )
            },
            SlidingExpiration = true
        });
    }
}

GenerateUserIdentityAsync 方法看起来需要成为实体的一部分,我不喜欢这一点,因此我为它创建了一个扩展方法,该方法在具有 OWIN 配置的程序集内部:

UserExtensions.cs

internal static class UserExtensions {
    public static async Task<ClaimsIdentity> GenerateUserIdentityAsync(
        this User user,
        UserManager<User, short> manager) {
        var userIdentity = await manager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);

        return userIdentity;
    }
}

我感觉它与 UserManager<User, short> 的保险有关,但我似乎无法解决它。我认为 OWIN 应用程序必须为请求创建它的单例,但它没有发生,因此验证覆盖不起作用?问题是,我正在使用 Ninject,我不确定如何让它与 OWIN 合作,因为 OWIN 在管道中要早得多...这是 Ninject 配置:

NinjectConfiguration.cs

namespace X.Dependencies {
    using System;
    using System.Linq;
    using System.Web;
    using Data;
    using Data.Models;
    using Identity;
    using Microsoft.AspNet.Identity;
    using Microsoft.Owin.Security;
    using Microsoft.Web.Infrastructure.DynamicModuleHelper;
    using Ninject;
    using Ninject.Modules;
    using Ninject.Web.Common;
    using Services;

    public static class NinjectConfiguration {
        private static readonly Bootstrapper Bootstrapper = new Bootstrapper();

        /// <summary>
        /// Starts the application
        /// </summary>
        public static void Start() {
            DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
            DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));

            Bootstrapper.Initialize(CreateKernel);
        }

        /// <summary>
        /// Stops the application.
        /// </summary>
        public static void Stop() {
            Bootstrapper.ShutDown();
        }

        /// <summary>
        /// Creates the kernel that will manage your application.
        /// </summary>
        /// <returns>The created kernel.</returns>
        private static IKernel CreateKernel() {
            var kernel = new StandardKernel();

            try {
                kernel.Bind<Func<IKernel>>().ToMethod(
                    c => () => new Bootstrapper().Kernel);
                kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

                RegisterServices(kernel);

                return kernel;
            } catch {
                kernel.Dispose();

                throw;
            }
        }

        /// <summary>
        /// Load your modules or register your services here!
        /// </summary>
        /// <param name="kernel">The kernel.</param>
        private static void RegisterServices(
            IKernel kernel) {
            if (kernel == null) {
                return;
            }

            kernel.Bind<XContext>().ToSelf().InRequestScope();

            kernel.Bind<IUserStore<User, short>>().To<UserStore>().InRequestScope();

            kernel.Bind<IAuthenticationManager>().ToMethod(
                c =>
                    HttpContext.Current.GetOwinContext().Authentication).InRequestScope();

            RegisterModules(kernel);
        }

        private static void RegisterModules(
            IKernel kernel) {
            var modules = AssemblyHelper.GetTypesInheriting<NinjectModule>().Select(Activator.CreateInstance).Cast<NinjectModule>();

            kernel.Load(modules);
        }
    }
}

很多 OWIN 和 Identity 部分都是 copy/pasting/adjusting 根据我在网上找到的内容组合在一起的...非常感谢您的帮助。提前致谢!

您的 cookie 设置为 30 分钟后过期,但 SlidingExpiration 设置为 true。它的意思是,如果用户超过 30 分钟没有使用该网站,cookie 将在 30 分钟后过期。但是,如果用户停止使用网站 28 分钟,然后在 29 分钟或 30 分钟到期时间内点击按钮,则 cookie 到期将重置为另一个 30 分钟。实际上,cookie 不会过期。而且您不会看到 cookie 过期的影响。 cookie 只会在 30 分钟后失效,session 将不再有效。如果 cookie 有效,则会话有效,反之亦然。

这可能就是您遇到的情况。

设为假。

 SlidingExpiration = false

很可能您缺少 UserManager 注册 OWIN。

最新VS给出的MVC模板有如下几行代码:

app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

这是 运行 应用程序生命周期的早期阶段,有效地注册了关于如何创建 ApplicationUserManager 的委托。此代码通常位于您的行 app.UseCookieAuthentication 之前。并且需要向 OWIN 提供关于如何创建 ApplicationUserManager 的委托,因为它在数据库中更改 SecurityStamp 时用于 cookie 失效的例程。

现在棘手的部分是为 OWIN 提供正确的委托。很多时候你的 DI 容器是在这段代码 运行 之后创建的。所以你需要小心这一点。通常你需要将你的 DI 注册为 MVC 的 ServiceProvider 来解析你的控制器。如果这可行,您将从 MVC 服务提供商处获得 ApplicationUserManager

app.CreatePerOwinContext(() => DependencyResolver.Current.GetService<ApplicationUserManager>());

这里是full sample of the code。或者您保留创建 ApplicationUserManager 实例的静态方法。

blogged about using DI with Identity. And there is a GitHub repository 有使用 Indentity 的 DI 容器的工作代码示例。我希望这能给你一些想法。

一些代码会更好地解释。此方法只有在您登录后才能使用

[Authorise]
public ActionResult Dashboard()
{
   return View();
}

您的身份验证 cookie 设置

    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/Account/Login"),
        Provider = new CookieAuthenticationProvider
        {
            OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                validateInterval: TimeSpan.FromMinutes(2),
                regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
        },
        SlidingExpiration = false                
    });