我已经打了好几个小时了,我很难过。我正在向MVC 5控制器发出ajax post请求,试图自动登录特定的预定义&#34; super&#34;用户。在控制器方法中,我试图以编程方式设置HttpContext.Current.User并进行身份验证,因此超级用户可以跳过手动登录的过程。对此的共识似乎就在这里,我实现了:< / p>
setting HttpContext.Current.User
这似乎有效,直到我尝试使用自定义AuthorizeAttribute查看任何其他控制器方法。
控制器方法:
[HttpPost]
[AllowAnonymous]
public ActionResult Login(string username)
{
string password = ConfigurationManager.AppSettings["Pass"];
User user = service.Login(username, password);
var name = FormsAuthentication.FormsCookieName;
var cookie = Response.Cookies[name];
if (cookie != null)
{
var ticket = FormsAuthentication.Decrypt(cookie.Value);
if (ticket != null && !ticket.Expired)
{
string[] roles = (ticket.UserData as string ?? "").Split(',');
System.Web.HttpContext.Current.User = new GenericPrincipal(new FormsIdentity(ticket), roles);
}
}
//...processing result
return Json(result);
}
上面的service.Login方法创建了cookie:
FormsAuthentication.SetAuthCookie(cookieValue, false);
虽然我设置了具有Identity和IsAuthenticated的User,但下面的filterContext.HttpContext.User不是同一个用户。它本质上是空的,好像从未分配过,并且未经过身份验证。
public override void OnAuthorization(AuthorizationContext filterContext)
{
string[] userDetails = filterContext.HttpContext.User.Identity.Name.Split(char.Parse("|"));
}
我能找到的最近的帖子是:IsAuthenticated works on browser - but not with Air client!
然而,对我来说已经解决了这个问题:
<authentication mode="Forms">
<forms cookieless="UseCookies" timeout="60" loginUrl="~/Account/Login" />
</authentication>
我缺少什么使AuthorizationContext.User与我在控制器中进行身份验证的HttpContext.Current.User相匹配?
更新
我意识到我需要一个重定向来正确设置cookie,我只是无法通过ajax调用远程工作。这是在站点B上执行控制器方法时站点A中的脚本的样子。此重定向不会设置会话。在下一个控制器方法上验证用户时,它仍然不存在。它只是将我重定向回登录视图。
function remoteLogin(id) {
$.ajax({
url: "/MyController/RemoteLogin",
type: "POST",
dataType: "json",
data: { "id": id }
}).done(function (data) {
if (data) {
if (data.user) {
var user = data.user;
$.ajax({
url: "http://siteB.xyz/Account/Login",
type: "POST",
dataType: "json",
data: { "username": user.username, "password": user.password }
}).done(function (data) {
if (data) {
window.location.href = "http://siteB.xyz/Next"
} else {
alert("Fail.");
}
}).fail(function (data) {
alert("Fail.");
});
} else {
alert("Fail.");
}
}
}).fail(function (data) {
alert("Fail.");
});
}
答案 0 :(得分:3)
您遇到的问题是此时您只设置了身份验证cookie,在表单身份验证模块中创建的IPrincipal将不会发生,直到有新请求 - 所以此时HttpContext.User就在一个奇怪的状态。一旦重定向发生,那么因为它是来自浏览器的新请求,所以在您的页面到达并创建了正确的用户对象之前,cookie将被读取。
Cookie仅在请求完成后在浏览器上设置。
答案 1 :(得分:2)
问题与您的操作代码相对于请求处理管道的运行位置有关。您的代码正在 ProcessRequest 步骤中运行(请参阅下文)。
HttpContext.Current.User 应该由 AuthenticateRequest 事件处理程序设置。 FormsAuthenticationModule 负责处理此事,转而使用 Request.Cookies &#39; FormsAuthenticationCookie 返回 FormsAuthenticationTicket ,然后转换为 IPrincipal 。该Principal设置为 Request.CurrentUser ,我相信 Thread.CurrentPrincipal
这需要在 AuthenticateRequest 步骤中完成,因为请求缓存可能因用户而异( ResolveRequestCache ),会话状态总是如此( AcquireRequestState )。此外, AuthorizeRequest 步骤会决定 AuthenticateRequest 步骤中设置的用户主体是否具有通过 AuthorizeRequest 步骤所需的权限,而不会获取401或300级重定向到登录页面(我相信MVC和WebAPI的授权机制是 ProcessRequest 的一部分)
您可以尝试通过将 HttpContext.Current.User 和 Thread.CurrentPrincipal 设置为 IPrincipal ,但它仅适用于在 ProcessRequest 阶段中该点之后运行的代码...已经进行了有关会话状态,缓存和授权的重要决策。
理论上,您可以通过编写HttpModule并在 AuthenticateRequest (或global.asax)之前/之前实现它来实现类似于您尝试做的事情,但是您不会&# 39;但是还可以访问更高级别的MVC控制器概念,会话状态等。您可以检查 HttpContext.Request.QueryString , HttpContext.Request.Form ,和 HttpContext.Request.Cookies ,但其他并不多。您必须从HTTP请求中获取AJAX调用中的用户名,并调用 FormsAuthentication.SetAuthCookie()或创建 FormsAuthenticationTicket 和 FormsAuthenticationCookie 您自己并将Cookie填入 Request.Cookies 和 Response.Cookies 。当您的控制器逻辑运行时,我非常确定该请求将显示为已验证。