我在我的mvc应用程序中使用带有AspNet标识的ninject
在我的全局asax中,我有以下代码行
kernel.Bind<IIdentityManager>().To<IdentityManager>().InRequestScope().WithConstructorArgument("conn", idConnString);
每当向控制器发出新请求时,都应该创建上述类的新实例。
然而,这并没有发生。断点显示上述类的构造函数仅在网站加载时被调用一次,并且在我刷新页面或发出新请求时永远不再被命中(它被注入到每个页面请求检查的类中)声明并因此授权或拒绝用户访问他们所请求的页面。因此,支持identitymanager的数据库连接上下文保持不变,并且永远不会根据请求重新加载。因此,它永远不会对网站外部发生的声明进行任何更改,如果在每个请求上创建了一个新的IdentityManager实例,就会发生这种情况,因为我希望它能够给出上述绑定。
非常感谢任何建议。
编辑以添加更多代码。 (注意我删除了与此特定问题无关的代码以使其更短)
我的Global.asax
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
kernel.Bind<IVariables>().ToConstructor<Variables>(context => new Variables(AppSettingKeys.NRDAWebServer)).InRequestScope();
var variables = kernel.Get<IVariables>();
var masterPassword = VBHelperCore.Encryptor.EncDec.Decrypt(File.ReadAllBytes(AppSettingKeys.ConfigSettingsKeys.ConfigLocation + AppSettingKeys.SQLConnection.NRDAMasterUserName),
AppSettingKeys.HexString);
var s3ConnString = @"Data Source=" + variables.Get(AppSettingKeys.SQLConnection.NRDAMasterSQLServer, null) + @";Initial Catalog=" + variables.Get(AppSettingKeys.SQLConnection.NRDAMasterDB, null) +
";User ID=" + variables.Get(AppSettingKeys.SQLConnection.NRDAMasterUserName, null) + ";Password=" +
masterPassword +
";Trusted_Connection=False;MultipleActiveResultSets=True;";
var idConnString = s3ConnString;
kernel.Bind<IAuthenticationFilter>().To<NrdaAuthenticationAttribute>().InRequestScope();
kernel.Bind<IIdentityManager>().To<IdentityManager>().InRequestScope().WithConstructorArgument("conn", idConnString);
kernel.Bind<INrdaClaimsTransformer>().To<NrdaClaimsTransformer>().InRequestScope();
GlobalConfiguration.Configuration.DependencyResolver = new Ninject.WebApi.DependencyResolver.NinjectDependencyResolver(kernel);
return kernel;
}
这实质上加载配置变量以获取带有密码的连接字符串,然后将IdentityManager的新实例与传递给其构造函数的连接字符串绑定。
我已经定义了一个ActionFilter
public class NrdaAuthenticationAttribute : ActionFilterAttribute, IAuthenticationFilter
{
[Inject]
public INrdaClaimsTransformer ClaimsTransformer{ private get; set; }
[Inject]
public ILogger Log { get; set; }
public void OnAuthentication(AuthenticationContext filterContext)
{
try
{
var user = filterContext.HttpContext.User;
if ((user != null && user.Identity.IsAuthenticated))
{
ClaimsPrincipal currentPrincipal = ClaimsPrincipal.Current;
ClaimsPrincipal tranformedClaimsPrincipal = ClaimsTransformer.Authenticate(string.Empty, currentPrincipal);
Thread.CurrentPrincipal = tranformedClaimsPrincipal;
HttpContext.Current.User = tranformedClaimsPrincipal;
}
else
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
catch (SecurityException ex)
{
Log.Error(ex, "Security error" + ex.Message, null);
}
}
public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
{
}
}
所有控制器都有,所以每次访问任何控制器时都会调用此过滤器(所以每次请求都是如此)
[NrdaAuthentication]
过滤器使用内核绑定的Claims Transformer
public class NrdaClaimsTransformer : ClaimsAuthenticationManager, INrdaClaimsTransformer
{
[Inject]
public IIdentityManager IdentityManager { private get; set; }
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
{
var ret = !incomingPrincipal.Identity.IsAuthenticated
? base.Authenticate(resourceName, incomingPrincipal)
: DressUpPrincipal(incomingPrincipal);
return base.Authenticate(resourceName, ret);
}
private ClaimsPrincipal DressUpPrincipal(ClaimsPrincipal incomingPrincipal)
{
var user = IdentityManager.GetByUsername(incomingPrincipal.Identity.Name);
return null //code removed to simplify example
}
}
显然我已经削减了很多代码以简化,但由于ninject绑定都被设置为InRequestScope()
,我希望在每个新请求上调用IdentityManager
的构造函数。但事实并非如此。断点显示它仅在网站首次启动时调用,之后再次调用,因此它必须在每个Web请求中使用相同的实例,而不应该
编辑2
好的我觉得我发现了问题。似乎因为InRequestScope在自定义授权属性中不起作用。或者实际上我尝试过的任何其他范围函数。我假设这是因为属性实例被加载到用户会话的内存中,因此注入的类永不过期,因此不需要由ninject重新加载。当我通过使用控制器调用注入的类来进行测试时,在操作中它可以正常工作。现在我只需要在属性中加载一个新的identitymanager实例而不是ninject版本