在多层 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();
}
}
}
虽然我有两个问题,但这一切似乎都很完美:
- 在PostAuthenticationRequest方法中设置Thread.CurrentPrincipal可以吗?
- 在我的服务层引用using Microsoft.AspNet.Identity可以吗?
我需要引用 Microsoft.AspNet.IDentity 的原因是因为 IPrincipal 不包含用户 ID,它只包含用户名。
如果其中任何一个被认为是不好的做法,我该如何解决我当前的问题?
- Is it okay to set the Thread.CurrentPrincipal in the PostAuthenticationRequest method?
是的,可以将 Principal 对象 (HttpContext.Current.User) 分配给当前线程。
- Is it okay to reference the using Microsoft.AspNet.Identity in my service layer?
虽然您可以访问它,但这不是一个好的做法。
原因是 -
- 服务层不应与表示层紧密耦合。
- 很难对服务层进行单元测试。
相反,如果您想要在服务层中使用 UserId,则需要将 UserId 作为参数传递。
在您的场景中
您想 return FinancialAccount 而不是字符串值,并让表示层使用 string.Format()
创建文本。
原因是你想维护单一职责原则。换句话说,如果您以后想更改文本这经常发生,您确实想再次接触服务层。
public FinancialAccount GetFinancialAccountDetails(int accountId)
{
return _financialAccountRepository.GetById(accountId);
}
在我的 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();
}
}
}
虽然我有两个问题,但这一切似乎都很完美:
- 在PostAuthenticationRequest方法中设置Thread.CurrentPrincipal可以吗?
- 在我的服务层引用using Microsoft.AspNet.Identity可以吗?
我需要引用 Microsoft.AspNet.IDentity 的原因是因为 IPrincipal 不包含用户 ID,它只包含用户名。
如果其中任何一个被认为是不好的做法,我该如何解决我当前的问题?
- Is it okay to set the Thread.CurrentPrincipal in the PostAuthenticationRequest method?
是的,可以将 Principal 对象 (HttpContext.Current.User) 分配给当前线程。
- Is it okay to reference the using Microsoft.AspNet.Identity in my service layer?
虽然您可以访问它,但这不是一个好的做法。
原因是 -
- 服务层不应与表示层紧密耦合。
- 很难对服务层进行单元测试。
相反,如果您想要在服务层中使用 UserId,则需要将 UserId 作为参数传递。
在您的场景中
您想 return FinancialAccount 而不是字符串值,并让表示层使用 string.Format()
创建文本。
原因是你想维护单一职责原则。换句话说,如果您以后想更改文本这经常发生,您确实想再次接触服务层。
public FinancialAccount GetFinancialAccountDetails(int accountId)
{
return _financialAccountRepository.GetById(accountId);
}