8

我在 2 个 MVC 站点(称为 SiteA 和 SiteB)上进行了基本的单点登录,使用的方法类似于以下方法:

http://forums.asp.net/p/1023838/2614630.aspx

它们位于同一域的子域上,并在 web.config 中共享哈希\加密密钥等。我已经修改了 cookie,因此同一域上的所有站点都可以访问它。所有这些似乎工作正常。

这些站点位于不同的服务器上,无法访问相同的 SQL 数据库,因此只有 SiteA 实际保存用户登录详细信息。SiteB 有一个成员数据库,但用户为空。

这适用于我所需的场景,即:

1) 用户登录 SiteA

2) 应用程序从 SiteA(通过 AJAX)和 SiteB(通过 AJAX 使用 JSONP)加载数据

我在 SiteA 的 AccountController 上有以下登录操作,这是“魔术”发生的地方:

[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        if (MembershipService.ValidateUser(model.UserName, model.Password))
        {
            FormsService.SignIn(model.UserName, model.RememberMe);

            //modify the Domain attribute of the cookie to the second level of domain
            // Add roles  
            string[] roles = Roles.GetRolesForUser(model.UserName);
            HttpCookie cookie = FormsAuthentication.GetAuthCookie(User.Identity.Name, false);
            FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
            // Store roles inside the Forms cookie.  
            FormsAuthenticationTicket newticket = new FormsAuthenticationTicket(ticket.Version, model.UserName, 
                ticket.IssueDate, ticket.Expiration, ticket.IsPersistent, String.Join("|", roles), ticket.CookiePath);
            cookie.Value = FormsAuthentication.Encrypt(newticket);
            cookie.HttpOnly = false;
            cookie.Domain = ConfigurationManager.AppSettings["Level2DomainName"];
            Response.Cookies.Remove(cookie.Name);
            Response.AppendCookie(cookie);

            if (!String.IsNullOrEmpty(returnUrl))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }
        else
        {
            ModelState.AddModelError("", "The user name or password provided is incorrect.");
        }
    }

这做了一些我在初始场景中并不严格需要的东西,但与我的问题有关。它将登录到 SiteA 的用户的角色列表插入到身份验证票证的 UserData 中。然后通过 global.asax 中的以下内容在 SiteB 上“恢复”:

protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
    if (Context.Request.IsAuthenticated)
    {
        FormsIdentity ident = (FormsIdentity) Context.User.Identity;
        string[] arrRoles = ident.Ticket.UserData.Split(new[] {'|'});
        Context.User = new System.Security.Principal.GenericPrincipal(ident, arrRoles);
    }
}

在我将角色添加到组合中之前,上述所有内容都有效。如果我只用 [Authorize] 属性装饰 SiteB 上的 Controllers\Actions,一切都会正常工作。但是一旦我添加 [Authorize(roles="TestAdmin")] 用户就不能再访问该控制器操作。显然我已将用户添加到 TestAdmin 角色。

如果我在 SiteB 上调试 global.asax 代码,当我离开 global.asax 代码时它看起来没问题,但是当我在控制器本身中遇到断点时,Controller.User 和 Controller.HttpContext.User 现在是一个系统。 Web.Security.RolePrincipal 不再设置角色。

所以我的问题是:有人知道我如何恢复 SiteB 上的角色或其他方式吗?

4

2 回答 2

2

由于这似乎停滞不前,我可以用一些额外的发现来部分回答这个问题。在调试\测试之后,似乎 MVC2 在离开 Application_AuthenticateRequest 之后但在进入我的控制器之前做了一些奇怪的事情。更多细节在这里:

http://forums.asp.net/t/1597075.aspx

一种解决方法是使用 Application_AuthorizeRequest 而不是 Application_AuthenticateRequest。

编辑:我相信我找到了问题的原因。在我的 MVC1 项目中,我禁用了角色管理器,但我的测试 MVC2 项目启用了角色管理器。在 MVC1 测试项目中启用角色管理器后,MVC1 和 MVC2 之间的行为是相同的。我也有一个关于这个问题的 MVC Microsoft 团队开放,如果 Application_AuthorizeRequest 是从身份验证票证 cookie 中恢复角色的正确位置,我会在此处回复...

于 2010-08-30T22:32:08.147 回答
2

你已经解决了,但我们开始吧:

让它工作:关闭角色管理器。asp.net 这样做并不是什么奇怪的行为,因为您明确告诉它使用指定配置查找用户角色。

另一种方法:在两者中启用角色管理器。使用配置来共享 cookie,就像您在自定义代码中所做的那样。根据您的描述,您不必担心它会尝试为用户获取角色,只要您为身份验证 cookie 使用匹配的配置

您应该使用 Application_AuthorizeRequest 来设置角色 cookie 吗?恕我直言,早期的意见(认证)是最好的,我一直这样做,从来没有遇到过问题。

于 2010-09-06T09:10:33.410 回答