Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asp.net mvc 在Web层之外获取当前主体_Asp.net Mvc_Asp.net Mvc 3_Authentication_Forms Authentication_Iprincipal - Fatal编程技术网

Asp.net mvc 在Web层之外获取当前主体

Asp.net mvc 在Web层之外获取当前主体,asp.net-mvc,asp.net-mvc-3,authentication,forms-authentication,iprincipal,Asp.net Mvc,Asp.net Mvc 3,Authentication,Forms Authentication,Iprincipal,我有以下ntier应用程序:MVC>服务>存储库>域。我正在使用表单身份验证。在MVC层之外使用Thread.CurrentPrincipal获取当前登录的应用程序用户安全吗?还是应该使用HttpContext.Current.user 我问的原因是Thread.CurrentPrincipal似乎存在一些问题,但我谨慎地在MVC层之外添加对System.Web的引用,以防将来需要提供非Web字体端 更新 我一直遵循到目前为止收到的建议,将用户名作为被调用方法的参数的一部分传递到服务中,这导致了

我有以下ntier应用程序:MVC>服务>存储库>域。我正在使用表单身份验证。在MVC层之外使用Thread.CurrentPrincipal获取当前登录的应用程序用户安全吗?还是应该使用HttpContext.Current.user

我问的原因是Thread.CurrentPrincipal似乎存在一些问题,但我谨慎地在MVC层之外添加对System.Web的引用,以防将来需要提供非Web字体端

更新

我一直遵循到目前为止收到的建议,将用户名作为被调用方法的参数的一部分传递到服务中,这导致了我原来问题的改进。我需要能够检查用户是否在我的许多服务和域方法中扮演特定角色。似乎有几种解决方案,只是想知道哪种方法是最好的:

  • 将整个HttpContext.Current.User作为参数传递,而不仅仅是用户名
  • 在我的web层之外调用Thread.CurrentPrincipal并使用它。但如何确保它等于HttpContext.Current.User
  • 坚持按目前的建议输入用户名,然后使用Roles.IsUserInRole。这种方法的问题是,它需要一个对System.Web的引用,我觉得在MVC层之外它是不正确的

  • 您建议我如何继续?

    我也不会这样做,
    HttpContext.Current.User
    特定于您的web层


    为什么不将用户名注入您的服务层?

    您应该抽象您的用户信息,以便它不依赖于
    线程.CurrentPrincipal
    HttpContext.Current.user

    例如,您可以添加接受用户名的构造函数或方法参数

    下面是一个过度简化的构造函数参数示例:

    class YourBusinessClass 
    {
       string _userName;
       public YourBusinessClass(string userName)
       {
          _userName = userName;
       }
    
       public void SomeBusinessMethodThatNeedsUserName()
       {
          if (_userName == "sally")
          {
             // do something for sally
          }
       }
    }
    

    将相关用户详细信息映射到新的
    ,以表示LoggedInUser,并将其作为参数传递给业务层方法

     public class LoggedInUser
     {
       public string UserName { set;get;}
       //other relevant proerties
     }
    
    现在设置这个值并传递给BL方法

    var usr=new LoggedInUser();
    usr.UserName="test value ";  //Read from the FormsAuthentication stuff and Set
    var result=YourBusinessLayerClass.SomeOperation(usr);
    
    我更喜欢选项2(在web层之外使用Thread.CurrentPrincipal)。因为这不会影响您的服务层和数据层方法。奖金:您可以在自定义主体中存储您的角色+附加信息

    确保服务和数据层中的Thread.CurrentPrincipal与web层相同;您可以在Global.asax(Application\u AuthenticateRequest)中设置HttpContext.Current.User(Context.User)。在底部添加了其他可以设置此选项的替代位置

    示例代码:

        //sample synchronizing HttpContext.Current.User with Thread.CurrentPrincipal
        protected void Application_AuthenticateRequest(Object sender, EventArgs e)
        {
            HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
    
            //make sure principal is not set for anonymous user/unauthenticated request
            if (authCookie != null && Request.IsAuthenticated)
            {
                FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
    
                //your additional info stored in cookies: multiple roles, privileges, etc
                string userData = authTicket.UserData;
    
                CustomPrincipal userPrincipal = PrincipalHelper.CreatePrincipal(authTicket.Name, authTicket.UserData, Request.IsAuthenticated);
    
                Context.User = userPrincipal;
            }
        }
    
    当然,首先必须实现登录表单,以创建包含自定义主体的授权cookie


    将对服务器的任何请求(css文件、javascript文件、图像文件等)执行应用程序_AuthenticateRequest。要将此功能仅限于控制器操作,可以尝试在ActionFilter中设置自定义主体(我还没有尝试过)。我尝试的是在控制器的拦截器中设置此功能(我使用Castle Windsor进行依赖注入和面向方面的编程)。

    我认为您遇到了这个问题,因为您需要进一步限制您的域责任。您的服务或文档不应负责处理授权。这个责任应该由MVC层来承担,因为当前用户登录的是您的web应用程序,而不是您的域

    如果您没有尝试从您的服务或文档中查找当前用户,而是在MVC应用程序中执行检查,则会得到如下结果:

    if(Roles.IsUserInRole("DocumentEditorRole")){
    
        //UpdateDocument does NOT authorize the user. It does only 1 thing, update the document.
        myDocumentService.UpdateDocument(currentUsername, documentToEdit);
    
    } else {
    
        lblPermissionDenied.InnerText = @"You do not have permission 
                                          to edit this document.";
    
    }
    

    它干净、易于阅读,并允许您保持您的服务和域类不受授权问题的影响。您仍然可以将
    角色.IsUserInRole(“DocumentEditorRole”)
    映射到您的viewmodel,因此唯一丢失的是Document类上的CurrentUserCanEdit方法。但是,如果您认为域模型代表真实世界的对象,那么该方法无论如何都不属于文档。您可能认为它是域用户对象(
    User.CanEditDocument(doc)
    )上的一种方法,但总而言之,我认为如果您将授权排除在域层之外,您会更高兴。

    您的意思是创建我自己的IPrincipal实现吗?在成功登录期间是否会设置此选项?如果是这样,我将如何在业务层中检索它?不,只检索业务层中需要的内容。假设您只需要用户名,您可以执行类似于我在答案中添加的示例的操作。Shyju、Joe R和我基本上都在说同样的话,只给你的业务层它需要的东西。同意,我们真的在说同样的话。:-)所以我认为Thread.CurrentPrincipal不应该被使用是对的?我在域对象(如CanEdit)上有许多方法,这些方法会对此进行检查,以确保用户经过身份验证。这工作得很好,因为我可以自动将结果映射到Viewmodel上的bool。如果从我的域中删除Thread.CurrentPrincipal,我似乎需要做一些大的更改!因此,我可以将HttpContext.Current.User注入到我的服务中,而该服务在ctor中接受IPrincipal?将通过HttpContext.Current.User填充的用户名传递到服务层。它可以是字符串参数,如果需要更多值,甚至可以是新的对象参数。所以不,不是我的校长。是的,在成功登录后。如果您删除Thread.CurrentPrincipal并使用您自己的POCO,您将拥有更大的灵活性,更改将更容易。另一方面,您必须替换现有代码,这些代码可能适合您相对简单的需求。您必须根据项目动态来决定采取哪条路径,如果您完成后更新页面,这样我们就可以看到它是如何进行的,这将是一件好事。我仍在研究这一点。我面临的问题是,