2

ASP.net MVC4 のカスタム ロール プロバイダーに問題があります。非常に軽量の RoleProvider を実装しましたが、これは変更するまで問題なく動作するようです

[Authorize]
public class BlahController:....
}

[Authorize(Roles="Administrator")]
public class BlahController:....
}

その変更を行うとすぐに、ユーザーは認証されなくなり、401 エラーが発生します。私の RoleProvider は基本的に IsUSerInRole に対して true を返し、GetUserRoles に対して "Administrator" を含むリストを返すため、これは奇妙です。カスタム RoleProvider のすべてのメソッドにブレークポイントを設定しましたが、いずれも呼び出されていませんでした。

次に、AuthorizeAttribute から継承した独自の authorize 属性を実装しました。これで、何が起こっているかを確認できるようにブレークポイントを入れました。基になる属性によって呼び出される User.IsInRole() が false を返すことが判明しました。

ロール プロバイダーが適切に設定されていることを確信しています。設定ファイルにこれがあります

<roleManager enabled="true" defaultProvider="SimplicityRoleProvider">
  <providers>
    <clear />
    <add name="SimplicityRoleProvider" type="Simplicity.Authentication.SimplicityRoleProvider" applicationName="Simplicity" />
  </providers>
</roleManager>

ここで説明されている方法を使用して、どのロール プロバイダーが現在のロール プロバイダーであるかを確認します:現在の RoleProvider インスタンスを参照しますか? 正しい結果が得られます。ただし、User.IsInRole は引き続き false を返します。

Azure Access Control Services を使用していますが、それがカスタム ロール プロバイダーと互換性がない理由がわかりません。

IsInRole がカスタム RoleProvider から値を返すように IPrincipal User を修正するにはどうすればよいですか?


RoleProvider ソース:

public class SimplicityRoleProvider : RoleProvider { プライベート ILog ログ { get; 設定; }

    public SimplicityRoleProvider()
    {
        log = LogManager.GetLogger("ff");
    }        

    public override void AddUsersToRoles(string[] usernames, string[] roleNames)
    {
        log.Warn(usernames);
        log.Warn(roleNames);
    }

    public override string ApplicationName
    {
        get
        {
            return "Simplicity";
        }
        set
        {

        }
    }

    public override void CreateRole(string roleName)
    {

    }

    public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
    {
        return true;
    }

    public override string[] FindUsersInRole(string roleName, string usernameToMatch)
    {
        log.Warn(roleName);
        log.Warn(usernameToMatch);
        return new string[0];
    }

    public override string[] GetAllRoles()
    {
        log.Warn("all roles");
        return new string[0];
    }

    public override string[] GetRolesForUser(string username)
    {
        log.Warn(username);
        return new String[] { "Administrator" };
    }

    public override string[] GetUsersInRole(string roleName)
    {
        log.Warn(roleName);
        return new string[0];
    }

    public override bool IsUserInRole(string username, string roleName)
    {
        log.Warn(username);
        log.Warn(roleName);
        return true;
    }

    public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
    {

    }

    public override bool RoleExists(string roleName)
    {
        log.Warn(roleName);
        return true;
    }
}
4

4 に答える 4

2

カスタム AuthorizeAttribute とカスタム RoleProvider がある場合、System.Web.Security.Roles.GetRolesForUser(Username) が自動的に接続されないようです。

そのため、カスタム AuthorizeAttribute で、データ ソースからロールのリストを取得し、AuthorizeAttribute にパラメーターとして渡されたロールと比較する必要があります。

ロールを手動で比較する必要はないことを示唆するコメントをいくつかのブログ投稿で見ましたが、AuthorizeAttribute をオーバーライドすると、この動作が抑制され、自分で提供する必要があるように見えます。


とにかく、私は何がうまくいったかを説明します。うまくいけば、それはいくつかの助けになるでしょう。

これを達成するためのより良い方法があるかどうかについてのコメントを歓迎します。

私の場合、 AuthorizeAttribute が ApiController に適用されていることに注意してください。ただし、それが関連する情報であるかどうかはわかりません。

   public class RequestHashAuthorizeAttribute : AuthorizeAttribute
    {
        bool requireSsl = true;

        public bool RequireSsl
        {
            get { return requireSsl; }
            set { requireSsl = value; }
        }

        bool requireAuthentication = true;

        public bool RequireAuthentication
        {
            get { return requireAuthentication; }
            set { requireAuthentication = value; }
        }

        public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext ActionContext)
        {
            if (Authenticate(ActionContext) || !RequireAuthentication)
            {
                return;
            }
            else
            {
                HandleUnauthorizedRequest(ActionContext);
            }
        }

        protected override void HandleUnauthorizedRequest(HttpActionContext ActionContext)
        {
            var challengeMessage = new System.Net.Http.HttpResponseMessage(HttpStatusCode.Unauthorized);
            challengeMessage.Headers.Add("WWW-Authenticate", "Basic");
            throw new HttpResponseException(challengeMessage);
        }

        private bool Authenticate(System.Web.Http.Controllers.HttpActionContext ActionContext)
        {
            if (RequireSsl && !HttpContext.Current.Request.IsSecureConnection && !HttpContext.Current.Request.IsLocal)
            {
                //TODO: Return false to require SSL in production - disabled for testing before cert is purchased
                //return false;
            }

            if (!HttpContext.Current.Request.Headers.AllKeys.Contains("Authorization")) return false;

            string authHeader = HttpContext.Current.Request.Headers["Authorization"];

            IPrincipal principal;
            if (TryGetPrincipal(authHeader, out principal))
            {
                HttpContext.Current.User = principal;
                return true;
            }
            return false;
        }

        private bool TryGetPrincipal(string AuthHeader, out IPrincipal Principal)
        {
            var creds = ParseAuthHeader(AuthHeader);
            if (creds != null)
            {
                if (TryGetPrincipal(creds[0], creds[1], creds[2], out Principal)) return true;
            }

            Principal = null;
            return false;
        }

        private string[] ParseAuthHeader(string authHeader)
        {
            if (authHeader == null || authHeader.Length == 0 || !authHeader.StartsWith("Basic")) return null;

            string base64Credentials = authHeader.Substring(6);
            string[] credentials = Encoding.ASCII.GetString(Convert.FromBase64String(base64Credentials)).Split(new char[] { ':' });

            if (credentials.Length != 3 || string.IsNullOrEmpty(credentials[0]) || string.IsNullOrEmpty(credentials[1]) || string.IsNullOrEmpty(credentials[2])) return null;

            return credentials;
        }

        private bool TryGetPrincipal(string Username, string ApiKey, string RequestHash, out IPrincipal Principal)
        {
            Username = Username.Trim();
            ApiKey = ApiKey.Trim();
            RequestHash = RequestHash.Trim();

            //is valid username?
            IUserRepository userRepository = new UserRepository();
            UserModel user = null;
            try
            {
                user = userRepository.GetUserByUsername(Username);
            }
            catch (UserNotFoundException)
            {
                throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.Unauthorized));
            }

            //is valid apikey?
            IApiRepository apiRepository = new ApiRepository();
            ApiModel api = null;
            try
            {
                api = apiRepository.GetApi(new Guid(ApiKey));
            }
            catch (ApiNotFoundException)
            {
                throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.Unauthorized));
            }

            if (user != null)
            {
                //check if in allowed role
                bool isAllowedRole = false;
                string[] userRoles = System.Web.Security.Roles.GetRolesForUser(user.Username);
                string[] allowedRoles = Roles.Split(',');  //Roles is the inherited AuthorizeAttribute.Roles member
                foreach(string userRole in userRoles)
                {
                    foreach (string allowedRole in allowedRoles)
                    {
                        if (userRole == allowedRole)
                        {
                            isAllowedRole = true;
                        }
                    }
                }

                if (!isAllowedRole)
                {
                    throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.Unauthorized));
                }

                Principal = new GenericPrincipal(new GenericIdentity(user.Username), userRoles);                
                Thread.CurrentPrincipal = Principal;

                return true;
            }
            else
            {
                Principal = null;
                throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.Unauthorized));
            }
        }
    }

カスタム承認属性は、次のコントローラーを管理しています。

public class RequestKeyAuthorizeTestController : ApiController
{
    [RequestKeyAuthorizeAttribute(Roles="Admin,Bob,Administrator,Clue")]
    public HttpResponseMessage Get()
    {
        return Request.CreateResponse(HttpStatusCode.OK, "RequestKeyAuthorizeTestController");
    }
}

カスタム RoleProvider には、次のメソッドがあります。

public override string[] GetRolesForUser(string Username)
{
    IRoleRepository roleRepository = new RoleRepository();
    RoleModel[] roleModels = roleRepository.GetRolesForUser(Username);

    List<string> roles = new List<string>();

    foreach (RoleModel roleModel in roleModels)
    {
        roles.Add(roleModel.Name);
    }

    return roles.ToArray<string>();
}
于 2012-07-12T04:58:40.873 に答える
0

したがって、問題はロールプロバイダーを実装する方法ではなく、それを使用するようにアプリケーションを構成する方法です。ただし、構成に問題は見つかりませんでした。これが実際にアプリケーションを構成する方法であることを確認してください。この投稿が役立つ場合があります:http://brianlegg.com/post/2011/05/09/Implementing-your-own-RoleProvider-and-MembershipProvider-in-MVC-3.aspx。デフォルトのMVCテンプレートを使用してプロジェクトを作成する場合は、AccountControllerを確認してください。その投稿によると、カスタムメンバーシッププロバイダーを機能させるには、いくつかの変更が必要になる場合があります。しかし、それはロールプロバイダーには影響しません。

よろしくお願いします、

明徐。

于 2012-04-18T07:59:28.097 に答える
0

stimmsのコメントには次のように書かれていAttributeますIAuthenticationFilter

using System.Web.Security;

....

protected override async Task<IPrincipal> AuthenticateAsync(string userName, string password, CancellationToken cancellationToken)
{
    if (string.IsNullOrWhiteSpace(userName) || string.IsNullOrWhiteSpace(password))
    {
        // No user with userName/password exists.
        return null;
    }

    var membershipProvider = Membership.Providers["CustomMembershipProvider"];
    if (membershipProvider != null && membershipProvider.ValidateUser(userName, password))
    {
         ClaimsIdentity identity = new GenericIdentity(userName, "Basic");
         return new RolePrincipal("CustomRoleProvider", identity);
    }

    return null;           
}

RolePrincipal重要なのは、カスタム ロール プロバイダーを指す を返すことです。

最初に私は戻っnew ClaimsPrincipal(identity)てきました。これにより、OPで説明されている問題が発生しました。

于 2016-07-06T12:27:50.927 に答える