web-dev-qa-db-ja.com

ASP.NET MVCフォーム認証+属性の承認+単純なロール

ASP.NET MVCアプリケーションにsimple Authentication and Authorizationを追加しようとしています。

私は基本的なフォーム認証に追加された機能を追加しようとしています(シンプルさとカスタムデータベース構造のため)

これが私のデータベース構造であると仮定します:ユーザー:ユーザー名パスワードロール(理想的にはいくつかの列挙。必要であれば文字列。現在、ユーザーは1つのロールしか持っていませんが、これは変わるかもしれません)

高レベルの問題:上記のデータベース構造を考えると、次のことができるようになりたいと思います。

  • フォーム認証を使用した単純なログイン
  • [Authorize(Roles = {MyRoles.Admin、MyRoles.Member})]でアクションを飾ります
  • ビューでロールを使用する(一部のパーシャルに表示するリンクを決定するため)

現在、私が本当に確信しているのは認証方法です。その後、私は失われました。どの時点でユーザーロール(ログイン、すべての承認?)を取得するのかわかりません。私の役割は文字列ではない可能性があるため、User.IsInRole()にどのように適合するかはわかりません。

今、私は私が必要なものを達成する「単純な」ものを見つけていないので、ここで尋ねています。複数の例を見てきました。

認証の場合:

  • データベースと「SetAuthCookie」をチェックする簡単なユーザー検証があります
  • または、Membershipプロバイダーをオーバーライドし、ValidateUser内でこれを行います。これらのいずれかで、単純なユーザーロールを追加する方法がわからないため、次のように動作します:HttpContext.Current.User.IsInRole( "Administrator")さらに、これを変更して列挙値を操作する方法がわかりません。

認可については、私は見た:

  • AuthorizeAttributeの派生とAuthorizeCoreの実装OR OnAuthorizationでロールを処理しますか?
  • IPrincipalを実装しますか?

どんな援助も大歓迎です。しかし、私が多くの詳細を必要としているのではないかと恐れています。

52
Kevin

文字列ではなく列挙型を使用できるカスタムAuthorizeAttributeを構築します。承認する必要がある場合は、列挙型名+列挙値を追加して列挙を文字列に変換し、そこからIsInRoleを使用します。

承認されたユーザーにロールを追加するには、 http://www.eggheadcafe.com/articles/20020906の最初のコードのようなHttpApplicationAuthenticateRequestイベントにアタッチする必要があります。 asp (ただし、大規模にネストされたifステートメントをガード句に変換します!)。

フォーム認証Cookieのユーザーロールをラウンドトリップするか、データベースから毎回取得することができます。

8
Neal

似たようなものを実装したと思います。
NerdDinnertutorial に基づく私の解決策は次のとおりです。

ユーザーにサインインするとき、次のようなコードを追加します:

var authTicket = new FormsAuthenticationTicket(
    1,                             // version
    userName,                      // user name
    DateTime.Now,                  // created
    DateTime.Now.AddMinutes(20),   // expires
    rememberMe,                    // persistent?
    "Moderator;Admin"                        // can be used to store roles
    );

string encryptedTicket = FormsAuthentication.Encrypt(authTicket);

var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
System.Web.HttpContext.Current.Response.Cookies.Add(authCookie);

次のコードをGlobal.asax.csに追加します:

protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
    HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
    if (authCookie == null || authCookie.Value == "")
        return;

    FormsAuthenticationTicket authTicket;
    try
    {
        authTicket = FormsAuthentication.Decrypt(authCookie.Value);
    }
    catch
    {
        return;
    }

    // retrieve roles from UserData
    string[] roles = authTicket.UserData.Split(';');

    if (Context.User != null)
        Context.User = new GenericPrincipal(Context.User.Identity, roles);
}

これを実行した後、コントローラーアクションコードで [Authorize] 属性を使用することができます

[Authorize(Roles="Admin")]
public ActionResult AdminIndex ()

さらに質問がある場合はお知らせください。

118
yinner

私はこのようなことをしました:

  • Global.asax.csを使用して、セッション、キャッシュ、またはアプリケーションの状態で比較するロールをロードするか、ValidateUserコントローラーでオンザフライでロードします。

[Authorize]属性をコントローラーに割り当て、認証を必要とする

 [Authorize(Roles = "Admin,Tech")]

または、アクセスを許可するには、たとえば、LoginおよびValidateUserコントローラーは以下の属性を使用します

 [AllowAnonymous] 

私のログインフォーム

<form id="formLogin" name="formLogin" method="post" action="ValidateUser">
<table>
  <tr>
    <td>
       <label for="txtUserName">Username: (AD username) </label>
    </td>
    <td>
       <input id="txtUserName" name="txtUserName" role="textbox" type="text" />
    </td>
  </tr>
  <tr>
     <td>
         <label for="txtPassword">Password: </label>
     </td>
     <td>
         <input id="txtPassword" name="txtPassword" role="textbox" type="password" />
     </td>
  </tr>
  <tr>
      <td>
         <p>
           <input id="btnLogin" type="submit" value="LogIn" class="formbutton" />
        </p>
      </td>
  </tr>
</table>
       @Html.Raw("<span id='lblLoginError'>" + @errMessage + "</span>")
</form>

フォームポストから呼び出されるログインコントローラーとValidateUserコントローラー

ユーザーの検証は、サービスにローカルなWindows ADコンテキストに対して検証するWCFサービスを介した認証ですが、これを独自の認証メカニズムに変更できます

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using System.Security.Principal;
using MyMVCProject.Extensions;
namespace MyMVCProject.Controllers
{
public class SecurityController : Controller
{
    [AllowAnonymous]
    public ActionResult Login(string returnUrl)
    {
        Session["LoginReturnURL"] = returnUrl;
        Session["PageName"] = "Login";
        return View("Login");
    }
    [AllowAnonymous]
    public ActionResult ValidateUser()
    {
        Session["PageName"] = "Login";
        ViewResult retVal = null;
        string loginError = string.Empty;
        HttpContext.User = null;

        var adClient = HttpContext.Application.GetApplicationStateWCFServiceProxyBase.ServiceProxyBase<UserOperationsReference.IUserOperations>>("ADService").Channel;

        var username = Request.Form["txtUserName"];
        var password = Request.Form["txtPassword"];

        //check for ad domain name prefix
        if (username.Contains(@"\"))
          username = username.Split('\\')[1];

        //check for the existence of the account 
        var acctReq = new UserOperationsReference.DoesAccountExistRequest();
        acctReq.userName = username;
        //account existence result
        var accountExist = adClient.DoesAccountExist(acctReq);
        if (!accountExist.DoesAccountExistResult)
        {
            //no account; inform the user
            return View("Login", new object[] { "NO_ACCOUNT", accountExist.errorMessage });
        }
        //authenticate
        var authReq = new UserOperationsReference.AuthenticateRequest();
        authReq.userName = username;
        authReq.passWord = password;
        var authResponse = adClient.Authenticate(authReq);
        String verifiedRoles = string.Empty;
        //check to make sure the login was as success against the ad service endpoint
        if (authResponse.AuthenticateResult == UserOperationsReference.DirectoryServicesEnumsUserProperties.SUCCESS)
        {
            Dictionary<string, string[]> siteRoles = null;

            //get the role types and roles
            if (HttpContext.Application["UISiteRoles"] != null)
                siteRoles = HttpContext.Application.GetApplicationState<Dictionary<string, string[]>>("UISiteRoles");

            string groupResponseError = string.Empty;
            if (siteRoles != null && siteRoles.Count > 0)
            {
                //get the user roles from the AD service
                var groupsReq = new UserOperationsReference.GetUsersGroupsRequest();
                groupsReq.userName = username;
                //execute the service method for getting the roles/groups
                var groupsResponse = adClient.GetUsersGroups(groupsReq);
                //retrieve the results
                if (groupsResponse != null)
                {
                    groupResponseError = groupsResponse.errorMessage;
                    var adRoles = groupsResponse.GetUsersGroupsResult;

                    if (adRoles != null)
                    {
                        //loop through the roles returned from the server
                        foreach (var adRole in adRoles)
                        {
                            //look for an admin role first
                            foreach (var roleName in siteRoles.Keys)
                            {
                                var roles = siteRoles[roleName].ToList();
                                foreach (var role in roles)
                                {
                                    if (adRole.Equals(role, StringComparison.InvariantCultureIgnoreCase))
                                    {
                                        //we found a role, stop looking
                                        verifiedRoles += roleName + ";";
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (String.IsNullOrEmpty(verifiedRoles))
            {
                //no valid role we need to inform the user
                return View("Login", new object[] { "NO_ACCESS_ROLE", groupResponseError });
            }

            if (verifiedRoles.EndsWith(";"))
                verifiedRoles = verifiedRoles.Remove(verifiedRoles.Length - 1, 1);

            //all is authenticated not build the auth ticket
            var authTicket = new FormsAuthenticationTicket(
            1,                             // version
            username,                      // user name
            DateTime.Now,                  // created
            DateTime.Now.AddMinutes(20),  // expires
            true,                    // persistent?
           verifiedRoles   // can be used to store roles
            );

            //encrypt the ticket before adding it to the http response
            string encryptedTicket = FormsAuthentication.Encrypt(authTicket);

            var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
            Response.Cookies.Add(authCookie);

            Session["UserRoles"] = verifiedRoles.Split(';');

            //redirect to calling page
            Response.Redirect(Session["LoginReturnURL"].ToString());
        }
        else
        {
            retVal = View("Login", new object[] { authResponse.AuthenticateResult.ToString(), authResponse.errorMessage });
        }

        return retVal;
    }
}

}

ユーザーは認証され、新しいIDを作成します

protected void FormsAuthentication_OnAuthenticate(Object sender,     FormsAuthenticationEventArgs e)
    {
        if (FormsAuthentication.CookiesSupported == true)
        {
            HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
            if (authCookie == null || authCookie.Value == "")
                return;

            FormsAuthenticationTicket authTicket = null;
            try
            {
                authTicket = FormsAuthentication.Decrypt(authCookie.Value);
            }
            catch
            {
                return;
            }

            // retrieve roles from UserData
            if (authTicket.UserData == null)
                return;

            //get username from ticket
            string username = authTicket.Name;

            Context.User = new GenericPrincipal(
                      new System.Security.Principal.GenericIdentity(username, "MyCustomAuthTypeName"), authTicket.UserData.Split(';'));
        }
    }

私の_Layout.cshtmlの上部にあるサイトでは、このようなものがあります

 {
  bool authedUser = false;
  if (User != null && User.Identity.AuthenticationType == "MyCustomAuthTypeName" && User.Identity.IsAuthenticated)
   {
      authedUser = true;
   }
 }

その後本文に

        @{
         if (authedUser)
          {
            <span id="loggedIn_userName">
                <label>User Logged In: </label>@User.Identity.Name.ToUpper()
            </span>
          }
          else
          {
            <span id="loggedIn_userName_none">

                <label>No User Logged In</label>
            </span>
          }
        }
4
C0r3yh

ユーザーを「ロール内のユーザー」テーブルに追加します。コードでストアドプロシージャ「addusertorole」(そのようなもの)を使用して、さまざまなロールに追加します。 「ロール」テーブルで非常に簡単にロールを作成できます。

使用するテーブル:User、UsersInRole、Roles

組み込みのストアドプロシージャを使用して、これらのテーブルを操作します。あとは、属性を追加するだけです。

たとえば、ユーザーを選択してロールに追加するビューに「管理者」属性を設定できます。ストアドプロシージャを使用して、そのユーザーをロールに追加できます。

0
Mike McClintock