如何在OWIN ASP.NET MVC5中注销用户

12

我有一个ASP.NET MVC5项目的标准AccountController类。当我尝试注销用户时,我会遇到错误,因为HttpContextnull。(我指的是HttpContext.GetOwinContext().Authentication为null)

所以我不知道如何在会话结束时注销用户......

global.asax中,我有以下内容:

protected void Session_Start(object sender, EventArgs e)
{
     Session.Timeout = 3; 
}

protected void Session_End(object sender, EventArgs e)
{
            try
            {
                 var accountController = new AccountController();
                 accountController.SignOut();
            }
            catch (Exception)
            {
            }
}

账户控制器

public void SignOut()
{
      // Even if I do It does not help coz HttpContext is NULL
      _authnManager = HttpContext.GetOwinContext().Authentication;    

    AuthenticationManager.SignOut();


}

private IAuthenticationManager _authnManager;  // Add this private variable


public IAuthenticationManager AuthenticationManager // Modified this from private to public and add the setter
{
            get
            {
                if (_authnManager == null)
                    _authnManager = HttpContext.GetOwinContext().Authentication;
                return _authnManager;
            }
            set { _authnManager = value; }
}

Startup.Auth.cs

 public void ConfigureAuth(IAppBuilder app)
        {
            // Enable the application to use a cookie to store information for the signed in user
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                ExpireTimeSpan = TimeSpan.FromMinutes(3),
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Account/Login")
            });
}
6个回答

14

假设您正在使用ApplicationCookie来存储登录信息。

AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);

1
它说AuthManager没有SignOut方法。 - Phil
1
你可以尝试使用以下代码: var ctx = Request.GetOwinContext(); var authenticationManager = ctx.Authentication; authenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie); - radbyx
@phil,它只是删除了cookie。除非刷新页面,否则页面不会重定向到登录页面。在同一请求中注销后,有没有办法使身份无效? - user6395764
@msz 是的,我去年就明白了,哈哈。 - Phil

9
一个调用 Session_End() 的方法引发了异常。这是完全符合预期的,因为你不能简单地创建 new AccountController() ,调用 accountController.SignOut() 并期望它工作。这个新的控制器没有连接到MVC管道 - 它没有HttpContext和所有其他要求才能正常工作。
你应该在响应用户请求时注销他们。创建一个新的具有个人帐户验证功能的MVC项目。打开 AccountController 并查看 LogOff() 方法:
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult LogOff()
    {
        AuthenticationManager.SignOut();
        return RedirectToAction("Index", "Home");
    }

在/Account/LogOff的POST请求响应中将执行AuthenticationManager.SignOut()。每当此类请求到达时,ASP.NET/MVC将创建一个AccountController实例并适当初始化它。之后将调用LogOff方法,在这里您可以实际执行AuthenticationManager.SignOut();
此外,在默认的ASP.NET/MVC应用程序中,使用Identity在代码的Helpers区域声明了AuthenticationManager,如下所示:
private IAuthenticationManager AuthenticationManager { get { return HttpContext.GetOwinContext().Authentication; } }

希望这有所帮助。

@ClarkKent 那个解决方案确实使用了OWIN,我已经编辑了回答来解释它是如何做到的。请参阅待定编辑。米兰解释了为什么在注销用户之前会抛出错误。 - Termato
好的...我刚刚在Session_End中注释了代码,但是我的应用程序出现了奇怪的行为。我将SessionTimeout设置为1分钟。当我登录并什么都不做时,它运行良好。所以1分钟后,当我刷新页面时,它会注销并重定向到登录页面。但是如果在2-3分钟内我在网站中导航,它就无法正常工作。 :) - NoWar
@ClarkKent 在那2-3分钟的时间里,你是否在网站上进行了积极地浏览?你尝试过前往不同的页面,坐一分钟然后再移动吗?如果是这样,尝试输出你的会话变量,看看它是否仍然被设置或者被重置。或者你用来记录用户退出的功能没有在你跳转到另一个页面时被调用。 - Termato
是的,我使用不同的页面进行导航。因此,当用户处于活动状态时,应用程序(ASP.NET MVC)会忽略1分钟的过期间隔... - NoWar
3
你的代码有些混乱,即使你成功调用了上下文填充的函数,仍可能会面临一个单独的问题,就像 https://katanaproject.codeplex.com/workitem/356 中所阐述的一样。你需要调用AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie),而不仅仅是AuthenticationManager.SignOut()。 - rism
显示剩余5条评论

3

我尝试了所有这些:

System.Web.HttpContext.Current.GetOwinContext().Authentication.SignOut(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ApplicationCookie);
FormsAuthentication.SignOut();
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);

Request.GetOwinContext().Authentication.SignOut();

Request.GetOwinContext().Authentication.SignOut(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ApplicationCookie);

但最终这解决了我的问题:

HttpContext.User = new GenericPrincipal(new GenericIdentity(string.Empty),null);

Check


2

为此,您需要定义一个ActionFilter属性,在那里您需要将用户重定向到相应的控制器操作。在那里,您需要检查会话值,如果为空,则需要重定向用户。以下是代码(您也可以访问我的博客获取详细步骤):

public class CheckSessionOutAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            string controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName.ToLower().Trim();
            string actionName = filterContext.ActionDescriptor.ActionName.ToLower().Trim();

            if (!actionName.StartsWith("login") && !actionName.StartsWith("sessionlogoff"))
            {
                var session = HttpContext.Current.Session["SelectedSiteName"];
                HttpContext ctx = HttpContext.Current;
                //Redirects user to login screen if session has timed out
                if (session == null)
                {
                    base.OnActionExecuting(filterContext);


                    filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new
                    {
                        controller = "Account",
                        action = "SessionLogOff"
                    }));

                }
            }

        }

    }
}

2
Session.Abandon();
var owinContext = System.Web.HttpContext.Current.Request.GetOwinContext();
var authenticationTypes = owinContext.Authentication.GetAuthenticationTypes();
owinContext.Authentication.SignOut(authenticationTypes.Select(o => o.AuthenticationType).ToArray());

```


1

这对我有用

`public void SignOut()
    {
        IOwinContext context = _context.Request.GetOwinContext();
        IAuthenticationManager authenticationManager = context.Authentication;
        authenticationManager.SignOut(AuthenticationType);
    }
`

我唯一的问题是没有重定向到登录页面,因此当我从一个有 [Authorize] 属性的视图注销时,会出现视图未找到错误。我认为当用户未经授权访问此代码块时,自动重定向已内置...
`app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = "ApplicationCookie",
        LoginPath = new PathString("/Account/Login"),
        ExpireTimeSpan = TimeSpan.FromHours(1),
    });
`

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接