ASP.NET身份2使身份困难无效

时间:2015-12-01 06:25:34

标签: c# asp.net-mvc asp.net-mvc-5 ninject asp.net-identity-2

我一直在整天更新我的ASP.NET身份实现,我觉得我已经迈出了最后一步,但却无法让它发挥作用。我想要发生的一切是让用户的当前会话(如果有的话)在有关它们的某些内容发生变化时失效,并将它们发送回登录页面。从我今天读过的几十篇与身份相关的文章中,我已经确定我必须覆盖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方法看起来需要成为实体的一部分,我不喜欢这样,所以我为它做了一个extesion方法,这个方法是在程序集内部的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和身份部分通过复制/粘贴/调整我在网上找到的东西放在一起......我真的很感激一些帮助。提前谢谢!

3 个答案:

答案 0 :(得分:4)

您很可能缺少{OWIN UserManager注册。

最新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。并且有一个GitHub repository与DI容器的工作代码示例一起使用Indentity。我希望这可以给你一些想法。

答案 1 :(得分:0)

您的Cookie设置为在30分钟后过期,但SlidingExpiration设置为true。这意味着,如果用户未使用该网站超过30分钟,则cookie将在30分钟后过期。但是,如果用户停止使用网站28分钟,然后在29分钟或30分钟到期时点击按钮,则cookie过期将重置为另外30分钟。实际上cookie不会过期。而且你不会看到cookie过期的影响。该cookie仅在30分钟后无效,会话将不再有效。如果cookie有效,则会话有效,反之亦然。

这可能正是您所经历的。

设为false。

 SlidingExpiration = false

答案 2 :(得分:0)

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

[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                
    });