在使用实体服务/存储库模式时,在模型中引用System.Web.Security是不好的做法吗?

时间:2014-04-11 15:08:38

标签: c# asp.net entity-framework refactoring

在我的ASP.net网站中,我需要检查登录用户是属于某个角色,还是在我的数据库“UserInstance”表中的字段设置为true。要做到这一点,我可以做到以下几点。

if(Roles.IsUserInRole("Global Admin") 
|| uow.UserInstanceService.GetUserInstance(userId,InstanceId).Admin)
{
 //Do something
}

然而,由于我将要使用此代码,所以很多权限取决于登录用户要么是“全局管理员”还是我的表的字段是真的我不想写出来不断。

我发现的一个解决方案是在“UserInstance”服务中创建一个方法,该方法检查“IsUserAdminOrGlobalAdmin”方法中的两个方法。

 public class UserInstanceService
{
    IRepository<UserInstance> userInstanceRepository;

    public UserInstanceService(IRepository<UserInstance> userInstanceRepository)
    {
        this.userInstanceRepository = userInstanceRepository;
    }

    public UserInstance GetByUserIdAndInstanceId(Guid userId, int instanceId)
    {
       return userInstanceRepository.GetSingle(u => u.UserId == userId && u.InstanceId == instanceId);
    }

   public bool IsUserAdminOrGlobalAdmin(Guid userId,int instanceId)
    {
        bool valid = false;

        if (System.Web.Security.Roles.IsUserInRole("Global Admin"))
            valid = true;

        if (GetByUserIdAndInstanceId(userId, instanceId).Admin)
            valid = true;

        return valid;
    } 
   //Removed rest of methods for readability
}

由于这是商务逻辑,我把这个方法放在我的“UserInstanceService”类中,该类与包含实体上下文的存储库类进行交互。这个服务类驻留在一个单独的Model项目中,所以我不得不添加对System.Web.Security的引用,我不确定这样做是不是很好。我注意到的一件事是我不能为这个方法编写单元测试,因为它依赖于用户登录。

所以我的问题是,在服务中结合HttpContext特定功能(如登录用户角色)是否可以接受?

编辑 - 阅读完答案后,我更改了我的代码,以便调用Auth服务(在Web应用程序项目中),然后调用UserInstanceService,就像这样。

public class Auth: IAuthService {

public bool IsUserAdminOrGlobalAdmin(Guid userId,int instanceId) {

    myEntities entityContext = new myEntities

    //RepsitoryBase inherits my IRepository<TEntity> class 
    UserInstanceService uis = new UserInstanceService(new RepositoryBase<UserInstance>(entityContext));
    bool valid = false

    if(Roles.IsUserInRole("Global Admin"))
         valid = true;

    if(uis.GetByUserIdAndInstanceId(userId,instanceId).Admin)
         valid = true;

    return valid;

}

}

所以我可以在我的网页中这样说这个

if(Auth.IsUserAdminOrGlobalAdmin(userId,InstanceId)
{
//Do stuff
}

2 个答案:

答案 0 :(得分:2)

原始答案是在假设UserAccess需要身份验证的情况下编写的,但似乎身份验证使用了UserAccess;简单地反转依赖关系,但其他所有东西都应该以相同的方式使用。


原始答案:

将特定于ASP.NET的代码放入与存储库分开的自己的服务中。然后,该服务(例如,Auth服务)可以被需要访问集中式身份验证/授权逻辑的任何组件(例如UserInstanceService)使用。

Consume the Auth as a dependency per IoC principles,希望使用一些DI来让生活更轻松。

如果Auth服务保持独立,它也可以通过模拟进行测试,例如测试使用是否经过身份验证时会发生什么,这完全避免了为User服务设置完整ASP.NET堆栈的需要。

此外,由于服务(接口)和组件(类)是分开的,因此实用的HTTP利用组件可以存在于与服务不同的项目中并在以后连接 - 这将避免将Web依赖性引入到Model项目中


例如,

// This is the Service Contract and can live in the Model
public class IAuthService {
    void AssertCurrentUserIsAdminOrGlobalAdmin();
    void AssertIsUserAdminOrGlobalAdmin(Guid userId,int instanceId);
}    

// This is the Component, which provides the Service, and is part
// of the Web/HTTP-specific project. It is wired up via IoC/DI from
// the large context of the application.
public class Auth: IAuthService {
    public void AssertCurrentUserIsAdminOrGlobalAdmin() {
       // This one already knows the applicable HTTP/User Context
    }
    public void AssertIsUserAdminOrGlobalAdmin(Guid userId,int instanceId) {
       // Do whatever
    }
}

// This Component is part of the Model
public class UserInstanceService
{
    // IoC dependencies
    IRepository<UserInstance> userInstanceRepository;
    IAuthService authService;
}

答案 1 :(得分:0)

您可以在线程上设置当前主体并使用它。我认为这也是ASP.Net为您所做的大部分工作。