繁体   English   中英

MVC获取/模拟存储库中的Windows用户

[英]MVC Get/Impersonate Windows User In Repository

我有一个使用Windows用户名并将其传递给过程以返回数据的Intranet应用程序。

  1. 我正在使用依赖项注入,但是我不相信有办法正确分离用户名。
  2. 我试图通过不传递用户名作为参数来确保这一点的安全,但是我也希望能够模拟(或绕过我的GetWindowsUser()方法)并发送另一个用户名,以便为其他用户测试结果。
    • 我的一个想法是在另一个页面中使用另一个(模拟的)用户名设置会话变量,然后在获取实际用户名之前先检查该会话变量是否存在,但是我不知道如何访问会话变量在存储库中。

Web API控制器

public class DropDownDataController : ApiController
{
    private IDropDownDataRepository _dropDownDataRepository;        

    //Dependency Injection using Unity.WebAPI NuGet Package
    public DropDownDataController(IDropDownDataRepository dropDownDataRepository)
    {
        _dropDownDataRepository = dropDownDataRepository;
    }

    [HttpGet]
    public HttpResponseMessage MyList()
    {
        try
        {
            return _dropDownDataRepository.MyList();
        }
        catch
        {
            throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
        }
    }
}

仓库

public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
    private DatabaseEntities db = new DatabaseEntities();

    public HttpResponseMessage MyList()
    {
        //(This should be separated somehow, right?) 
        //Create a new instance of the Utility class
        Utility utility = new Utility();
        //Grab the windowsUser from the method
        var windowsUser = utility.GetWindowsUser();

        //Pass windowsUser parameter to the procedure
        var sourceQuery = (from p in db.myProcedure(windowsUser)
                           select p).ToList();

        string result = JsonConvert.SerializeObject(sourceQuery);
        var response = new HttpResponseMessage();
        response.Content = new StringContent(result, System.Text.Encoding.Unicode, "application/json");

        return response;            
    }
}

接口

public interface IDropDownDataRepository : IDisposable
{
    HttpResponseMessage MyList();        
}

实用程序类

public class Utility
{
    public string GetWindowsUser()
    {
        //Get the current windows user
        string windowsUser = HttpContext.Current.User.Identity.Name;        

        return windowsUser;
    }
}

更新1

除了下面的Nikolai和Brendt发表的内容之外,还需要以下内容来允许Web Api控制器使用会话状态。 使用ASP.NET Web API访问会话

提取Utility类并将其注入到存储库中。 然后,您可以存根或模拟进行测试。

public interface IUtility
{
    string GetWindowsUser();
}

public class TestUtility : IUtility
{
    public string GetWindowsUser()
    {
        return "TestUser";
    }
}

public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{

    private IUtility _utility;

    public DropDownDataRepository(IUtility utility)
    {
        _utility = utility;
    }

}

编辑

此外,存储库不应返回HTTPResponseMessage类型,而应仅返回您正在访问的域模型的List<T>

public List<Model> MyList()
{
    //Grab the windowsUser from the method
    var windowsUser = _utility.GetWindowsUser();

    //Pass windowsUser parameter to the procedure
    var sourceQuery = (from p in db.myProcedure(windowsUser)
                       select p).ToList();

    return sourceQuery           
}

然后将JSON部分移至控制器。

我的一个想法是在另一个页面中使用另一个(模拟的)用户名设置会话变量,然后在获取实际用户名之前先检查该会话变量是否存在,但是我不知道如何访问会话变量在存储库中。

潜在地,如果您向会话添加依赖项,则需要隔离它,例如

public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
    // ... other fields

    private ISession session;

    public DropDownDataRepository(ISession session)
    {
        this.session = session;
    }

    public HttpResponseMessage MyList()
    {
         var myUserName = this.session.UserName;
         // ... etc

与ISession类似:

 public interface ISession
 {
      string UserName { get; }
 }

实施为:

 public class MySession : ISession
 {
     public string UserName
     {
         get
         {
            // potentially do some validation and return a sensible default if not present in session
            return HttpContext.Current.Session["UserName"].ToString();
         }
     }

 }

当然,如果需要,可以将MySession类与HttpContext分离。


关于此:

    //(This should be separated somehow, right?) 
    //Create a new instance of the Utility class
    Utility utility = new Utility();

是的,无论何时创建new对象,您都将它们紧密地耦合在一起,这会给您带来问题,例如,如果您尝试对它进行单元测试。

在这种情况下,您可以从Utility提取IUtility接口:

public class Utility : IUtility
{
    string GetWindowsUser();
}

然后:

public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
    // ... other fields

    private IUtility utility;

    public DropDownDataRepository(IUtility utility)
    {
        this.utility = utility;
        // .... etc

然后,您已删除了UtilityDropDownDataRepository之间的依赖关系,并且可以轻松替换为其他类型或模拟。

我从尼古拉(Nikolai)和布伦特(Brent)那里得到了很多帮助,并且在他们发布的答案中得到了大部分帮助,但是最终我自己弄清了完整答案。 我遇到的问题与无法访问WebAPI中的会话变量有关。 因此,我确定对此有更清洁的解决方案,但是我绝对可以改善自己的工作,并提出了以下有效的代码。

需要此答案才能允许访问Web Api中的会话变量- 使用ASP.NET Web API访问会话

GLOBAL.asax.cs

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        GlobalConfiguration.Configure(WebApiConfig.Register);
        UnityConfig.RegisterComponents();
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }

    //Added to allow use of session state in Web API
    protected void Application_PostAuthorizeRequest()
    {
        if (IsWebApiRequest())
        {
            HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
        }
    }

    //Added to allow use of session state in Web API
    private bool IsWebApiRequest()
    {
        return HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.StartsWith(WebApiConfig.UrlPrefixRelative);
    }

    protected void Session_Start(Object sender, EventArgs e)
    {
        //Default set the session variable to none
        Session["_impersonatedUser"] = "none";
    }

    protected void Session_End(Object sender, EventArgs e)
    {
        //Reset the session variable to blank
        Session["_impersonatedUser"] = "";
    }
}

UNITY.config

public static class UnityConfig
{
    public static void RegisterComponents()
    {
        var container = new UnityContainer();

        // register all your components with the container here
        // it is NOT necessary to register your controllers

        // e.g. container.RegisterType<ITestService, TestService>();


        container.RegisterType<IDropDownDataRepository, DropDownDataRepository>();
        container.RegisterType<IUtilityRepository, UtilityRepository>();
        container.RegisterType<ISessionRepository, SessionRepository>();

        //MVC5
        //Unity.MVC5 NuGet Package
        DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));

        //WEB API 
        //Unity.WebApi NuGet Package
        GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
    }
}

Web API控制器

public class DropDownDataController : ApiController
{
    private IDropDownDataRepository _dropDownDataRepository;      

    //Dependency Injection using Unity.WebAPI NuGet Package
    public DropDownDataController(IDropDownDataRepository dropDownDataRepository)
    {
        _dropDownDataRepository = dropDownDataRepository;
    }

    [HttpGet]
    public HttpResponseMessage MyList()
    {
        try
        {
            var sourceQuery = _dropDownDataRepository.MyList();

            //JSON stuff moved to controller
            string result = JsonConvert.SerializeObject(sourceQuery);
            var response = new HttpResponseMessage();
            response.Content = new StringContent(result, System.Text.Encoding.Unicode, "application/json");

            return response;
        }
        catch
        {
            throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
        }
    }

    protected override void Dispose(bool disposing)
    {
        _dropDownDataRepository.Dispose();
        base.Dispose(disposing);
    }
}

下拉数据存储库

public class DropDownDataRepository : IDropDownDataRepository, IDisposable
{
    private DatabaseEntities db = new DatabaseEntities();
    private IUtilityRepository _utilityRepository;
    private ISessionRepository _sessionRepository;

    //Dependency Injection of Utility and Session
    public DropDownDataRepository(IUtilityRepository utilityRepository, ISessionRepository sessionRepository)
    {
        _utilityRepository = utilityRepository;
        _sessionRepository = sessionRepository;
    }

    //Changed to a list here
    public List<MyProcedure> MyList()
    {
        string windowsUser;
        //Check the session variable to see if a user is being impersonated
        string impersonatedUser = _sessionRepository.ImpersonatedUser;

        //Grab the windowsUser from the Utility Repository
        windowsUser = _utilityRepository.GetWindowsUser();

        if (impersonatedUser != "none")
        {
            windowsUser = impersonatedUser;
        }        

        //Pass windowsUser parameter to the procedure
        var sourceQuery = (from p in db.MyProcedure(windowsUser)
                           select p).ToList();

        return sourceQuery;            
    }

    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                db.Dispose();
            }
        }
        this.disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

下拉数据接口

public interface IDropDownDataRepository : IDisposable
{
    //Changed to list here
    List<MyProcedure> MyList();
}

实用程序存放区

public class UtilityRepository : IUtilityRepository
{
    public string GetWindowsUser()
    {
        //Get the current windows user
        string windowsUser = HttpContext.Current.User.Identity.Name;

        return windowsUser;
    }
}

实用界面

public interface IUtilityRepository
{
    string GetWindowsUser();
}

会话存储库

 public class SessionRepository : ISessionRepository
{
    public string ImpersonatedUser
    {
        get
        {
            return HttpContext.Current.Session["_impersonatedUser"].ToString();
        }
    }
}

会话界面

public interface ISessionRepository
{
    string ImpersonatedUser { get; }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM