Как я могу облегчить доступ к своему пользовательскому IPrincipal в ASP.NET MVC? - PullRequest
9 голосов
/ 12 августа 2011

Я написал собственный основной объект, который содержит несколько дополнительных полей (адрес электронной почты и ИД пользователя в дополнение к имени пользователя).

Чтобы получить доступ к этим свойствам, мне нужно привести объект Context.User какмой пользовательский принципал.

@Html.GetGravitarImage((User as CustomPrincipal).Email)

Этот пользовательский принципал создается / десериализуется с помощью Application_AuthenticateRequest в моем global.ascx.Вы можете увидеть этот вопрос, который я задал здесь для получения дополнительной информации.

private void Application_AuthenticateRequest(Object source, EventArgs e)
{
    var application = (HttpApplication)source;
    var context = application.Context;

    // Get the authentication cookie
    string cookieName = FormsAuthentication.FormsCookieName;
    HttpCookie authCookie = context.Request.Cookies[cookieName];
    if (authCookie == null)
        return;

    var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
    context.User = CustomPrincipal.CreatePrincipalFromCookieData(authTicket.UserData);
}

Однако, если пользователь не аутентифицирован, то приведение к CustomPrincipal завершится неудачно (потому что это не такбудет введен в метод выше), и результат (пользователь как CustomPrincipal) вернет ноль, таким образом, давая мне исключение нулевой ссылки, когда мой метод выше пытается получить электронную почту.

Что было бы чистым решениемк этой проблеме?Я хочу упростить доступ к своему пользовательскому принципалу, и выполнение следующих действий кажется громоздким:

@Html.GetGravitarIcon((User is CustomPrincipal) ? (User as CustomPrincipal).Email : "Default Email")

Это единственный способ справиться с этой ситуацией?

Ответы [ 6 ]

3 голосов
/ 13 августа 2011

Я быстро что-то взбил. Один из возможных способов простого введения пользовательского IPrincipal в ASP.NET MVC заключается в следующем:

1) Создайте собственного потомка интерфейса IPrincipal.

public interface IMyPrincipal : IPrincipal
{
    Guid UserId { get; }
    string EmailAddress { get; }
}

2) Предположим, что вы используете провайдера ASP.NET для проверки подлинности ваших пользователей. Давайте быстро создадим реализацию IMyPrincipal, которая использует API членства.

public class MyPrincipal : IMyPrincipal
{
    private MembershipUser _user;

    public MyPrincipal()
    {
        this._user = Membership.GetUser();
        var userName = this._user != null ? this._user.UserName : String.Empty;
        this.Identity = new GenericIdentity(userName);
    }

    public Guid UserId
    {
        get 
        { 
            return this._user != null ? (Guid) this._user.ProviderUserKey : 
                                        default(Guid);
        }
    }

    public string EmailAddress
    {
        get 
        { 
            return this._user != null ? this._user.Email : null;
        }
    }

    public IIdentity Identity { get; private set; }
    public bool IsInRole(string role) { return false; }
}

3) Создайте свой собственный тип базового класса для ваших контроллеров. Скройте унаследованный член User и представьте своего собственного IPrincipal потомка.

public class BaseController : Controller
{
    protected virtual new MyPrincipal User
    {
        get { return HttpContext.User as MyPrincipal; }
    }
}   

4) Все ваши контроллеры наследуются от этого нового типа BaseController.

public class HomeController : BaseController
{
  //...
}

5) Создайте свою собственную фабрику контроллеров, чтобы убедиться, что ваш принципал введен в HttpContext / Thread.

public class MyControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance
        (RequestContext requestContext, Type controllerType)
    {
        try
        {
            var controller = base.GetControllerInstance(requestContext, controllerType);
            requestContext.HttpContext.User = Thread.CurrentPrincipal = new 
                                                    MyPrincipal();
            return controller;
        }
        catch (Exception)
        {
            return base.GetControllerInstance(requestContext, controllerType);
        }
    }
}

6) Зарегистрируйте фабрику контроллера в обработчике событий Application_Start () Global.asax.

var controllerFactory = new MyControllerFactory();
ControllerBuilder.Current.SetControllerFactory(controllerFactory);

Вуаля, теперь вы можете использовать нового пользователя (IMyPrincipal) в любом месте ваших контроллеров.

Например:

public ActionResult Index()
{
    ViewBag.Message = "Welcome to ASP.NET MVC!";

    ViewBag.UserId = User.UserId;
    ViewBag.UserName = User.EmailAddress;

    return View();
}
2 голосов
/ 12 августа 2011

Вы можете создать базовый класс и переопределить свойство «Пользователь», используя ключевое слово «new», или создать метод расширения, подобный этому:

public static class ControllerExtensions
{
    public static CustomPrincipal CustomPrincipal(this Controller controller)
    {
        if(controller.User is CustomPrincipal)
        {
            return controller.User as CustomPrincipal;
        }
        return null; // maybe return an empty object instead to get around null reference...
    }
}
1 голос
/ 23 ноября 2012

Лучший способ сделать вашу реализацию IPrincipal доступной на ваших страницах Razor с помощью ASP.NET MVC - это сделать следующее:

  1. Реализовать интерфейс System.Security.Principal.IPrincipal.
  2. Реализуйте интерфейс System.Security.Principal.IIdentity.
  3. В Global.asax определите метод для: void Application_AuthenticateRequest(Object, EventArgs), который сохраняет обе ваши реализации IPrincipal и IIdentity.
  4. Создайте метод расширениядля IPrincipal для предоставления вашей реализации IIdentity.
  5. Наконец, добавьте пространство имен для предыдущего метода расширения в файле web.config в <system.web.webPages.razor>.

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

Hello @User.CustomIdentity().FirstName @User.CustomerIdentity().LastName!

Эти шаги являются кратким и кратким описанием хорошо подробной статьи, написанной здесь: http://rizzo7.blogspot.com/2012/04/mvc-30-razor-custom-principal-and.html

0 голосов
/ 12 августа 2011

Если вы не авторизованы, вы можете установить для объекта пользователя определенный экземпляр пользовательского участника со значениями по умолчанию:

if (authCookie == null)
{
    context.User = CustomPrincipal.Default; // Or CreateDefault()
    return;
}
0 голосов
/ 12 августа 2011

Вы также можете создать методы расширения для Email и UserID так же, как ответ Джона Калберера:

public static class CustomPrincipalExtensions
{
    public static string Email(this CustomPrincipal cUser)
    {
        return cUser != null ? cUser.Email : "Default Email"
    }

    public static string UserID(this CustomPrincipal cUser)
    {
        return cUser != null ? cUser.UserID : "Default ID"
    }
}
0 голосов
/ 12 августа 2011

Вы можете создать какой-либо служебный метод или добавить метод к одному из ваших сервисов, который проверяет, является ли он вашим пользовательским принципалом. Может быть что-то вроде:

public class UserService : IUserService
{
    public CustomPrincipal CurrentUser
    {
        get
        {
            CustomPrincipal user = HttpContext.Current.User as CustomPrincipal;

            if (user == null)
                return GuestUser; // Just some default user object

            return user;
        }
    }
}
...