Правильное расслоение
От: lumf  
Дата: 03.07.07 09:30
Оценка:
Првет все. Не могу понять как правильно должно выглядеть расслоение архитектуры. Под скажите пожалуйста.


Пример:

Есть объект BLL


public class UserInfo
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        #region Private Fields
            string _user_id;
            string _login;
            string _password;
            string _first_name;
            string _last_name;
            string _mid_name;
            string _email;
            string _role;
            Status _status;
            string _company_name;
            DateTime _login_time = DateTime.Now;

            IList<UserRight> _user_rights;
            
            
        #endregion

        #region Public Properties
        public string FullName
        {
            get
            {
                return _last_name + " " + _first_name + " " + _mid_name;
            }

        }

        public string FirstName
        {
            get
            {
                return _first_name;
            }
            set
            {
                _first_name = value;
            }
        }

        public string LastName
        {
            get
            {
                return _last_name;
            }
            set
            {
                _last_name = value;
            }
        }
        public string MiddleName
        {
            get
            {
                return _mid_name;
            }
            set
            {
                _mid_name = value;
            }
        }

        public string Email
        {
            get
            {
                return _email;
            }
            set
            {
                _email = value;
            }
        }

        public string UserID
        {
            get
            {
                return _user_id;
            }
            set
            {
                _user_id = value;
            }
        }

        public string Login
        {
            get
            {
                return _login;
            }
            set
            {
                _login = value;
            }
        }
        public string Password
        {
            get
            {
                return _password;
            }
            set
            {
                _password = value;
            }
        }


        public string Role
        {
            get
            {
                return _role;
            }
            set
            {
                _role = value;
            }
        }

        public string LoginTime
        {
            get
            {
                return _login_time.ToString();
            }
        }

        
        public Status Status
        {
            get
            {
                return _status;
            }
            set
            {
                _status = value;
            }
        }

        

        public string CompanyName
        {
            get
            {
                return _company_name;
            }
            set
            {
                _company_name = value;
            }
        } 

        #endregion


              }




Все действия с базой данных для этого объекта я делаю через объект DAL:

 public class UsersGateway
    {
        
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        
        static public bool Authentificate(string login, string password,string ip)
        {

                   }
        
        static public UserInfo GetUserInfoByLogin(string login)
        {
                   }

        static public UserInfo GetUserInfoByID(string user_id)
        {
                   }

        static public IList<UserInfo> GetAllUsers()
        {
                    }

        static public void UpdateUserStatus(UserInfo user_info)
        {
                  }

        static public int InsertNewUser(UserInfo user_info)
        {
            
                    }

        static public void UpdateUserInfo(UserInfo user_info)
        {
                                }

        static public void DeleteUser(string user_id)
        {
                    }

        static public void UpdateUserPassword(string login,string password)
        {
                    }


        
    }



Таким образом если мен нужен объект по какому-нибудь пользователю. То я пишу так:

UserInfo user_info = UsersGateway.GetUserInfoByID(user_id);


и тут возникает вопрос, у меня у пользователя есть набор прав. когда и как его инициализивать да бы сохранить нормальную структуру расслоения?

то есть как вариант я вижу такой подход:


IList<UserRight> user_rights = UserRightsGateway.GetUserRightsById(user_info.UserID);
user_info.SetUserRights(user_rights);


Но мне почему то кажется каким-то кривовоатым.....
Заранее всем спасибо
Сиськи и процессоры
Re: Правильное расслоение
От: SergH Россия  
Дата: 03.07.07 09:57
Оценка:
Здравствуйте, lumf, Вы писали:

L>Првет все. Не могу понять как правильно должно выглядеть расслоение архитектуры. Под скажите пожалуйста.


.....

L>Таким образом если мен нужен объект по какому-нибудь пользователю. То я пишу так:


L>
L>UserInfo user_info = UsersGateway.GetUserInfoByID(user_id);
L>


L> и тут возникает вопрос, у меня у пользователя есть набор прав. когда и как его инициализивать да бы сохранить нормальную структуру расслоения?


L>то есть как вариант я вижу такой подход:


L>
L>IList<UserRight> user_rights = UserRightsGateway.GetUserRightsById(user_info.UserID);
L>user_info.SetUserRights(user_rights);
L>


L>Но мне почему то кажется каким-то кривовоатым.....


Слишком низкоуровневый интерфейс. Тот факт, что права хранятся в отдельной таблице не должен волновать пользователя. Все эти детали должны быть где-то внутри, для получения полностью инициализированного пользователя должно быть достаточно одного вызова.

Там же, возможно, придётся сделать кеширование, чтобы не создавать несколько объектов для одного пользователя (или наоборот — если нужно наоборот )
Делай что должно, и будь что будет
Re[2]: Правильное расслоение
От: lumf  
Дата: 03.07.07 10:16
Оценка:
Здравствуйте, SergH, Вы писали:

SH>Здравствуйте, lumf, Вы писали:


L>>Првет все. Не могу понять как правильно должно выглядеть расслоение архитектуры. Под скажите пожалуйста.


SH>.....


L>>Таким образом если мен нужен объект по какому-нибудь пользователю. То я пишу так:


L>>
L>>UserInfo user_info = UsersGateway.GetUserInfoByID(user_id);
L>>


L>> и тут возникает вопрос, у меня у пользователя есть набор прав. когда и как его инициализивать да бы сохранить нормальную структуру расслоения?


L>>то есть как вариант я вижу такой подход:


L>>
L>>IList<UserRight> user_rights = UserRightsGateway.GetUserRightsById(user_info.UserID);
L>>user_info.SetUserRights(user_rights);
L>>


L>>Но мне почему то кажется каким-то кривовоатым.....


SH>Слишком низкоуровневый интерфейс. Тот факт, что права хранятся в отдельной таблице не должен волновать пользователя. Все эти детали должны быть где-то внутри, для получения полностью инициализированного пользователя должно быть достаточно одного вызова.


SH>Там же, возможно, придётся сделать кеширование, чтобы не создавать несколько объектов для одного пользователя (или наоборот — если нужно наоборот )



да я как раз понимаю что пользователь должен инициализироваться сразу. просто меня мущает один момент.


к примеру у пользователя есть проперть


 public IList<UserRight> UserRights
  {
            get
            {

                //здесь я к примеру проверяю проинициализировано ли у меня _user_rights
                // и если нет то делю так?
                _user_rights = UserRightsGateway.GetUserRightsById(_user_id);
                 return _user_rights;
            }

        }


Верен ли такой подход? мне почему то кажется он тоже каким-то странным.....
Сиськи и процессоры
Re[3]: Правильное расслоение
От: Taison Россия  
Дата: 03.07.07 12:19
Оценка:
Здравствуйте, lumf, Вы писали:

L>Здравствуйте, SergH, Вы писали:


SH>>Здравствуйте, lumf, Вы писали:


L>
L> public IList<UserRight> UserRights
L>  {
L>            get
L>            {

L>                //здесь я к примеру проверяю проинициализировано ли у меня _user_rights
L>                // и если нет то делю так?
L>                _user_rights = UserRightsGateway.GetUserRightsById(_user_id);
L>                 return _user_rights;
L>            }

L>        }

L>


L>Верен ли такой подход? мне почему то кажется он тоже каким-то странным.....


Думаю, что в данном случае, пользователю не нужно знать какие у него есть права. Он ими всё равно не управляет. Права пользователя больше интересует систему внутренней безопасности приложения, чем самого пользователя.

Далее ты привязываешь права пользователя к конкретному контексту (gateway). И при этом заставлешь пользователя что-то знать о UserRightsGateway. В реале (в случае сложной CRM — отдел кадров, отдел продаж, отдел поставок) у тебя могут быть несколько подсистем куда пользователь может заходить и что-то делать (база пользователей одна, и несколько gateway в зависимости от приложения)

По секьюрити, глянь например PermissionSet. Ты же там не найдёшь свойство User. Всё определяется по контексту. Например, HttpContext.Current.User.Identity.Name

Например, тебе никто не мешает определить свои классы, имплиментирущии IPrincipal, IIdentity.

Например:


CmsPrincipal.cs

using System;
using System.Collections;
using System.Data;
using System.Security.Principal;
using System.Web;

using ClassLib.Cms.Security;
using Rsdn.Framework.Data;

namespace Web.Manager.Security
{
    /// <summary>
    /// Summary description for CmsPrincipal.
    /// </summary>
    public class CmsPrincipal : IPrincipal
    {

        private IIdentity _identity;
        private string[] _roles;
        private User _user;
        private string _srid;

        public User Account {
            get { return _user; }
        }

        public string[] Roles {
            get { return _roles; }
        }

        public string ResourceID {
            get { return _srid; }
        }

        public CmsPrincipal(IIdentity identity, User user, string resource, string securityContext)
        {
            //
            // TODO: Add constructor logic here
            //
            this._identity = identity;
            this._user = user;
            ArrayList roles = ClassLib.Cms.SecurityManager.LoadUserRoles(_user.ID, resource, out this._srid, securityContext);
            this._roles = (string[]) roles.ToArray(typeof(string));
            Array.Sort(this._roles);
        }

        #region IPrincipal Members

        public IIdentity Identity
        {
            get
            {
                // TODO:  Add CmsPrincipal.Identity getter implementation
                return _identity;
            }
        }

        public bool IsInRole(string role)
        {
            // TODO:  Add CmsPrincipal.IsInRole implementation
            return Array.BinarySearch(_roles, role) >= 0;
        }

        #endregion

        /// <summary>
        /// Checks whether a principal is in all of the specified set of roles
        /// </summary>
        /// <param name="roles">Array of strings. Set of roles to check</param>
        /// <returns></returns>
        public bool IsInAllRoles( params string [] roles )
        {
            foreach (string searchrole in roles )
            {
                if (Array.BinarySearch(_roles, searchrole) < 0 )
                    return false;
            }
            return true;
        }

        /// <summary>
        /// Checks whether a principal is in any of the specified set of roles
        /// </summary>
        /// <param name="roles">Array of strings. Set of roles to check</param>
        /// <returns></returns>
        public bool IsInAnyRoles( params string [] roles )
        {
            foreach (string searchrole in roles )
            {
                if (Array.BinarySearch(_roles, searchrole ) >= 0 )
                    return true;
            }
            return false;
        }

    }
}

-----------------------------------------------------

global.asax.cs
.......
........
        protected void Application_AuthenticateRequest(Object sender, EventArgs e)
        {
            HttpApplication app = sender as HttpApplication;

            //Response.Write(String.Format("Application_AuthenticateRequest: {0} | {1}<br>", Request.Path, Request.ApplicationPath));
            // Extract the forms authentication cookie
            string cookieName = FormsAuthentication.FormsCookieName;
            HttpCookie authCookie = Context.Request.Cookies[cookieName];
            if(null == authCookie) {
                // There is no authentication cookie.
                return;
            }
            
            FormsAuthenticationTicket authTicket = null;
            try {
                authTicket = FormsAuthentication.Decrypt(authCookie.Value);
            } catch(Exception ex) {
                // Log exception details (omitted for simplicity)
                //Response.Write("decryption error:"+e.ToString()+".<br>");
                return;
            }
            if (null == authTicket) {
                // Cookie failed to decrypt.
                //Response.Write("failed to decrypt.<br>");
                return;
            }

            // When the ticket was created, the UserData property was assigned a
            // unique identificator of related database entry.
            User user = UserManager.Load(authTicket.UserData);

            // Create an Identity object
            FormsIdentity id = new FormsIdentity( authTicket );

            string contextPath = Context.Request.Path.Replace(Context.Request.ApplicationPath, "");
            // This principal will flow throughout the request.
            CmsPrincipal principal = new CmsPrincipal(id, user, contextPath, System.Configuration.ConfigurationSettings.AppSettings["SecurityContext"] != null?System.Configuration.ConfigurationSettings.AppSettings["SecurityContext"].ToString():"");

            // Attach the new principal object to the current HttpContext object
            Context.User = principal;
        }

.......
.......


Т.е. в данном случае, мы имеем данные о пользователе в свойстве
((CmsPrincipal) HttpContext.Current.User).Account,
а его права в ((CmsPrincipal) HttpContext.Current.User).Roles.
Re[4]: Правильное расслоение
От: lumf  
Дата: 03.07.07 12:54
Оценка:
Здравствуйте, Taison, Вы писали:

T>Здравствуйте, lumf, Вы писали:


L>>Здравствуйте, SergH, Вы писали:


SH>>>Здравствуйте, lumf, Вы писали:


L>>
L>> public IList<UserRight> UserRights
L>>  {
L>>            get
L>>            {

L>>                //здесь я к примеру проверяю проинициализировано ли у меня _user_rights
L>>                // и если нет то делю так?
L>>                _user_rights = UserRightsGateway.GetUserRightsById(_user_id);
L>>                 return _user_rights;
L>>            }

L>>        }

L>>


L>>Верен ли такой подход? мне почему то кажется он тоже каким-то странным.....


T>Думаю, что в данном случае, пользователю не нужно знать какие у него есть права. Он ими всё равно не управляет. Права пользователя больше интересует систему внутренней безопасности приложения, чем самого пользователя.



Что-то запутался Ну почему пользоватлею все равно... это же его права? его. у пользователя по идее должны быть методы добавления.удаления прав. А так же метод в который я передаю что-то, чтобы проверить имеет ли данный пользователь доступ к этому.


T>Далее ты привязываешь права пользователя к конкретному контексту (gateway). И при этом заставлешь пользователя что-то знать о UserRightsGateway. В реале (в случае сложной CRM — отдел кадров, отдел продаж, отдел поставок) у тебя могут быть несколько подсистем куда пользователь может заходить и что-то делать (база пользователей одна, и несколько gateway в зависимости от приложения)


можно вот тут чуть подробнее.... а то я догнать не могу.....
Сиськи и процессоры
Re[3]: Правильное расслоение
От: Нахлобуч Великобритания https://hglabhq.com
Дата: 03.07.07 13:21
Оценка: 6 (2)
Здравствуйте, lumf, Вы писали:

_user_rights = UserRightsGateway.GetUserRightsById(_user_id);


L>Верен ли такой подход? мне почему то кажется он тоже каким-то странным.....


Именно такой -- неверен. Причин несколько:

  • Бизнес-логика становится зависимой от DAL'а (то есть вообще кольцевые зависимости)
  • Если UserRightsGateway — синглтон, то сильно ухудшается тестируемость (testability)
  • Если UserRightsGateway — свойство User типа IUserRightsGateway, то встает вопрос о получении корректной реализации этого интерфейса

    Вообще, самый корректный вариант -- это Domain Model, состоящая из простых и понятных объектов, безо всякой прикладной логики. То есть бизнес-объекты выступают просто в виде контейнеров данных. Вариантов работы с такими объектами тоже много. Например, использовать какое-нибудь ORM-средство, которое возьмет на себя всю работу по загрузке, сохранению и обновлению объектов. В этом случае получается богатая объектная модель -- с ассоциациями, коллекциями, наследованием и прочими вещами. Но местные гуру такой подход почему-то не очень одобряют. Как бы то ни было, в этом случае код работы с пользователями может выглядеть как-то так (пользователь пытается отредактировать что-то и у этого "что-то" есть история изменений):

    User user = UserGateway.GetUserByLogin(login);
    if(user.HasRight(UserRight.Edit)) // UserRight - перечисление
    {
        ContentRevision revision = new ContentRevision();
        revision.EditedBy = user;
        
        Content content = ContentGateway.GetContentByTimestamp(timestamp);
        content.AddRevision(revision);
        content.LastModifiedOn = DateTime.Now;
        
        ContentGateway.SaveContent(content);
    } // if


    Второй вариант — это (как я его для себя определяю) использование какого-нибудь Result-Set Mapper'а. В этом случае получаем более бедную объектную модель, представляющую собой классы, один к одному соответствующие таблицам в БД. Тот же фрагмент кода может выглядеть примерно так:

    User user = UserGateway.GetUserByLogin(login);
    if(UserRightService.HasRight(user, UserRight.Edit))
    {
        Content content = ContentGateway.GetContentByTimestamp(timestamp);
        
        ContentRevision revision = new ContentRevision();
        revision.EditedBy = user.ID;
        revision.Content = content.ID;
        
        ContentRevisionGateway.SaveContentRevision(revision);
        
        content.LastModifiedOn = DateTime.Now;
        
        ContentGateway.SaveContent(content);
    } // if
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
  • HgLab: Mercurial Server and Repository Management for Windows
    Re[4]: Правильное расслоение
    От: lumf  
    Дата: 03.07.07 13:51
    Оценка:
    Здравствуйте, Нахлобуч, Вы писали:


    Н>
    Н>User user = UserGateway.GetUserByLogin(login);
    Н>if(user.HasRight(UserRight.Edit)) // UserRight - перечисление
    Н>{
    Н>    ContentRevision revision = new ContentRevision();
    Н>    revision.EditedBy = user;
        
    Н>    Content content = ContentGateway.GetContentByTimestamp(timestamp);
    Н>    content.AddRevision(revision);
    Н>    content.LastModifiedOn = DateTime.Now;
        
    Н>    ContentGateway.SaveContent(content);
    Н>} // if
    Н>


    ну вот я практически так и пытаюсь сделать только вот не могу понять как правильно загрузить права пользователя в user. Информация по пользователю гружу через BLToolkit именно вот в этом методе UserGateway.GetUserByLogin(login); но как вот сделать так чтобы и права грузились я не могу понять.... а самое главное верно ли будет подгружать права пользователя именно вэтом контексте? типа я при инициаизации забрал и информацию о пользователе, а заодно и права пользователя, а заодно может там и еще какие-то свойства пользователся, которые лежат в другой таблице (к примеру ip адреса с которых ему можно логиниться в систему)......
    Сиськи и процессоры
    Re[5]: Правильное расслоение
    От: Нахлобуч Великобритания https://hglabhq.com
    Дата: 03.07.07 14:07
    Оценка:
    Здравствуйте, lumf, Вы писали:

    L>ну вот я практически так и пытаюсь сделать


    Нет. У вас, если используете BLT (и если я его правильно помню), должен быть второй вариант.

    L>только вот не могу понять как правильно загрузить права пользователя в user. Информация по пользователю гружу через BLToolkit именно вот в этом методе UserGateway.GetUserByLogin(login); но как вот сделать так чтобы и права грузились я не могу понять.... а самое главное верно ли будет подгружать права пользователя именно вэтом контексте? типа я при инициаизации забрал и информацию о пользователе, а заодно и права пользователя, а заодно может там и еще какие-то свойства пользователся, которые лежат в другой таблице (к примеру ip адреса с которых ему можно логиниться в систему)......


    А нужна ли вся эта информация? То есть, всегда ли надо загружать информацию о правах, свойствах и т.д.?
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    HgLab: Mercurial Server and Repository Management for Windows
    Re[4]: Правильное расслоение
    От: lumf  
    Дата: 03.07.07 14:09
    Оценка:
    Здравствуйте, Нахлобуч, Вы писали:




    Дальше опять же встает вопрос: как правильно обновить эти права.

    то есть я написал

    user.AddRight(UserRight.Edit);

    Дальше что я должен вызвать чтобы сохранить эти права?
    Сиськи и процессоры
    Re[6]: Правильное расслоение
    От: lumf  
    Дата: 03.07.07 14:16
    Оценка:
    Здравствуйте, Нахлобуч, Вы писали:


    Н>А нужна ли вся эта информация? То есть, всегда ли надо загружать информацию о правах, свойствах и т.д.?




    во, точно анужнали она вообще.... давай загрузим ее потом как она понадобится (отложим)...... и как мне заполнить какое либо из полей в этом случае? кроме как изнутри?
    Сиськи и процессоры
    Re[5]: Правильное расслоение
    От: Нахлобуч Великобритания https://hglabhq.com
    Дата: 03.07.07 14:19
    Оценка:
    Здравствуйте, lumf, Вы писали:

    L>Дальше что я должен вызвать чтобы сохранить эти права?


    Я не знаю, как это делается в BLT, но общие соображение следующие.
    Класс UserRight имеет два свойства — UserID и RightID. Иными словами, он представляет собой таблицу-связку UserRightJunction, используемую для моделирования отношения "многие-ко-многим" в SQL. Таким образом, добавление роли пользователю сводится к добавлению записи в таблицу, что может выглядель примерно так:

    User user = UserGateway.GetUserByLogin(login);
    UserRightGateway.SaveUserRight(new UserRight(user.ID, UserRight.Edit));
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    HgLab: Mercurial Server and Repository Management for Windows
    Re[7]: Правильное расслоение
    От: Нахлобуч Великобритания https://hglabhq.com
    Дата: 03.07.07 14:19
    Оценка:
    Здравствуйте, lumf, Вы писали:

    L>и как мне заполнить какое либо из полей в этом случае? кроме как изнутри?


    Не понял вот этого.
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    HgLab: Mercurial Server and Repository Management for Windows
    Re[8]: Правильное расслоение
    От: lumf  
    Дата: 03.07.07 14:29
    Оценка:
    Здравствуйте, Нахлобуч, Вы писали:

    Н>Здравствуйте, lumf, Вы писали:


    L>>и как мне заполнить какое либо из полей в этом случае? кроме как изнутри?


    Н>Не понял вот этого.



    к примеру у пользователя есть проперть

    public IList<UserRight> UserRights
      {
                get
               {
    
                   //здесь я к примеру проверяю проинициализировано ли у меня _user_rights
                    // и если нет то делю так?
                    _user_rights = UserRightsGateway.GetUserRightsById(_user_id);
                     return _user_rights;
                }
    
            }





    это разве не lazy load ?
    Сиськи и процессоры
    Re[9]: Правильное расслоение
    От: Нахлобуч Великобритания https://hglabhq.com
    Дата: 03.07.07 14:42
    Оценка:
    Здравствуйте, lumf, Вы писали:

    L>это разве не lazy load ?


    В целом -- да. Но я уже описал недостатки такой реализации. Lazy Load тоже зверь не без проблем, но я не к нему веду. Я говорю о том, что в случае рукопашной реализации и простой Domain Model надо загружать только те данные, которые необходимы в данный конкретный момент.
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    HgLab: Mercurial Server and Repository Management for Windows
    Re[5]: Правильное расслоение
    От: Аноним  
    Дата: 03.07.07 14:44
    Оценка: 12 (3)
    T>>Думаю, что в данном случае, пользователю не нужно знать какие у него есть права. Он ими всё равно не управляет. Права пользователя больше интересует систему внутренней безопасности приложения, чем самого пользователя.

    L>Что-то запутался Ну почему пользоватлею все равно... это же его права? его. у пользователя по идее должны быть методы добавления.удаления прав. А так же метод в который я передаю что-то, чтобы проверить имеет ли данный пользователь доступ к этому.


    T>>Далее ты привязываешь права пользователя к конкретному контексту (gateway). И при этом заставлешь пользователя что-то знать о UserRightsGateway. В реале (в случае сложной CRM — отдел кадров, отдел продаж, отдел поставок) у тебя могут быть несколько подсистем куда пользователь может заходить и что-то делать (база пользователей одна, и несколько gateway в зависимости от приложения)


    L>можно вот тут чуть подробнее.... а то я догнать не могу.....


    Ну например. Представь СТУДЕНТА как пользователя (IPrincipal). И вот он каждый день посещает институт, где существует система пропусков, а также ходит на работу, где установлена своя система пропусков. Как пользователь (человек ) он один, а систем пропусков — две. В каждой из них у него свои права(роли). Всё зависит от контекста. И каждый раз при входе требуется пройти авторизацию. В примере, в обеих случаях её выполняет пропуск (IIdentity).
    Далее, как работник (EmployeePrincipal, студент — StudentPrincipal), пользователь по пропуску может посещать только определённые помещения, отделы. При этом только система безопасности предприятия определяет доступ пользователя, а не система безопасности института.

    Т.е. получаем, что пользователь не должен знать ничего о своих правах, как равно возможность их добавлять, удалять. В идеале, пользователь может попытаться сделать всё, — весь вопрос в том, позволит ли система ему это сделать.

    Проверка прав пользователя должна осуществляться в системе другим способом:

    Как я упоминал, глянь класс PermissionSet, а также IPermission, PrincipalPermission в MSDN
    Например, на предприятии существуют следующие группы пользователей (роли): рабочие, бригадиры, директора.
    И есть операция 'Назначить задание'. Задания могут быть трёх типов: глобальный, общие, отдельные задания.
    Глобальные могут назначать только директора.
    Общие — и диретора, и бригадиры.
    Отдельные задания — только бригадиры
    Получаем:
    public class Enterprise
    {
       protected static PrincipalPermission HighestAccessPermission = new PrincipalPermission(null, "Director");
       protected static PrincipalPermission HighAccessPermission = new PrincipalPermission(null, "Master");
       protected static PrincipalPermission LowAccessPermission = new PrincipalPermission(null, "Employee");
    
    .................
    .................
    
       public void AssignGlobalTask(ITaskInfo task, User responsible) {
          HighestAccessPermission.Demand(); // Только директор может назначить глобальную задачу
          // Do assign global task
       }
    
       public void AssignCommonTask(ITaskInfo task, User responsibles[]) {
          LowAccessPermission.Deny(); // Запретить рабочим назначать общую задачу, только директора и бригадиры
          // Do assign common task
       }
    
       public void AssignSeparateTask(ITaskInfo task, User responsibles[]) {
          HighAccessPermission.Demand();  
          // Do assign separate task
       }
    
       // Ещё можно декларативно
    
       [PrincipalPermission(SecurityAction.Demand, Role="Director")] // Только директор может назначить глобальную задачу
       public void AssignGlobalTask(ITaskInfo task, User responsible) {
          // Do assign global task
       }
    
       [PrincipalPermission(SecurityAction.Deny, Role="Employee")]  // Запретить рабочим назначать общую задачу, только директора и бригадиры
       public void AssignCommonTask(ITaskInfo task, User responsibles[]) {
          // Do assign common task
       }
    
       [PrincipalPermission(SecurityAction.Demand, Role="Master")]
       public void AssignSeparateTask(ITaskInfo task, User responsibles[]) {
          // Do assign separate task
       }
       
    .................
    }
    Re[6]: Это я был
    От: Taison Россия  
    Дата: 03.07.07 14:48
    Оценка: 2 (1)
    Здравствуйте, Аноним, Вы писали:

    Это был я
    Re[7]: Это я был
    От: lumf  
    Дата: 03.07.07 15:21
    Оценка: :)
    Здравствуйте, Taison, Вы писали:

    T>Здравствуйте, Аноним, Вы писали:


    T>Это был я



    спасибо ... очень познавательно надо переварить... как это можно у себя использовать
    Сиськи и процессоры
    Re[6]: Правильное расслоение
    От: lumf  
    Дата: 04.07.07 08:31
    Оценка:
    Здравствуйте, Нахлобуч, Вы писали:

    Н>Здравствуйте, lumf, Вы писали:


    L>>Дальше что я должен вызвать чтобы сохранить эти права?


    Н>Я не знаю, как это делается в BLT, но общие соображение следующие.

    Н>Класс UserRight имеет два свойства — UserID и RightID. Иными словами, он представляет собой таблицу-связку UserRightJunction, используемую для моделирования отношения "многие-ко-многим" в SQL. Таким образом, добавление роли пользователю сводится к добавлению записи в таблицу, что может выглядель примерно так:

    Н>
    Н>User user = UserGateway.GetUserByLogin(login);
    Н>UserRightGateway.SaveUserRight(new UserRight(user.ID, UserRight.Edit));
    Н>



    таким образом все опять сводится к тому что на каждый класс у меня есть своя таблица....

    и все эти классы являются RowGateway (по фаулеру)

    просто я немного не допонимаю.... если все эти классы разрознены и связаны лишь id

    то как им взаимодействовать?


    то есть если эти классы не включаются друг в друга...

    к примеру веб-приложение:

    я аутентифицировал пользователя, создал объект и положил его в сессию:


    User user = UserGateway.GetUserByLogin(login);



    так же есть набор прав данного пользователя и по идее тоже кладу в сессию (где-то же надо хранить, ну а раз не вобекте пользователя то в сессии)


    Ilist<UserRight> user_rights = UserRightGateway.GetUserRight(user.ID);



    вот пришел я на опрделенную страницу... и хочу узнать а есть ли у пользователя права на что нибудь?

    у какого класса должен быть метод для этой проверки?


    помогите осознать плиз...хочется освоить различную архитектуру... но на деле объектную модель не получается пострить потому что не понятно как это вообще делается нормально
    Сиськи и процессоры
    Re[7]: Правильное расслоение
    От: Нахлобуч Великобритания https://hglabhq.com
    Дата: 04.07.07 09:12
    Оценка:
    Здравствуйте, lumf, Вы писали:

    L>вот пришел я на опрделенную страницу... и хочу узнать а есть ли у пользователя права на что нибудь?


    Вот на той определенной странице и запросите права Дерните UserRightGateway.GetUserRight() и проверяйте.

    L>у какого класса должен быть метод для этой проверки?


    Это вам решать. Можно непосредственно в коде страницы. На первое время этого будет достаточно, а потом покумекаете и выделите в отдельные сервисные объекты.

    Не стоит сразу пытаться постичь все. Не выйдет, да и голова сразу столько информации не переварит. Двигайтесь последовательно.
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    HgLab: Mercurial Server and Repository Management for Windows
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.