MVC Owin Cookie Authentication - Override ReturnUr

2019-02-25 17:12发布

I have an MVC application using Owin Cookie Authentication. I have SlidingExpiration enabled and working. However, when a user's login expires and they are sent back to the LoginPath, the ReturnUrl is giving me some problems:

  1. I only want the ReturnUrl to be included if it points to a GET action, not a POST action.
  2. I would like to include the PathAndQuery instead of just Path so that I can re-fill any items the user might have had filled in on a form.

I tried creating my own AuthorizeAttribute (code below) and applying it to some of the methods in one of my controllers, but it seems like it is never hit when the session is expired.

public class CheckLoginExpirationFilter : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);

        if (filterContext.Result is HttpUnauthorizedResult)
        {
            string returnUrl = null;
            if (filterContext.HttpContext.Request.HttpMethod.Equals("GET", StringComparison.CurrentCultureIgnoreCase))
                returnUrl = filterContext.HttpContext.Request.Url.GetComponents(UriComponents.PathAndQuery, UriFormat.SafeUnescaped);

            filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary()
        {
            { "client", filterContext.RouteData.Values[ "client" ] },
            { "controller", "Security" },
            { "action", "Login" },
            { "ReturnUrl", returnUrl }
        });
        }
    }
}

An answer to a related question indicates that a custom AuthorizeAttribute is the "standard [solution], when you want to override this behavior," but I can't seem to get it to work.

1条回答
▲ chillily
2楼-- · 2019-02-25 18:14

Looks like I figured it out: I altered my startup config as follows:

    public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Security/Login"),
            CookieSecure = CookieSecureOption.SameAsRequest,
            SlidingExpiration = true,
            CookieName = "Program.Auth",
            ExpireTimeSpan = TimeSpan.FromSeconds(15)/*FromHours(1)*/,
            Provider = new CookieAuthenticationProvider { OnApplyRedirect = CustomRedirect }
        });

        // TODO - Figure out what claims type to base this on.
        AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Email;
    }

    private static void CustomRedirect(CookieApplyRedirectContext context)
    {
        var redirectUrl = context.Options.LoginPath.ToString();
        if (context.Request.Method == WebRequestMethods.Http.Get)
        {
            var returnUrl = context.Request.Path.ToString();
            if (!string.IsNullOrEmpty(returnUrl) && !returnUrl.Equals("/"))
                redirectUrl += "?" + context.Options.ReturnUrlParameter + "=" + returnUrl;
        }
        else if (context.Request.Method == WebRequestMethods.Http.Post)
        {
            //TODO: add toastr message showing that the post did not succeed
        }
        context.Response.Redirect(redirectUrl + "?tbn=inactive");
    }
}

Now I only get a ReturnUrl for GET requests. I tested with PathAndQuery but so far it has been causing other problems. For the moment, I would say the main problem here is solved.

查看更多
登录 后发表回答