Ninject UOW pattern, new ConnectionString after user is authenticated

人走茶凉 提交于 2019-12-11 12:15:42

问题


I wonder if any one can point me in the right direction?

I am using the UOW repository pattern and have my dependencies injected via Ninject. I have a UnitOfWorkMapping class which inherits from NinjectModule, which I use to bind my IUnitOfWork to a concrete implementation of Dbcontext, see below

public class UnitOfWorkMapping : NinjectModule
{
    public override void Load()
    {
        Bind<IUnitOfWork>()
            .To<WebsiteDbContext>()
            .InRequestScope()
            .WithConstructorArgument(
                "connectionString",
                ConfigurationManager.ConnectionStrings[ConnectionStringKeys.UnauthorisedUser]
                    .ConnectionString);

        // Objects that explicitly need a DB context for the life of the request
        Bind<IUnitOfWorkInRequestScope>()
            .To<WebsiteDbContext>()
            .InRequestScope()
            .WithConstructorArgument(
                "connectionString",
                ConfigurationManager.ConnectionStrings[ConnectionStringKeys.UnauthorisedUser]
                    .ConnectionString);

        // Objects that specificall need a DB context for the life of the application
        Bind<IUnitOfWorkInApplicationScope>()
            .To<WebsiteDbContext>()
            .InSingletonScope()
            .WithConstructorArgument(
                "connectionString",
                ConfigurationManager.ConnectionStrings[ConnectionStringKeys.UnauthorisedUser]
                    .ConnectionString);
    }
}

So this gets called when the application starts and provides my site user with a context for an unauthorised user. This context has a database connection which connects to a database User which has limited access to the database objects.

Once the user has logged in to site I would like to switch to another connection which will give the context access to a Database user with wider access to the database objects.

So by the time the code execution reaches the true condition block for "if (Request.IsAuthenticated)" it is already using the "authorised" database connection for the context.

    /// <summary>
    /// Handles the PostAuthenticateRequest event of the Application control.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
    protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
    {
        String[] roles;
        var applicationConfiguration =
            (IApplicationConfiguration)
                DependencyResolver.Current.GetService(typeof(IApplicationConfiguration));
        var identity = HttpContext.Current.User.Identity;
        if (Request.IsAuthenticated)
        {
            var roleRepository =
                (IRoleRepository)DependencyResolver.Current.GetService(typeof(IRoleRepository));
            roles = roleRepository.GetRolesForUser(identity.Name);
        }
        else
        {
            roles = new[] { applicationConfiguration.UnknownUserRoleName };
        }
        var webIdentity = new WebIdentity(identity, roles);
        var principal = new WebsitePrincipal(webIdentity)
        {
            ApplicationConfiguration = applicationConfiguration
        };

        HttpContext.Current.User = principal;
    }

I haven't been able to find a code example on the net that is close enough to my code to adapt and implement. Please can any one advise? Thank you in advance.

A link to the complete code can be provided if required.

Solution: Ok, so with the tireless help of Erik we have got there. The solution I am using is as so..

public class UnitOfWorkMapping : NinjectModule
{
    public override void Load()
    {
        // Bind the IUnitOfWork for a user that is not logged in.
        Bind<IUnitOfWork>()
            .To<WebsiteDbContext>()
            .When(request => IsUserAuthenticated(request))
            .WithConstructorArgument(
                "connectionString", ConfigurationManager.ConnectionStrings[ConnectionStringKeys.MainUserConnectionString]
                    .ConnectionString);

        // Bind the IUnitOfWork for a user that is not logged in.
        Bind<IUnitOfWork>()
            .To<WebsiteDbContext>()
            .When(request => !IsUserAuthenticated(request))
            .WithConstructorArgument(
                "connectionString", ConfigurationManager.ConnectionStrings[ConnectionStringKeys.UnauthorisedUser]
                    .ConnectionString);

    }

    /// <summary>
    /// Determines if the user authenticated.
    /// </summary>
    /// <param name="request">The Ninject Activation request.</param>
    /// <returns>
    /// returns <c>true</c> if the user exists and is authenticated
    /// </returns>
    public Boolean IsUserAuthenticated(IRequest request)
    {
        return (
            (HttpContext.Current.User != null) &&
            HttpContext.Current.User.Identity.IsAuthenticated);
    }
}

I hope that helps someone not spend days trying to get to the bottom of this issue.


回答1:


If you want to use different bindings for whether a user is logged in or out, it's very simple.

Bind<IUnitOfWork>()
   .To<WebsiteDbContext>()
   .When(x => !HttpContext.Current.Request.IsAuthenticated)
   .InRequestScope()
   .WithConstructorArgument(
       "connectionString",
        ConfigurationManager.ConnectionStrings[ConnectionStringKeys.UnauthorisedUser]
           .ConnectionString);

Bind<IUnitOfWork>()
    .To<WebsiteDbContext>()
    .When(x => HttpContext.Current.Request.IsAuthenticated)
    .InRequestScope()
    .WithConstructorArgument(
        "connectionString",
        ConfigurationManager.ConnectionStrings[ConnectionStringKeys.AuthorisedUser]
           .ConnectionString);

Note that these both have the same IUnitOfWork binding, it will simply return the correct one based on whether the user is logged in or not.

I would also do this:

Bind<IIdentity>()
    .To<WebIdentity>()
     ...

Bind<IIdentity>()
    .ToMethod(x => HttpContext.Current.User.Identity)
    .WhenInjectedInto(typeof(WebIdentity))
    ...

Bind<IPrincipal>()
    .To<WebsitePrincipal>()
    ...

Then, configure your WebsitePrincipal's constructor to take IIdentity and IApplicationConfiguration parameters, make WebIdentity's constructor take IIdentity and IRoleRepository as parameters (note the .WhenInjectedInto uses the existing Identity). Have your constructors do the work.

Then you need only write the following (DI takes care of the rest):

protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
    HttpContext.Current.User = DependencyResolver.Current.GetService(typeof(IPrincipal));
}


来源:https://stackoverflow.com/questions/23641883/ninject-uow-pattern-new-connectionstring-after-user-is-authenticated

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!