6

MVC 4でフォーム認証を使用してユーザーを認証しようとしています(RavenDBを使用しているため、標準のメンバーシッププロバイダーを使用できません)。その後、このUser.IsInRole()方法を使用AuthorizeAttributeするか、ユーザーがスタッフの役割を果たしていることを確認します。

ここで、認証が成功したときにチケットを設定します(現時点ではUserController.cs):

FormsAuthenticationTicket ticket =
    new FormsAuthenticationTicket(
        1,
        model.Email,
        DateTime.Now,
        DateTime.Now.AddDays(1),
        false,
        model.Email);

string hashedTicket = FormsAuthentication.Encrypt(ticket);

HttpCookie cookie =
    new HttpCookie(
        FormsAuthentication.FormsCookieName,
        hashedTicket);

HttpContext.Response.Cookies.Add(cookie);

ここで、各リクエストのチケットを確認します(Global.asax):

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    var authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];

    if (authCookie != null)
    {
        var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
        var user = this.UserService.GetUserByEmail(authTicket.Name);

        var identity = new GenericIdentity(authTicket.Name, "Forms");

        var principal = new GenericPrincipal(identity, user.Roles);

        HttpContext.Current.User = principal;
    }
}

次に、アクションメソッドの1つ(CalendarController.cs)にデバッグポイントを設定すると、次のようにisStaffなりfalseます。

public ActionResult Index()
{
    var user = HttpContext.User;

    bool isStaff = user.IsInRole(Role.Staff);

    return View();
}

完了のためだけに(Roles.cs、物事をテストするための一時的なクラス):

public static class Role
{
    public static string Staff
    {
        get { return "Staff"; }
    }

    public static string Manager
    {
        get { return "Manager"; }
    }
}

誰かが私が欠けているかもしれないものについて私にポイントを与えるのを手伝ってもらえますか?アクションメソッドにたどり着くまでに、設定した役割がなくなっているように見えます。

4

3 に答える 3

13

これを手伝ってくれてありがとう、私が思いついたもの(以下に含まれています)はうまくいきます!ユーザーが有効なチケット (Cookie) を持っている場合は、ログイン画面から直接自動ログインし、ユーザーの Cookie にロールを配置することなく、 オブジェクトClaimsIdentityとオブジェクトを使用してクレーム ベースのロールを処理します。また、カスタム承認属性を設定する必要なくClaimsPrincipal、ファイル内の認証も処理します。Global.asax.cs

UserController.cs

public ActionResult Login()
{
    LoginViewModel model = new LoginViewModel();

    if ((HttpContext.User != null) &&
        (HttpContext.User.Identity.IsAuthenticated))
    {
        return RedirectToAction("Index", "Home");
    }

    return View(model);
}

[HttpPost]
public ActionResult Login(LoginViewModel model)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }

    bool isAuthenticated = this.userService.IsPasswordValid(model.Email, model.Password);

    if (!isAuthenticated)
    {
        ModelState.AddModelError("AuthError", Resources.User.Login.AuthError);

        return View(model);
    }

    FormsAuthentication.SetAuthCookie(model.Email, model.RememberUser);

    return RedirectToAction("Index", "Home");
}

Global.asax.cs

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    var authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];

    if (authCookie != null)
    {
        var ticket = FormsAuthentication.Decrypt(authCookie.Value);

        FormsIdentity formsIdentity = new FormsIdentity(ticket);

        ClaimsIdentity claimsIdentity = new ClaimsIdentity(formsIdentity);

        var user = this.UserService.GetUserByEmail(ticket.Name);

        foreach (var role in user.Roles)
        {
            claimsIdentity.AddClaim(
                new Claim(ClaimTypes.Role, role));
        }

        ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(claimsIdentity);

        HttpContext.Current.User = claimsPrincipal;
    }
}
于 2013-01-30T22:37:16.827 に答える
3

Raven を使用しているので、独自のカスタム MembershipProvider と RoleProvider を作成したと仮定します。それらを使用するようにweb.configを変更しました。次のようなエントリが必要です。

<membership defaultProvider="MyMembershipProvider">
  <providers>
    <add name="MyMembershipProvider" type="namespace.MyMembershipProvider, providerAssemblyName" connectionStringName="DefaultConnection" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
  </providers>
</membership>
<roleManager enabled="true" defaultProvider="DefaultRoleProvider">
  <providers>
    <add connectionStringName="DefaultConnection" applicationName="/" name="DefaultRoleProvider" type="namespace.MyRoleProvider, providerAssemblyName" />
  </providers>
</roleManager>

.NET Framework バージョン 4.5 を使用している場合は、クレーム ベースのセキュリティが使用されるため、Cookie にロールを格納する必要はありません。代わりに、ロールはClaimsPrincipalに格納されている単なる別のクレームです。すべてのプリンシパルが ClaimsPrincipal から継承され、ユーザー セッション用に保存されます。

System.Web.HttpContext.Current.User as ClaimsPrincipal

メンバーシップとロール プロバイダーが正しく設定されている場合、ASP.NET はそれらを使用して ClaimsPrincipal にロールを設定し、 IsInRoleをチェックするときにクレームをチェックする必要があります。

このようなロールの ClaimsPrincipal からロールを取得することもできます。

principal.FindAll(ClaimTypes.Role).Select(p => p.Value);

そして、このように ClaimsPrincipal にロールを追加できます。

List<Claim> claims = new List<Claim>();
foreach (string role in roles)
   claims.Add(new Claim(ClaimTypes.Role, role));
ClaimsPrincipal principal = new ClaimsPrincipal(new ClaimsIdentity(claims, "Forms"));

これで、このように認証後に Cookie を設定できます。

FormsAuthentication.SetAuthCookie(username, false);
于 2013-01-30T15:44:22.977 に答える
2

ロール情報を挿入する FormsAuthenticationTicket を作成していません:

        var ticket = new FormsAuthenticationTicket(
                1, //ticket version
                userName,
                DateTime.Now,
                DateTime.Now.Add(timeout), //timeout
                true, //persistent cookies
                roles,// <---ROLES not model.Email
                FormsAuthentication.FormsCookiePath);

- - - 編集 - - -

私が言ったことを忘れてください: IsInRole() の呼び出しが早すぎるか、user.Roles の値が間違っていると思います (おそらく文字列内のスペース: isinrole は StringComparison.OrdinalIgnoreCase を使用します)、または GenericIdentity の代わりに FormsIdentity を使用する必要があります。

デバッガーは何と言っていますか?

参考: http://pastebin.com/jkqqcg28 (これは、認証の処理に使用する最初のモデルです)

于 2013-01-30T14:16:42.540 に答える