4

在我们的 ASP.NET MVC 项目中,我们使用 Ninject 来解决控制器所需的依赖关系。

这些依赖项之一是当前用户HttpContext.Current.User.Identity。如果用户通过了身份验证,我们希望实例化一个用户对象和几个依赖它的服务。但我们不想手动执行此操作,而是让 ninject 将这些实例注入控制器。

所以我们现在遇到了麻烦,因为当然可以在没有经过身份验证的情况下找到一个 url。然后 ninject 尝试在 asp.net 重定向到登录页面之前解析实例。

我可以想到解决方案,我们配置 ninject 只在用户通过身份验证时注入:

kernel.Bind<User>().ToMethod(GetUser).When(context => HttpContext.Current.User.Identity.IsAuthenticated).InRequestScope();

这里的问题是,即使用户没有经过身份验证,ninject 也会实例化一个默认对象,所以我的服务会崩溃或无论如何都需要检查实例。空检查会让我更容易接受,但我不想激活AllowNullInjectionNinject 的设置。

所以我的问题是做这些有条件的事情的最佳实践是什么?在这些情况下我是否可以使用 Ninject 功能,或者我不应该注入这些依赖项?

4

2 回答 2

5

我假设您正在谈论一种情况,即未经身份验证的用户可以尝试导航到通常需要身份验证的页面,但无需先完成登录过程。然后,Ninject 将无法将当前用户对象注入控制器,因为它尚不为人所知,并且会引发异常。

我可以看到 2 个选项:

第一个选项不是注入当前用户,而是创建一个工厂或提供者来检索当前用户详细信息并注入它。然后控制器可以调用提供程序来获取当前用户,如果用户不可用,您可以重定向到登录页面。

public OrdersController(IUserProvider userProvider)
{
    this.userProvider = userProvider
}

public void DoSomething()
{
    var user = this.userProvider.GetCurrentUser();
    if (user == null)
        RedirectToLogin();

    // continue doing something
}

public class UserProvider : IUserProvider
{
    public User GetCurrentUser() { ... }
}

此选项的问题是您可能需要在许多控制器中执行此操作(这是一个“横切关注点”),并且您不想一遍又一遍地重复执行重定向的代码。相反,第二种选择是使用装饰器设计模式创建一个拦截器,在转发到真实控制器之前检查登录用户。

我过去做过类似的事情的方式是使用Ninject Interception Extension创建一个属性来标记哪些控制器需要身份验证,如下所示(位 psuedo-codey):

public class AuthenticationInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        bool authenticated = // ... get the current user ...

        if (authenticated)
            invocation.Proceed();
        else
            RedirectToLoginPage(); // however you want to do this
    }
}

public class RequiresAuthenticationAttribute : InterceptAttribute
{
    public override IInterceptor CreateInterceptor(IProxyRequest request)
    {
        return request.Context.Kernel.Get<AuthenticationInterceptor>();
    }
}

[RequiresAuthentication]
public class OrdersController : IOrdersController
{
    // assume you've already been authenticated
}

RequiresAuthentication每当创建装饰的类并检查当前用户凭据时,都会自动创建拦截器。如果它们无效,请求将被转发到登录页面,否则将照常继续。然后可以编写和测试这个拦截器一次,同时在许多地方使用,而无需重复代码。

于 2013-07-03T20:06:19.783 回答
0

就像一些人可能会觉得有用的简单身份验证和非身份验证答案一样。

        kernel.Bind<ICustomUser>()
            .To<User>()
            .When(ctx => HttpContext.Current.User.Identity.IsAuthenticated)
            .InRequestScope();

        kernel.Bind<ICustomUser>()
            .To<Guest>()
            .When(ctx => !HttpContext.Current.User.Identity.IsAuthenticated)
            .InRequestScope();

否则任何更复杂的亚当罗杰斯遮阳篷更好:)

于 2015-09-03T05:23:37.900 回答