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 (JSONP を使用した AJAX による) からデータをロードします。

「魔法」が起こる場所である SiteA の AccountController に、次の LogOn アクションがあります。

[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 は System.ロールが設定されていない Web.Security.RolePrincipal。

私の質問は次のとおりです。SiteB でロールを復元する方法や、これを行う別の方法を知っている人はいますか?

4

2 に答える 2

2

これは停滞しているように見えるので、いくつかの追加の調査結果でこれに部分的に答えることができます. これをもう少しデバッグ/テストした後、Application_AuthenticateRequest を離れた後、コントローラーに入る前に、MVC2 が奇妙なことをしているようです。詳細はこちら:

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

回避策は、Application_AuthenticateRequest の代わりに Application_AuthorizeRequest を使用することです。

編集:問題の原因を見つけたと思います。MVC1 プロジェクトでは roleManager を無効にしましたが、テスト MVC2 プロジェクトでは roleManager を有効にしました。MVC1 テスト プロジェクトで roleManager を有効にすると、MVC1 と MVC2 の動作は同じになります。また、これについて開いている MVC Microsoft チームの 1 つに質問があり、Application_AuthorizeRequest が認証チケット Cookie からロールを復元する正しい場所である場合は、ここに投稿します...

于 2010-08-30T22:32:08.147 に答える
2

あなたはすでにそれを解決しましたが、ここに行きます:

機能させる:ロールマネージャーをオフにします。指定された構成でユーザーのロールを探すように明示的に指示しているため、asp.netがそれを行っているのは奇妙な動作ではありません。

別の方法として、両方でロール マネージャーを有効にします。カスタム コードで行っているように、構成を使用して Cookie を共有します。説明に基づいて、認証Cookieに一致する構成を使用している限り、ユーザーのロールを取得しようとすることを心配する必要はありません

ロール Cookie を設定するために Application_AuthorizeRequest を使用する必要がありますか? 以前の私の意見(Authenticate)が最適です。私は常にそのようにしてきましたが、問題に遭遇したことはありません。

于 2010-09-06T09:10:33.410 に答える