簡體   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