ASP.NET MVC创建模拟用户

4

我有一个MVC应用程序,其中有一个用户类,用户也可以模拟另一个用户(仅限管理员用户)。

所以我有下面的代码来验证请求并实例化我的版本的用户类。

然后它尝试从Session对象中获取模拟的用户,但在global.asax中的此方法中不可用Session。

希望这有意义。

我还能怎么做呢?

我的问题是,在global.asax方法的哪个点上,您可以访问每个请求的Session对象?

protected void Application_OnAuthenticateRequest(object sender, EventArgs e)
{
    IMylesterService service = ObjectFactory.GetInstance<IMylesterService>();

    if (Context.User != null)
    {
        if (Context.User.Identity.IsAuthenticated)
        {
            User user = service.GetUser(Context.User.Identity.Name);
            if (user == null)
                throw new ApplicationException("Context.user.Identity.name is not a recognized user");

            User impersonatedUser = (User)this.Session["ImpersonatedUser"];
            if (impersonatedUser == null)
                user.ImpersonatedUser = user;
            else
                user.ImpersonatedUser = impersonatedUser;

            System.Threading.Thread.CurrentPrincipal = Context.User = user;
            return;
        }
    }
    User guest = service.GetGuestUser();
    guest.ImpersonatedUser = guest;

    System.Threading.Thread.CurrentPrincipal = Context.User = guest;
}

我最近一直遇到这个问题,希望有人能提供帮助。唯一有效的方法是使用OnSessionStart,但如果您此时未经过身份验证,则会错失机会。我正在移植一个ASP.NET应用程序,其中一些在共享基础ASPX中运行的会话代码现在需要移到其他地方... - Brian Moeskau
3个回答

1

尝试创建一个授权过滤器:

public class CustomAuthorizationFilter : AuthorizeAttribute
{
    protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
    {
        // perform your authorization here
        // full access to HttpContext and session
    }
}

然后,您可以将此属性应用于控制器。理想情况下,您应该有一个基本控制器,所有其他控制器都从中继承,并且您可以在该控制器的类级别上应用该属性。然后,您的所有请求都将被授权并应用上述代码中编码的模拟。


0

在AuthenticateRequest期间,Session将不可用:您需要做的是将所需信息标记到Identity.userData中;例如,如果您正在使用表单身份验证,请执行以下操作:

void Application_AuthenticateRequest(object sender, EventArgs e)
{
   if (Context.User != null)
   {
     if (Context.User.Identity.IsAuthenticated)
     {
       // retrieve the value 
       var id = (FormsIdentity)Context.User.Identity;
       var myvalue = id.Ticket.UserData; // "Here you are"
     }
   }
}

如果要使用表单进行登录,您需要编写自定义 cookie: MVC -> class FormsAuthenticationService : IFormsAuthenticationService

public static void SetAuthenticationCookie(HttpContextBase context, FormsAuthenticationTicket ticket)
{
    var cookie = new HttpCookie(FormsAuthentication.FormsCookieName)
       {
          Value = FormsAuthentication.Encrypt(ticket),
          Secure = FormsAuthentication.RequireSSL,
          Domain = FormsAuthentication.CookieDomain,
          HttpOnly = true,
          Expires = DateTime.Now.AddMinutes(15)
       };

    if (!context.Request.IsSecureConnection && FormsAuthentication.RequireSSL)
    {
        throw new HttpException("Ticket requires SSL.");
    }
    context.Response.Cookies.Add(cookie);
}
public static FormsAuthenticationTicket CreateTicket(HttpContextBase context, string emailAddress, string userData, bool persist)
{
    return new FormsAuthenticationTicket(1, emailAddress, DateTime.Now, DateTime.Now.AddMinutes(15), persist, userData, FormsAuthentication.FormsCookiePath);
}

最后,在SignIn中,您现在将通过调用CreateTicket(...)创建所需的票证,然后通过SetAuthenticationCookie(...)将其写出。

public void SignIn(string userName, string password)
{
    if(CheckUserValid(userName,password, out string email))
    {
        var ticket = CreateTicket(email, "Here you are", true);
        SetAuthenticationCookie(HttpContext.Current.Base(), ticket);
    }
}

我从未使用过它,但假设会话状态是在AcquireRequestState期间分配的:

public void Init(HttpApplication context)
{
    context.AcquireRequestState += new EventHandler(context_AcquireRequestState);
}

0
我之前也遇到过需要在 global.asax 中访问 session 的问题,最终通过将代码移动到 AcquireRequestState 处理程序中解决了这个问题,因为此时身份验证已经通过。
    protected void Application_AcquireRequestState(Object sender, EventArgs e)
    {
        if (Request.IsAuthenticated && Context.Session != null)
        {
            // access Context.Session
        }
    }

这会触发很多次,当前上下文并不总是有一个有效的会话对象,因此需要进行检查。

编辑:还必须添加IsAuthenticated的检查--在注销时会出现null错误。现在运行得非常好。


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