【问题标题】:Is it considered bad practice to reference the Microsoft.AspNet.Identity in the service layer of a multi layered web application?在多层 Web 应用程序的服务层中引用 Microsoft.AspNet.Identity 是否被认为是不好的做法?
【发布时间】:2015-06-03 12:02:00
【问题描述】:

在我的 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. 可以在我的服务层引用使用 Microsoft.AspNet.Identity 吗?

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

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

【问题讨论】:

    标签: c# asp.net asp.net-mvc security asp.net-identity


    【解决方案1】:
    1. 可以在 PostAuthenticationRequest 方法中设置 Thread.CurrentPrincipal 吗?

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

    1. 可以在我的服务层引用 using Microsoft.AspNet.Identity 吗?

    这不是一个好习惯,尽管您可以访问它。

    原因是——

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

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

    在您的场景中

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

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

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

    【讨论】:

    • 你已经基本证实了我的想法。我只是不喜欢当我已经可以访问 Thread.CurrentPrincipal.Identity 时必须将用户 ID 作为参数传递的想法。为什么 IIdentity 有用户名但没有用户 ID?在登录过程中添加 UserId 作为声明会更好吗,如下面的示例所示:stackoverflow.com/questions/22246538/…
    • 我同意返回对象而不是字符串。这只是我快速创建的代码来帮助说明我的问题。
    • Why does IIdentity have a username but not the userid? 在 ASP.Net Identity 中,您使用 User.Identity.GetUserId() 获取控制器内部的 userId。
    • 是的,但这就是我的全部问题。如果我不引用 ASP.Net Identity 程序集,即因为它们是扩展方法,这在我的服务层不可用。
    • 您推荐的方法是将签名更改为:public FinancialAccount GetFinancialAccountDetails(int accountId, string userId)?
    猜你喜欢
    • 2016-02-19
    • 2021-10-27
    • 1970-01-01
    • 2011-05-18
    • 1970-01-01
    • 2013-04-12
    • 2018-08-11
    • 1970-01-01
    相关资源
    最近更新 更多