允许一个人一次使用帐户的可重复使用方式

时间:2013-08-08 22:44:00

标签: asp.net-mvc

我制作了一项功能,可以同时阻止一个用户名的多次登录,我在这样的操作中调用它:

        int userId = (int)WebSecurity.CurrentUserId;

        if ((this.Session.SessionID != dba.getSessionId(userId)) || dba.getSessionId(userId) == null)
        {
            WebSecurity.Logout();
            return RedirectToAction("Index", "Home");
        }

所以关键是每次用户登录时我都会将他的sessionID保存到数据库字段中。因此,如果具有相同用户名的某人登录已使用相同用户名登录的某人,则会使用此新会话覆盖该数据库字段。如果DB中的sessionID与登录用户的当前会话ID不同,则将其记录下来。

是否有可能将这部分代码放在一个地方,或者我是否必须将它放在我的应用程序中的每个Action中?

我试过Global.asax:

void Application_BeginRequest(object sender, EventArgs e)
    {
        if (Session["ID"] != null)
        {
            int userId = Convert.ToInt32(Session["ID"]);
            if ((this.Session.SessionID != db.getSessionId(userId)) || db.getSessionId(userId) == null)
            {
                WebSecurity.Logout();
            }
        }
    }

但是如果我这样做的话,我不能在这里使用Session,也不能使用WebSecurity类:

    void Application_BeginRequest(object sender, EventArgs e)
    {
        int userId = (int)WebSecurity.CurrentUserId;

        if ((this.Session.SessionID != db.getSessionId(userId)) || db.getSessionId(userId) == null)
        {
            WebSecurity.Logout();
            Response.RedirectToRoute("Default");                
        }
    }

因为我得到空引用异常。

修改

我用过这个:

    void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
    {
        int userId = (int)WebSecurity.CurrentUserId;
        using (var db = new UsersContext())
        {
            string s = db.getSessionId(userId);

            if ((filterContext.HttpContext.Session.SessionID != db.getSessionId(userId)) || db.getSessionId(userId) == null)
            {
                WebSecurity.Logout();
                filterContext.Result = new RedirectResult("/Home/Index");
            }
        }
    }

我不得不使用using语句用于上下文,否则 db.getSessionId(userId)返回旧的sessionId。方法是这样的:

    public string getSessionId(int userId)
    {
        string s = "";
        var get = this.UserProfiles.Single(x => x.UserId == userId);
        s = get.SessionId;
        return s;
    }

非常奇怪,将不得不阅读发生这种情况的原因。

一切都很好,除了一件事。我在一个控制器中有一个JsonResult动作,它返回Json,但是因为事件(它在enter事件上的文本框)不能触发POST(我认为它是因为它之前注销)重定向不起作用。它甚至无法发布到Json动作以接收回调和重定向。有什么线索吗?

                        success: function (data) {
                        if (data.messageSaved) {
                            //data received - OK!
                        }
                        else {
                            // in case data was not received, something went wrong redirect out
                            window.location.href = urlhome;
                        }
                    }

在我使用ActionFilterAttribute之前,我使用代码检查POST内部的不同会话,当然它可以进行回调,因此如果没有收到数据则重定向..但是现在因为它甚至不能POST并进入方法它只是卡在那里,并没有重定向:)

6 个答案:

答案 0 :(得分:4)

我会从AuthorizeAttribute派生出来。如果您不需要授权请求,则无需检查此信息。

public class SingleLoginAuthorizeAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    { 
        bool isAuthorized = base.AuthorizeCore(httpContext);

        if (isAuthorized)
        {
            int userId = (int)WebSecurity.CurrentUserId;

            if ((filterContext.HttpContext.Session.SessionID != dba.getSessionId(userId)) 
                || dba.getSessionId(userId) == null)
            {
                WebSecurity.Logout();
                isAuthorized = false;
                filterContext.Result = new RedirectResult("/Home/Index");
            }
        }

        return isAuthorized;
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAjaxRequest())
        {
            filterContext.Result = new JsonResult()
            {
                Data = FormsAuthentication.LoginUrl,
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            };
        }
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }
}

我还提到这可以让你短路其他ActionFilters,因为它们在OnAuthorization之后运行。

  1. 正向订单 - OnAuthorization:AuthorizationFilter(范围控制器)
  2. 正向订单 - OnActionExecuting:ActionFilter1(范围全局)
  3. 正向订单 - OnActionExecuting:ActionFilter2(范围控制器)
  4. 正向订单 - OnActionExecuting:ActionFilter3(范围操作)
  5. 然后提到Rob Lyndon,你可以在FilterConfig(MVC4)

    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new SingleLoginAuthorizeAttribute());
        }
    }
    

    然后,当您不想要任何授权时,可以使用ActionResult方法或Controller Class上的AllowAnonymouseAttribute来允许匿名访问。

    <强>更新

    我为你的ajax调用(Get或Post)添加了一种处理超时的方法。你可以这样做:

    success: function (jsonResult)
    {
      if (jsonResult.indexOf('http') == 0)
      {
        window.location = jsonResult;
      }
    
      // do other stuff with the Ajax Result
    }
    

    这不是最好的方法,但如果你想了解更多有关如何做得更好的信息,我会问另一个问题,而不是在这个问题上附加更多问题。

答案 1 :(得分:3)

ActionFilterAttribute是要走的路。

答案 2 :(得分:2)

我们创建了一个名为SeatCheck的{​​{3}}并按照以下方式装饰每个控制器:

[SeatCheck]
public class NoteController : BaseController
{

我们使用它来计算座位和其他功能,但它使得在不考虑它的情况下更容易控制它。

在proejct ActionFilters文件夹中,我们有SeatCheck.cs文件,如下所示:

namespace site.ActionFilters
{
  public class SeatCheckAttribute : ActionFilterAttribute
  {
     public override void OnActionExecuting(ActionExecutingContext filterContext)
     {

您可以像这样

在Action Filter中获取SessionID
 filterContext.HttpContext.Session.SessionID

答案 3 :(得分:1)

是的,的确有。您可以使用从ActionFilterAttribute派生的属性。

我会写一个名为SessionSecurityAttribute的课程:

public class SessionSecurityAttribute : ActionFilterAttribute
{
    public MyDbConn MyDbConn { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var session = filterContext.RequestContext.HttpContext.Session;
        if (session["ID"] != null && WebSecurity.IsAuthenticated)
        {
            int userId = Convert.ToInt32(session["ID"]);
            if ((sessionID != MyDbConn.getSessionId(userId)) || MyDbConn.getSessionId(userId) == null)
            {
                WebSecurity.Logout();
            }
        }
    }
}

问题仍然存在:如何在让他们访问您的数据库的同时将这些属性添加到您的操作中?这很简单:在Global.asax中,您可以调用自举RegisterGlobalFilters方法:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());
    filters.Add(new SessionSecurityAttribute
        {
            MyDbConn = DependencyResolver.Current.GetService<MyDbConn>()
        });
}

默认情况下,这会将SessionSecurityAttribute与数据库连接一起添加到每个操作中,而不需要重复代码。

答案 4 :(得分:1)

创建custom action filter,并将该代码放入过滤器,然后将过滤器应用于您的控制器。

答案 5 :(得分:0)

您可以尝试实现自己的自定义ISessionIDManager: http://msdn.microsoft.com/en-us/library/system.web.sessionstate.isessionidmanager.aspx

在验证中,检查它是否仍然有效,否则返回false。