确定AuthorizeAttribute是在Class级别还是Method级别

时间:2015-09-30 20:02:29

标签: asp.net-mvc vb.net

我正在创建自定义AuthorizeAttribute,如果当前属性已在类(控制器)级别或方法(操作)中声明,我想检查自定义AuthorizeAttribute的New()方法内部水平。

我的控制器:

<CustomAuthorization>
Public Class SeomController
...
    <CustomAuthorization>
    Function Index() As ActionResult

我的CustomAuthorizationAttribute:

Public Sub New()
    ' Determine if we're at Controller level or Action level

2 个答案:

答案 0 :(得分:2)

属性do not (or at least they should not) have any behavior,因此不建议创建自我感知属性。

但是,如果您在链接文章中采用该方法,则可以创建一个全局IAuthorizationFilter来确定您的属性的注册位置。

CustomAuthorizationAttribute

首先,你需要一个愚蠢的&#34;授权属性只是一个属性(不是AuthorizeAttribute子类)来标记您的控制器和操作。它足够聪明,可以收集元数据并将其拆分为数组以便于访问,但就是这样。

<AttributeUsage(AttributeTargets.[Class] Or AttributeTargets.Method, Inherited := True)> _
Public Class CustomAuthorizationAttribute
    Inherits Attribute
    Private m_users As String
    Private m_usersSplit As String()
    Private m_roles As String
    Private m_rolesSplit As String()

    Public Property Users() As String
        Get
            Return Me.m_users
        End Get
        Set
            Me.m_users = value
            Me.m_usersSplit = SplitString(value)
        End Set
    End Property

    Public Property Roles() As String
        Get
            Return Me.m_roles
        End Get
        Set
            Me.m_roles = value
            Me.m_rolesSplit = SplitString(value)
        End Set
    End Property

    Friend ReadOnly Property UsersSplit() As String()
        Get
            Return Me.m_usersSplit
        End Get
    End Property

    Friend ReadOnly Property RolesSplit() As String()
        Get
            Return Me.m_rolesSplit
        End Get
    End Property

    Friend Shared Function SplitString(original As String) As String()
        If String.IsNullOrEmpty(original) Then
            Return New String(-1) {}
        End If
        Return (From piece In original.Split(New Char() {","C})Let trimmed = piece.Trim() Where Not String.IsNullOrEmpty(trimmed)trimmed).ToArray(Of String)()
    End Function
End Class

CustomAuthorizationFilter

要确定属性的位置,可以继承AuthorizeAttribute(实现IAuthorizationFilter),然后为其添加一些逻辑以确定属性的注册位置。

通常,您应该覆盖AuthorizeCore方法并返回true或false以指示用户是否已获得授权,这就是我显示决策逻辑的位置。

Public Class CustomAuthorizationFilter
    Inherits AuthorizeAttribute
    Private Enum Level
        Action
        Controller
    End Enum

    Private Function GetCustomAuthorizationAttribute(actionDescriptor As ActionDescriptor, ByRef registeredLevel As Level) As CustomAuthorizationAttribute
        Dim result As CustomAuthorizationAttribute = Nothing

        ' Check if the attribute exists on the action method
        result = DirectCast(actionDescriptor.GetCustomAttributes(attributeType := GetType(CustomAuthorizationAttribute), inherit := True).SingleOrDefault(), CustomAuthorizationAttribute)

        If result IsNot Nothing Then
            registeredLevel = Level.Action
            Return result
        End If

        ' Check if the attribute exists on the controller
        result = DirectCast(actionDescriptor.ControllerDescriptor.GetCustomAttributes(attributeType := GetType(CustomAuthorizationAttribute), inherit := True).SingleOrDefault(), CustomAuthorizationAttribute)

        registeredLevel = Level.Controller
        Return result
    End Function

    Protected Overrides Function AuthorizeCore(httpContext As HttpContextBase) As Boolean
        Dim actionDescriptor = TryCast(httpContext.Items("ActionDescriptor"), ActionDescriptor)
        If actionDescriptor IsNot Nothing Then
            Dim registeredLevel As Level
            Dim authorizeAttribute = Me.GetCustomAuthorizationAttribute(actionDescriptor, registeredLevel)

            ' If the authorization attribute exists
            If authorizeAttribute IsNot Nothing Then
                If registeredLevel = Level.Action Then
                        ' Attribute is registered on an action
                        ' Implement user and role checking logic using
                        '
                        ' authorizeAttribute.RolesSplit
                        ' authorizeAttribute.UsersSplit
                ElseIf registeredLevel = Level.Controller Then
                        ' Attribute is registered on a controller
                        ' Implement user and role checking logic using
                        '
                        ' authorizeAttribute.RolesSplit
                        ' authorizeAttribute.UsersSplit
                End If
            End If
        End If

        Return True
    End Function

    Public Overrides Sub OnAuthorization(filterContext As AuthorizationContext)
        ' Pass the current action descriptor to the AuthorizeCore
        ' method on the same thread by using HttpContext.Items
        filterContext.HttpContext.Items("ActionDescriptor") = filterContext.ActionDescriptor
        MyBase.OnAuthorization(filterContext)
    End Sub
End Class

用法

全局注册您的CustomAuthorizationFilter,以便它可以检测您的属性所在位置(并运行任何其他授权逻辑)。

Public Class FilterConfig
    Public Shared Sub RegisterGlobalFilters(ByVal filters As GlobalFilterCollection)
        filters.Add(New CustomAuthorizationFilter())
        filters.Add(New HandleErrorAttribute())
    End Sub
End Class

然后正常装饰你的控制器和动作。

<CustomAuthorization>
Public Class SeomController
...
    <CustomAuthorization>
    Function Index() As ActionResult

答案 1 :(得分:1)

这不是你问题的答案,但可能是另一种选择。

将属性添加到自定义属性类

Public Enum Levels
    Controller
    Action
End Enum

Public Class CustomAttributes
    Public Class CustomAuthorize
        Inherits System.Web.Mvc.AuthorizeAttribute
        Private _level As Levels
        Public Property Level() As Levels
            Get
                Return _level
            End Get
            Set(ByVal value As Levels)
                _level = value
            End Set
        End Property
        Protected Overrides Function AuthorizeCore(httpContext As HttpContextBase) As Boolean
            If (_level = Levels.Controller) Then
                'Controller Level
            End If
            Return MyBase.AuthorizeCore(httpContext)
        End Function
    End Class
End Class

然后您可以在添加属性时指明属性的分配位置。

<CustomAttributes.CustomAuthorize(Level:=Levels.Controller)>
Public Class AccountController

    <CustomAttributes.CustomAuthorize(Level:=Levels.Action)>
    Public Function Login(returnUrl As String) As ActionResult
        ViewBag.ReturnUrl = returnUrl
        Return View()
    End Function