ASP.NET MVC Post Authentication IoC setup

本文关键字:IoC setup Authentication Post NET MVC ASP | 更新日期: 2023-09-27 18:18:51

我有一个http客户端包装器,我注入到我所有的控制器。如果一个用户是经过身份验证的,注入的包装器应该有一些属性设置为经过身份验证的用户信息。

我现在有这个:

[System.Web.Mvc.Authorize]
public class ProfileController : Controller
{
    private readonly IMyClient client;
    public ProfileController()
    {
        string apiKey = ConfigurationManager.AppSettings["ApiKey"];
        client = new MyClient(apiKey);
        SetupClient();
    }
    private void SetupClient()
    {
        if (Thread.CurrentPrincipal.Identity.IsAuthenticated)
        {
            var identity = Thread.CurrentPrincipal.Identity as ClaimsIdentity;
            var tokenClaim = identity.Claims.First(c => c.Type == ClaimTypes.Sid);
            client.AddCredentials(tokenClaim.Value);
        }
    }
}

我想卸载SetupClient到某个地方,将允许我做IMyClient的依赖注入。

本质上我想实现这个解决方案:

ProfileController.cs

[System.Web.Mvc.Authorize]
public class ProfileController : Controller
{
    private readonly IMyClient client;
    public ProfileController(IMyClient client)
    {
        this.client = client;
    }
}

Startup.cs

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        IoCConfig.RegisterIoC(app);
        ConfigureAuth(app);
    }
}

IoCConfig.cs

public class IoCConfig
{
    public static void RegisterIoC(IAppBuilder app)
    {
        var container = new Container();
        container.Register<IMyClient>(
            () =>
            {
                var apiKey = ConfigurationManager.AppSettings["APIKey"];
                var myClient= new MyClient(apiKey);
                // This will not work as this code is executed on app start
                // The identity will not be of the user making the web request
                var identity = Thread.CurrentPrincipal.Identity as ClaimsIdentity;
                var tokenClaim = identity.Claims.First(c => c.Type == ClaimTypes.Sid);
                client.AddCredentials(tokenClaim.Value);
                return myClient;
            });
        // Register the dependency resolver.
        DependencyResolver.SetResolver(
            new SimpleInjectorDependencyResolver(container));
    }
}

我被困在IoCConfig的代码中,以提取经过身份验证的用户的信息(如果用户经过身份验证),并设置客户端进行注入。有什么帮助吗?

我的IoC框架是SimpleInjector,但我想要一个不可知的解决方案。

ASP.NET MVC Post Authentication IoC setup

我是这样做的

public class ProfileController : Controller
{
    private readonly MyClient _client;
    public ProfileController()
    {
        var clientInfo = Resolve<IClientInfo>(); // call out to your service locator
        _client = clientInfo.GetClient();
    }
}
public interface IClientInfo
{
    MyClient GetClient();
}
public interface IAuth
{
    System.Security.Claim GetSidClaim();
}
public class ClientInfo : IClientInfo
{
    private readonly IAuth _auth;
    public ClientInfo(IAuth auth)
    {
        _auth = auth;
    }
    public MyClient GetClient()
    {
        var apiKey = ApiKey;
        var client = new MyClient(apiKey);
        var claim = _auth.GetSidClaim();
        client.AddCredentials(claim.Value);
        return client;
    }
    protected virtual string ApiKey
    {
        get { return ConfigurationManager.AppSettings["APIKey"]; }
    }
}

我会看看NInject和MVC扩展…

http://ninject.codeplex.com/wikipage?title=Dependency%20Injection%20With%20Ninjecthttp://www.codeproject.com/Articles/412383/Dependency-Injection-in-asp-net-mvc-and-webapi-us

当设置正确时,它只是一个为IMyClient创建绑定的问题,NInject将隐式地为您注入它。还有很多其他的注入框架,NInject只是我选择的一个。它们中的每一种都会给你带来实质性的好处,而不是你自己做的任何东西。例如,使用NInject,你可以创建在整个应用中注入单例的绑定,或者为每个请求注入单例的绑定。

在NInject中你可以创建一个像

这样的绑定
Bind<IMyClient>().ToMethod(x => SetupClient(x)).InRequestScope();
private IMyClient SetupClient(IContext context)
{
    string apiKey = ConfigurationManager.AppSettings["ApiKey"];
    var client = new MyClient(apiKey);
    if (Thread.CurrentPrincipal.Identity.IsAuthenticated)
    {
        var identity = Thread.CurrentPrincipal.Identity as ClaimsIdentity;
        var tokenClaim = identity.Claims.First(c => c.Type == ClaimTypes.Sid);
        client.AddCredentials(tokenClaim.Value);
    }
    return client;
}

InRequestScope说NInject应该为每个请求创建一个实例…

https://github.com/ninject/Ninject.Web.Common/wiki/InRequestScope

我认为等效的SimpleInjector是…

https://simpleinjector.codeplex.com/wikipage?title=ObjectLifestyleManagement PerWebRequest

这个问题的答案就像把你的代码改成…

public static void RegisterIoC(IAppBuilder app)
{
    var container = new Container();
    container.RegisterPerWebRequest<IMyClient>(
        () =>
        {
            ...

我通过CRice发布的使用工厂委托的版本解决了这个问题:

ProfileController.cs

[System.Web.Mvc.Authorize]
public class ProfileController : Controller
{
    private readonly IMyClient client;
    public ProfileController(Func<IMyClient> clientFactory)
    {
        client = clientFactory.Invoke();
    }
}

IoCConfig.cs

public class IoCConfig
{
    public static void RegisterIoC(IAppBuilder app)
    {
        // Create the container as usual.
        Container container = new Container();
        // Registering as a factory delegate because we need the user authentication information if any.
        container.RegisterSingle<Func<IMyClient>>(() =>
        {
            string apiKey = ConfigurationManager.AppSettings["ApiKey"];
            var myClient = new MyClient(apiKey);
            if (Thread.CurrentPrincipal.Identity.IsAuthenticated)
            {
                var identity = Thread.CurrentPrincipal.Identity as ClaimsIdentity;
                var tokenClaim = identity.Claims.First(c => c.Type == ClaimTypes.Sid);
                myClient.AddCredentials(tokenClaim.Value);
            }
            return myClient;
        });

        // This is an extension method from the integration package.
        container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
        // This is an extension method from the integration package as well.
        container.RegisterMvcIntegratedFilterProvider();
        container.Verify();
        DependencyResolver.SetResolver(
    new SimpleInjectorDependencyResolver(container));
    }
}