如何在 ASP.NET MVC 中实现自定义主体和身份?

Posted

技术标签:

【中文标题】如何在 ASP.NET MVC 中实现自定义主体和身份?【英文标题】:How do I implement custom Principal and Identity in ASP.NET MVC? 【发布时间】:2011-03-17 11:30:25 【问题描述】:

我想在经过身份验证的用户中存储额外的信息,以便我可以轻松访问它(例如 User.Identity.Id),而不仅仅是名称,因为我打算让那个非唯一的.

到目前为止,我已经收集到我应该寻求实现自定义主体和/或身份,但我不确定如何去做。我一直在寻找有关此事的文档和教程,但我在不同的地方找到了相关的东西,我发现它有点混乱。

我已经看到了如何在用户数据属性中将自定义信息添加到身份验证 cookie,但我希望在单元测试中获得依赖注入的好处,我可以通过主体和身份来获得。

如果我想实现自己的 Principal 或 Identity,我需要考虑哪些确切步骤?

在这种情况下我能做的最简单的事情是什么(只需添加 ID 并保留所有默认值)? “默认值”将包括默认提供者(成员资格、角色等)。

我已经看到了other question,但我希望答案不会在两者之间留下任何漏洞,例如示例中 AuthenticateRequest 事件中的角色魔术字符串。相反,我需要知道如何将默认 SqlRoleProvider 中的角色添加到当前用户:何时何地执行此操作,以及是否需要执行其他任何操作来将我的新类与其他默认提供程序连接起来。

如果能够转到示例 ASP.NET MVC 2 应用程序(例如,来自 Visual Studio 2010 模板),进行编辑并让它工作,那就太棒了。


编辑:我已经编辑了这个问题,以更好地表明我在这里迷路,所以我不能凑合答案水平太高。

P.S.:在我看来,在身份中使用 ID 而不是在主体中使用 ID 更有意义,尽管我之前在某种程度上说过。

【问题讨论】:

您目前是否已设置并运行表单身份验证和角色? 我愿意。我从 VS 2010 模板中的 MVC Web 应用程序(与 MVC Empty Web 应用程序相反)开始,因此它具有用于用户管理的所有默认 SQL 提供程序:包括成员资格和角色。但大部分都是在幕后完成的。按照惯例,因为它是 你不能只使用 Profile 支持来处理这种事情吗?这就是它的用途(与用户关联的额外数据) - 应该比我认为的“自定义用户”更简单 确实,但我想将它放在某种会话变量中,而不是每次都从存储中获取它。此外,除了身份验证 cookie UserInfo(这是我用作解决方法的方法)之外,我还想要一些可以与依赖注入一起进行测试的东西,比如 hanselman 所做的 hanselman.com/blog/… 【参考方案1】:

这个问题已经被问过并回答过: ASP.NET MVC - Set custom IIdentity or IPrincipal

但是总结一下……

使用您要存储的其他属性创建一个自定义主体类:

Public Class CustomPrincipal
    Inherits System.Security.Principal.GenericPrincipal

    Private _eyeColor As String
    Public ReadOnly Property EyeColor As String
        Get
            Return _eyeColor
        End Get
    End Property

    Public Sub New(id As System.Security.Principal.IIdentity, roles As String(), eyeColor As String)
        MyBase.New(id, roles)
        _eyeColor = eyeColor            
    End Sub

End Class

修改 global.asax Global.Application_AuthenticateRequest 以使用您的自定义主体:

Protected Sub Application_AuthenticateRequest(ByVal sender As Object, ByVal e As System.EventArgs)
    ...
    Dim roles() As String = "examplerole"         
    Context.User = new CustomPrincipal(Context.User.Identity, roles, "green")
End Sub

然后,当您想在代码的其他地方引用这些属性之一时,请执行以下操作:

CType(My.User.CurrentPrincipal, CustomPrincipal).EyeColor

【讨论】:

Seth - 你从哪里得到“绿色”?您是否在每个 Application_AuthenticateRequest 从数据库中检索它?您是否将其存储在会话变量中? @mga911 - 在这个例子中,“绿色”是硬编码的。在一个真正的网络应用程序中,我会从数据库中读取它,并可能将它存储在一个 cookie 中。在对 AuthenticateRequest 的其他调用中,可以从 cookie 中读取它以防止 db 调用。会话变量在这里不是一个选项,因为 AuthenticateRequest 在 SessionStart 之前被调用。【参考方案2】:

你不能真的指望有人能用几段话教你所有你不知道的关于 .NET 的知识。您可以在 MSDN http://msdn.microsoft.com/en-us/library/system.security.principal.genericprincipal.aspx 上阅读相当不错的示例,并深入研究该类及其在 Reflector 中的派生类——它并没有什么特别之处。

角色只是您自己使用的名称的字符串数组,在您的应用程序/服务器中。

话虽如此,您根本不必针对精确的 GenericPrincipal 导数。看看

HttpContext.Current.Items

它是一个 Hashtable,仅供您服务的请求免费使用 - 这意味着您可以在某一时刻说:

HttpContext.Current.Items["TokenUser"] = new MyThinUser(anything,I,want,there);

然后代码中的其他所有内容都可以:

var user = HttpContext.Current.Items["TokenUser"] as MyThinUser;

你就完成了。

在您的新类中存储您需要/想要从身份验证代码传递到所有其他功能的所有内容。保留 User 属性不变(这样您就可以窥视它,而不必担心您更改了某些内容)。你可以随意简化或复杂化你的系统,但你可以保持完全的独立性。

例如,如果您有自己的身份验证并且只有几个级别的访问权限而不是枚举角色,那么您可以只携带良好的旧访问级别编号(无论如何,作为字符串携带的枚举角色效率非常低)。

请记住,VS 中的自动生成样本通常适用于某些特定场景。因此,如果您看到用于用户管理的 SQL 提供程序并不意味着您实际上必须使用它 - 您仍然可以调用自己的 sproc 来从您自己的 SQL 表中获取所需的内容。

【讨论】:

这是一个有趣的方法。

以上是关于如何在 ASP.NET MVC 中实现自定义主体和身份?的主要内容,如果未能解决你的问题,请参考以下文章

在 ASP.NET 5 (vNext) MVC 6 中实现自定义路由器

如何在 ASP.NET Core 中实现自定义模型验证?

在 MVC 中实现自定义身份和 IPrincipal

如何在 WCF 服务中实现自定义身份验证

如何在ASP.NET MVC中实现报表打印和导出

如何使用trackerenableddbcontext在asp.net mvc5和代码中的实体框架中实现审计跟踪