ASP.NET成员身份登录在用户登录时重定向到未授权

时间:2016-07-28 15:12:50

标签: asp.net vb.net asp.net-mvc-5 asp.net-membership membership-provider

我们有一个使用ASP.net Membership的应用程序来提供基本的登录机制。一切正常,但最近我们发现,如果您在登录时尝试访问登录页面,则会被重定向到“未授权”状态。页。

  

示例用户流程。

     

用户进入安全页面(整个应用程序需要登录,那里有   甚至没有你可以访问的主页,只需重定向直接登录)。   这会将它们重定向到https://www.example.com/Account/Login

     

用户登录并重定向到主页https://www.example.com/。   他们已登录,一切正常。

     

用户点击恰好设置为的书签   https://www.example.com/Account/Login

     

用户被重定向到通用的未授权页面。

我的AccountController上有<Authorize()>属性,但是&#39;登录&#39;上的<AllowAnonymous()>属性。正如我们之前看到的那样,当你没有登录时,它可以正常工作,但是当你遇到这种情况时,似乎会陷入困境。

的AccountController

<Authorize()> _
Public Class AccountController
'''other functions go here'''

<AllowAnonymous()> _
Public Function Login(ByVal returnUrl As String) As ActionResult
    ViewData("ReturnUrl") = returnUrl
    Return View()
End Function

授权重定向过滤器

<AttributeUsage(AttributeTargets.[Class] Or AttributeTargets.Method)> _
Public Class AuthorizeRedirect
    Inherits AuthorizeAttribute
    Private Const IS_AUTHORIZED As String = "isAuthorized"

    Public RedirectUrl As String = "~/Home/Unauthorized"

    Protected Overrides Function AuthorizeCore(httpContext As System.Web.HttpContextBase) As Boolean
        Dim isAuthorized As Boolean = MyBase.AuthorizeCore(httpContext)

        httpContext.Items.Add(IS_AUTHORIZED, isAuthorized)

        Return isAuthorized
    End Function

    Public Overrides Sub OnAuthorization(filterContext As AuthorizationContext)
        MyBase.OnAuthorization(filterContext)

        Dim isAuthorized = If(filterContext.HttpContext.Items(IS_AUTHORIZED) IsNot Nothing, Convert.ToBoolean(filterContext.HttpContext.Items(IS_AUTHORIZED)), False)

        If Not isAuthorized AndAlso filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated Then
            filterContext.RequestContext.HttpContext.Response.Redirect(RedirectUrl)
        End If
    End Sub
End Class

看到这一切,我认为最简单的解决方案是检查用户是否已登录我的登录操作并将其自行重定向,如下所示。

<AllowAnonymous()> _
Public Function Login(ByVal returnUrl As String) As ActionResult
    If User.Identity.IsAuthenticated() Then
        Return RedirectToAction("Index", "Home")
    End If
    ViewData("ReturnUrl") = returnUrl
    Return View()
End Function

但是AuthorizeFilter总是首先跳进去,这是可以理解的,但我无法弄清楚最后一个缺失的部分。我想要的只是不显示“你没有权限查看此页面”#39;如果用户在登录时进入登录屏幕,而是将其重定向到主页。我错过了什么?

编辑以使事情更清晰

登录后,我转到/Account/Login。这个302会将我重定向到/Home/Unauthorized(我的自定义页面)。但是,我仍然登录。

网络请求

Network request to Login page, which 302 redirects to Unauthorized

未经授权的网页。请注意突出显示的黄色部分显示我仍然登录。只有在您登录时才会显示。如果您没有登录,则不会获得任何内容。

Unauthorized page

问题似乎是当我已经登录并尝试转到其上具有[AllowAnonymous]属性的页面时,应用程序不知道该怎么做。如果有的话,我在这里看到的行为比它实际上再次给我一个登录页面更可取,因为这会令人困惑,但仍然不理想。

编辑2 - 逐行逐步执行代码

以下是逐行逐步执行代码的结果。

登录时

页面/Account/Login

OnAuthorization过滤器AuthorizeRedirect中的第一个断点。

Public Overrides Sub OnAuthorization(filterContext As AuthorizationContext)
    MyBase.OnAuthorization(filterContext)

    Dim isAuthorized = If(filterContext.HttpContext.Items(IS_AUTHORIZED) IsNot Nothing, Convert.ToBoolean(filterContext.HttpContext.Items(IS_AUTHORIZED)), False)

    If Not isAuthorized AndAlso  filterContext.RequestContext.HttpContext.User.Identity.IsAuthenticated Then
        filterContext.RequestContext.HttpContext.Response.Redirect(RedirectUrl)
    End If
End Sub

Dim isAuthorized开头的行返回False。 filterContext.HttpContext.Items(IS_AUTHORIZED)没什么(项目列表中不存在)。

这意味着下一个If语句的计算结果为True(Not isAuthorized AndAlso ... IsAuthenticated),导致重定向到RedirectUrl

在这种情况发生之后,它似乎会回到相同的步骤,除非这次评估为假,这意味着重定向不会发生,尽管我猜测这只是“未经授权的”&#39 #39;页面加载并再次运行相同的代码。

我尝试将以下块添加到Login的{​​{1}}函数的顶部。

AccountController

但是,当然,由于过滤器是在操作发生之前运行的,因此在 之后它已被重定向到 If User.Identity.IsAuthenticated() Then Return RedirectToAction("Index", "Home") End If (已验证)逐步完成。

1 个答案:

答案 0 :(得分:2)

AuthorizationAttribute的基类在其OnAuthorization方法中包含此代码:

bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true)
                         || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true);

if (skipAuthorization)
{
    return;
}

if (AuthorizeCore(filterContext.HttpContext))
// ...

因此,如果控制器操作定义了AllowAnonymousAttribute,则不会调用AuthorizeCore方法。

因为filterContext.HttpContext.Items(IS_AUTHORIZED)永远不会被设置。

您可以简单地将代码从here复制到实现OnAuthorization,而无需调用基类。这样你就可以处理你想要的缓存。

顺便说一句,我的印象是,如果授权失败,请求管道中的后续进程无论如何都会重定向到登录页面。这就是OnAuthorization的基本实现将filterContext.Result设置为新的HttpUnauthorizedResult实例的原因。因此,为什么要覆盖OnAuthorization并首先进行重定向并不完全清楚。如果您想要某种自定义授权码,只需从true返回falseAuthorizeCore即可。