在多层 Web 应用程序的服务层中引用 Microsoft.AspNet.Identity 是否被认为是不好的做法?

Is it considered bad practice to reference the Microsoft.AspNet.Identity in the service layer of a multi layered web application?

在我的 MVC 应用程序中,我目前在 Application_PostAuthenticateRequest() 方法中设置 Thread.CurrentPrincipal = HttpContext.Current.User,例如

    protected void Application_PostAuthenticateRequest()
    {
        Thread.CurrentPrincipal = HttpContext.Current.User;
    }

这允许我在其他程序集(即服务层)中使用 Thread.CurrentPrincipal。例如:

using System.Security;
using System.Security.Permissions;
using System.Threading;
using Microsoft.AspNet.Identity;

namespace ServiceLayer
{
public class FinancialAccount
{
    public decimal Balance { get; set; }
    public string Owner { get; set; }
}

public class FinancialAccountRepository
{
    public FinancialAccount GetById(int id)
    {
        if (id == 1)
            return new FinancialAccount {Owner = "ac40fe16-1971-4b0d-b4d5-af850d0c2c05", Balance = 40324234};

        return new FinancialAccount {Owner = "3e2d1b43-1c63-4263-8c52-44d050279596", Balance = 100};
    }
}

public class FinancialService
{
    private readonly FinancialAccountRepository _financialAccountRepository;

    public FinancialService()
    {
        _financialAccountRepository = new FinancialAccountRepository();
    }

    [PrincipalPermission(SecurityAction.Demand, Role = Constants.RoleNames.AccountHolder)]
    [PrincipalPermission(SecurityAction.Demand, Role = Constants.RoleNames.BankManager)]
    public string GetFinancialAccountDetails(int accountId)
    {
        FinancialAccount financialAccount = _financialAccountRepository.GetById(accountId);
        ThrowExceptionIfUnauthorized(financialAccount);
        return "The account balance of account: " + accountId + " is " + financialAccount.Balance.ToString("C");
    }

    private void ThrowExceptionIfUnauthorized(FinancialAccount financialAccount)
    {
        if (financialAccount.Owner != Thread.CurrentPrincipal.Identity.GetUserId() && !Thread.CurrentPrincipal.IsInRole(Constants.RoleNames.BankManager))
            throw new SecurityException();
    }
}
}

虽然我有两个问题,但这一切似乎都很完美:

  1. 在PostAuthenticationRequest方法中设置Thread.CurrentPrincipal可以吗?
  2. 在我的服务层引用using Microsoft.AspNet.Identity可以吗?

我需要引用 Microsoft.AspNet.IDentity 的原因是因为 IPrincipal 不包含用户 ID,它只包含用户名。

如果其中任何一个被认为是不好的做法,我该如何解决我当前的问题?

  1. Is it okay to set the Thread.CurrentPrincipal in the PostAuthenticationRequest method?

是的,可以将 Principal 对象 (HttpContext.Current.User) 分配给当前线程。

  1. Is it okay to reference the using Microsoft.AspNet.Identity in my service layer?

虽然您可以访问它,但这不是一个好的做法。

原因是 -

  1. 服务层不应与表示层紧密耦合。
  2. 很难对服务层进行单元测试。

相反,如果您想要在服务层中使用 UserId,则需要将 UserId 作为参数传递。

在您的场景中

您想 return FinancialAccount 而不是字符串值,并让表示层使用 string.Format() 创建文本。

原因是你想维护单一职责原则。换句话说,如果您以后想更改文本这经常发生,您确实想再次接触服务层。

public FinancialAccount GetFinancialAccountDetails(int accountId)
{
   return _financialAccountRepository.GetById(accountId);        
}