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



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

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

网页 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 控制器使用会话状态。使用 Web API 访问会话 ASP.NET

抽象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之间的 depenity,并且可以轻松地替换另一种类型或模拟。

我从尼古拉和布伦特那里得到了很多帮助,并通过他们发布的答案获得了大部分时间,但最终我自己找到了完整的答案。 我遇到的问题与无法访问 WebAPI 中的会话变量有关。 所以,我确信有更干净的解决方案,但我肯定改进了我所拥有的并提出了以下代码,它有效。

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

全球.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"] = "";
    }
}

统一配置

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);
    }
}

网页 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; }
}

相关内容

  • 没有找到相关文章