Asp.net MVC Позволяет пользователю переключаться между ролями - PullRequest
2 голосов
/ 17 февраля 2011

Я разрабатываю сложный веб-сайт с пользователями, имеющими несколько ролей.Пользователи также связаны с другими элементами в БД, которые вместе с их ролями определяют, что они могут видеть и делать на веб-сайте.

Теперь некоторые пользователи имеют более 1 роли, но веб-сайт можетобрабатывать только одну роль за раз из-за сложной структуры.

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

Теперь я сохраняю последнее выбранное значение роли в БД вместе с другими его настройками пользователя.Когда он возвращается, таким образом, роль еще запоминается.

Значение раскрывающегося списка должно быть доступно по всему веб-сайту.Я хочу сделать 2 вещи:

  1. Сохранить текущую роль в Session.
  2. Переопределите метод IsInRole или напишите метод IsCurrentlyInRole, чтобы проверить весь доступ к текущей выбранной роли, а не все роли, как это делает оригинальный метод IsInRole

Для части «Хранение в сеансе» я подумал, что было бы неплохо сделать это в Global.asax

    protected void Application_AuthenticateRequest(Object sender, EventArgs e) {
        if (User != null && User.Identity.IsAuthenticated) {
            //check for roles session.
            if (Session["CurrentRole"] == null) {
                NASDataContext _db = new NASDataContext();
                var userparams = _db.aspnet_Users.First(q => q.LoweredUserName == User.Identity.Name).UserParam;
                if (userparams.US_HuidigeRol.HasValue) {
                    var role = userparams.aspnet_Role;
                    if (User.IsInRole(role.LoweredRoleName)) {
                        //safe
                        Session["CurrentRole"] = role.LoweredRoleName;
                    } else {
                        userparams.US_HuidigeRol = null;
                        _db.SubmitChanges();
                    }
                } else {
                    //no value
                    //check amount of roles
                    string[] roles = Roles.GetRolesForUser(userparams.aspnet_User.UserName);
                    if (roles.Length > 0) {
                        var role = _db.aspnet_Roles.First(q => q.LoweredRoleName == roles[0].ToLower());
                        userparams.US_HuidigeRol = role.RoleId;
                        Session["CurrentRole"] = role.LoweredRoleName;
                    }
                }
            }

        }
    }

, но, очевидно, это приводит к ошибкам во время выполнения.Session state is not available in this context.

  1. Как это исправить, и действительно ли это лучшее место для размещения этого кода?
  2. Как расширить пользователя (IPrincipal?) С помощью IsCurrentlyInRole без потери всех других функций
  3. Может быть, я делаю все это неправильно, и есть лучший способ сделать это?

Любая помощь очень ценится.

Ответы [ 2 ]

3 голосов
/ 18 февраля 2011

Да, вы не можете получить доступ к сеансу в Application_AuthenticateRequest.
Я создал свой собственный CustomPrincipal. Я покажу вам пример того, что я недавно сделал:

public class CustomPrincipal: IPrincipal
{
    public CustomPrincipal(IIdentity identity, string[] roles, string ActiveRole)
    {
        this.Identity = identity;
        this.Roles = roles;
        this.Code = code;
    }

    public IIdentity Identity
    {
        get;
        private set;
    }

    public string ActiveRole
    {
        get;
        private set;
    }

    public string[] Roles
    {
        get;
        private set;
    }

    public string ExtendedName { get; set; }

    // you can add your IsCurrentlyInRole 

    public bool IsInRole(string role)
    {
        return (Array.BinarySearch(this.Roles, role) >= 0 ? true : false);  
    }
}

Мой Application_AuthenticateRequest считывает куки, если есть билет аутентификации (пользователь вошел в систему):

protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
    HttpCookie authCookie = Request.Cookies[My.Application.FORMS_COOKIE_NAME];
    if ((authCookie != null) && (authCookie.Value != null))
    {
        Context.User = Cookie.GetPrincipal(authCookie);
    }
}


public class Cookie
    {
    public static IPrincipal GetPrincipal(HttpCookie authCookie)
    {
        FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
        if (authTicket != null)
        {
            string ActiveRole = "";
            string[] Roles = { "" };
            if ((authTicket.UserData != null) && (!String.IsNullOrEmpty(authTicket.UserData)))
            {
            // you have to parse the string and get the ActiveRole and Roles.
            ActiveRole = authTicket.UserData.ToString();
            Roles = authTicket.UserData.ToString();
            }
            var identity = new GenericIdentity(authTicket.Name, "FormAuthentication");
            var principal = new CustomPrincipal(identity, Roles, ActiveRole );
            principal.ExtendedName = ExtendedName;
            return (principal);
        }
        return (null);
    }
 }

Я расширил файл cookie, добавив в него UserData Аутентификационного билета. Я поместил дополнительную информацию здесь:

Это функция, которая создает cookie после регистрации:

    public static bool Create(string Username, bool Persistent, HttpContext currentContext, string ActiveRole , string[] Groups)
    {
        string userData = "";

        // You can store your infos
        userData = ActiveRole + "#" string.Join("|", Groups);

        FormsAuthenticationTicket authTicket =
            new FormsAuthenticationTicket(
            1,                                                                // version
            Username,
            DateTime.Now,                                                     // creation
            DateTime.Now.AddMinutes(My.Application.COOKIE_PERSISTENCE),       // Expiration 
            Persistent,                                                       // Persistent
            userData);                                                        // Additional informations

        string encryptedTicket = System.Web.Security.FormsAuthentication.Encrypt(authTicket);

        HttpCookie authCookie = new HttpCookie(My.Application.FORMS_COOKIE_NAME, encryptedTicket);

        if (Persistent)
        {
            authCookie.Expires = authTicket.Expiration;
            authCookie.Path = FormsAuthentication.FormsCookiePath;
        }

        currentContext.Response.Cookies.Add(authCookie);

        return (true);
    }

теперь вы можете получить доступ к своей информации в любом месте вашего приложения:

CustomPrincipal currentPrincipal = (CustomPrincipal)HttpContext.User;

, чтобы вы могли получить доступ к вашим пользовательским основным участникам: currentPrincipal.ActiveRole

Когда пользователь меняет свою роль (активную роль), вы можете переписать cookie.

Я забыл сказать, что я храню в authTicket.UserData сериализованный JSON класс, поэтому его легко десериализовать и проанализировать.

Вы можете найти больше информации здесь

0 голосов
/ 17 февраля 2011

Если вы действительно хотите, чтобы у пользователя была только одна активная роль за раз (что подразумевается при желании переопределить IsInRole), возможно, было бы проще всего хранить все «потенциальные» роли пользователя в отдельном месте, но только фактически позволяют им быть в одной роли аутентификации ASP.NET одновременно. Когда они выбирают новую роль, используйте встроенные методы, чтобы удалить их из текущей роли и добавить их в новую.

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