我一直在整天更新我的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和身份部分通过复制/粘贴/调整我在网上找到的东西放在一起......我真的很感激一些帮助。提前谢谢!
答案 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
});