我有一个MVC应用程序,我有一个User类,用户也可以冒充其他用户(仅限管理员用户)。
所以我在下面有这个代码来验证请求并实例化我的User类的版本。
然后尝试从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;
}
答案 0 :(得分:1)
尝试创建授权过滤器:
public class CustomAuthorizationFilter : AuthorizeAttribute
{
protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
{
// perform your authorization here
// full access to HttpContext and session
}
}
然后,您可以将此属性应用于控制器。理想情况下,您将拥有一个所有其他控制器继承的基本控制器,您可以在该控制器的类级别应用该属性。然后,您的所有请求都将获得授权,并按照您上面编码的方式应用模拟。
答案 1 :(得分:0)
在AuthenticateRequest期间,会话将不可用:您需要做的是将所需信息标记到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 - &gt; 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);
}
答案 2 :(得分:0)
我有同样的问题需要访问global.asax中的会话,最后通过将我的代码移动到AcquireRequestState
处理程序来解决它,这在验证通过后发生。
protected void Application_AcquireRequestState(Object sender, EventArgs e)
{
if (Request.IsAuthenticated && Context.Session != null)
{
// access Context.Session
}
}
这会激发很多,当前上下文并不总是有一个有效的会话对象,因此检查。
编辑:还要为IsAuthenticated添加检查 - 注销时出现空错误。现在效果很好。