Управление доступом на основе ролей для приложения WPF - лучшие практики - PullRequest
3 голосов
/ 05 марта 2012

Мне нужно реализовать какой-то RBAC для приложения WPF, которое я сейчас пишу. Начиная с версии 2.0 ASP.NET обладает инфраструктурой безопасности, членства и управления ролями (как описано, например, здесь ), и хотя я мог бы использовать это, он все еще чувствует, что использовать его в этом контексте было бы немного Hacky. Я буду рад получить отзывы от всех, кто использовал его и имел успех в аналогичном контексте.

Я также рассмотрел вопрос об использовании AD LDS, прочитал статьи TechNet и посмотрел некоторые примеры кода MSDN, но мне интересно, есть ли какой-либо компонент (для .NET), который устраняет некоторые присущие сложности создания базу данных, настройку ее для развертывания и текущего обслуживания. В этом случае все в порядке, бесплатное или коммерческое.

В других вопросах, касающихся SO, упоминаются службы клиентских приложений, но это влечет за собой добавление IIS в набор, что, хотя и не выходило за пределы возможностей, было тем, чего я не предполагал в самом начале проекта.

Каковы лучшие практики в этом случае? Приложение является типичным делом n-уровневого типа, которое обращается к удаленной базе данных SQL Server, поэтому роли могут храниться там, если это необходимо

.

1 Ответ

5 голосов
/ 05 марта 2012

Вы могли бы взглянуть на руководство / код P & P для идей (или вы могли бы использовать их блок, возможно).http://msdn.microsoft.com/en-us/library/ff953196(v=pandp.50).aspx

Я реализовал свое собственное внутреннее хранилище в SQLServer.Это не так сложно, таблицы, как пользователь, UserRole, SecurityItem, SecurityItemUser, SecurityItemRole.Я проверяю подлинность входа пользователя в Windows по AD, но сохраняю только свое имя входа Windows в базе данных (например, ключ для таблицы User).

Хорошая идея - абстрагироваться от модели интерфейсов / провайдера.Таким образом, если ваше приложение изменится в будущем, оно не потребует особого рефакторинга.

Я создал двухуровневое приложение (WPF -> SQLServer), которое значительно выросло, и руководство приняло решение о безопасности, которой они сейчас хотят3-х уровневое приложение (WCF среднего уровня).Сейчас я работаю над этим, и это настоящая боль, потому что я слишком тесно связал свой код авторизации с клиентским приложением.Теперь очевидно, что авторизация должна происходить на уровне сервиса, но потребует много работы.

С точки зрения того, как идентифицировать определенный «защищаемый», я придумал хороший прием, который экономитмного работы.Хотя, по иронии судьбы, это часть проблемы, которую я сейчас пытаюсь перестроить на 3 уровня.Хитрость заключается в том, чтобы использовать полное имя класса в качестве уникального идентификатора для защищаемого объекта, тогда вы можете использовать простой код при каждой проверке:

_secUtil.PromptSecurityCheck(_secUtil.GetFullyQualifiedObjectName(this, "Save"))

Вот еще один код, который даст вамИдея, как я это сделал (используя P & P Framework).

public class SecurityUtil : ISecurityUtil
{
    public string DatabaseUserName { get { return LocalUserManager.GetUserName(); } }

    public bool PromptSecurityCheck(string securityContext)
    {
        bool ret = IsAuthorized(securityContext);

        if (!ret)
        {
            MessageBox.Show(string.Format("You are not authorised to perform the action '{0}'.", securityContext), Settings.Default.AppTitle,
                                        MessageBoxButton.OK, MessageBoxImage.Error);
        }

        return ret;
    }

    public bool IsAuthorized(string securityContext)
    {
        IAuthorizationProvider ruleProvider = AuthorizationFactory.GetAuthorizationProvider("MyAuthorizationProvider");

        //bool ret = ruleProvider.Authorize(LocalUserManager.GetThreadPrinciple(), securityContext);
        bool ret = ruleProvider.Authorize(LocalUserManager.GetCurrentPrinciple(), securityContext);            
        return ret;
    }

    public string GetFullyQualifiedName(object element)
    {
        return element.GetType().FullName;
    }

    public string GetFullyQualifiedObjectName(object hostControl, string objectName)
    {
        return GetFullyQualifiedName(hostControl) + "." + objectName;
    }
}

[ConfigurationElementType(typeof(CustomAuthorizationProviderData))]
public class MyAuthorizationProvider : AuthorizationProvider
{
    public SitesAuthorizationProvider(NameValueCollection configurationItems)
    {
    }

    public override bool Authorize(IPrincipal principal, string context)
    {

        bool ret = false;

        if (principal.Identity.IsAuthenticated)
        {
            // check the security item key, otherwise check the screen uri
            ret = LocalCacheManager.GetUserSecurityItemsCache(LocalUserManager.UserId, false).Exists(
                si => si.SecurityItemKey.Equals(context, StringComparison.InvariantCultureIgnoreCase));

            if (!ret)
            {
                // check if this item matches a screen uri
                ret = LocalCacheManager.GetUserSecurityItemsCache(LocalUserManager.UserId, false).Exists(
                si => si.Uri.Equals(context, StringComparison.InvariantCultureIgnoreCase));
            }
        }

        return ret;

    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...