2015-04-16 4 views
2

Я разрабатываю веб-приложение с использованием Asp.Net MVC6 (vNext), Identity 3.0. * Beta3. Это трехуровневое приложение с пользовательским интерфейсом, службами и БД. Я могу зарегистрировать пользователя с классом Asp.net SignInManager, и я пытаюсь получить информацию о пользователе с ролями & претензий на уровне службы, чтобы я мог проверить, имеет ли пользователь разрешение на выполнение определенных действий.Thread.CurrentPrincipal Identity.Name is null в asp.net mvc 6 (vNext)

Как получить текущее имя пользователя из текущего идентификатора запроса запроса на уровне обслуживания. В MVC 5 я использовал Thread.CurrentPrincipal для этого. Но в MVC6 Identity.Name из Thread.CurrentPrincipal установлено значение null.

Может ли кто-нибудь дать мне знать, как я могу это сделать? Кроме того, если у вас есть лучшее решение, сообщите мне.

+0

Я знаю, что главный объекта HttpApplication настроенной нити к HttpContext, когда он получает нить. Вы пробовали HttpContext.Current.User, тоже null? –

+0

@ RazvanDumitru Спасибо за ответ. Можете ли вы сообщить мне, как получить HttpContext на уровне службы? – neomanni

+0

ASP.Net 5 написан таким образом, чтобы его можно было полностью тестировать с минимальным количеством статических свойств. Таким образом, такие значения, как главный пользователь, должны быть переданы в ваш уровень обслуживания в качестве параметра. (На самом деле это не ответ, а рекомендация следовать принятым шаблонам проектирования.) Кроме того, поскольку способ «асинк» меняет ситуацию, информация, зависящая от потока, может быть потеряна. –

ответ

1

Может быть, есть лучший способ. Но сейчас я добавляю специальное промежуточное программное обеспечение, как в следующем коде, чтобы ввести ussername в текущий поток в классе startup.cs. И в слое службы я буду читать его с помощью Thread.GetData (Thread.GetNamedDataSlot («current-username»)).

public class Startup { 

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory) 
    { 

     //.... code 

     app.UseIdentity(); 

     //... more code 

     app.Use(async (ctx, next) => 
     { 
      var httpContext = (ctx as HttpContext); 
      if (httpContext.User.Identity.IsAuthenticated) 
      { 
       Thread.SetData(Thread.GetNamedDataSlot("current-username"), httpContext.User.Identity.Name); 
      } 
      await next(); 
     }); 

     //... more code 

     app.UseMvc(routes => 
      { 
       routes.MapRoute(
        name: "default", 
        template: "{controller}/{action}/{id?}", 
        defaults: new { controller = "Home", action = "Index" }); 
      }); 

    } 
} 
+2

Написание собственного кода, связанного с безопасностью, чревато опасностью. E.g. здесь, если аутентифицированный пользователь делает запрос, они попадают в слот потока. Если пользователь, не прошедший проверку подлинности, затем делает запрос, и он происходит по одному и тому же потоку, вы не очищаете имя пользователя, поэтому они все равно будут аутентифицированы как первый пользователь ==, вы только что открыли себя для взлома. Если (! HttpContext.User.Identity.IsAuthenticated), то .... очистить слот проверки подлинности нити –

+0

Спасибо Jon. Я действительно очищаю слот после того, как прочитал его на сервисном уровне. Мне нужно только одно имя пользователя для запроса. Но вы подняли хороший пионт. Я хочу, чтобы был лучший способ сделать это. – neomanni

+1

Кроме того, использование статических данных потоков, подобных этому, напрямую, приведет к грусти, как только вы начнете использовать методы async. Теперь вы также затруднили тестирование своего уровня обслуживания, поскольку он напрямую обращается к локальным данным потока, вместо того, чтобы объявлять зависимость от IHttpContextAccessor, которую можно издеваться. –

2

Предполагая, что вы можете передавать услуги доступа в вашем слое, эквивалент HttpContext.Current является IHttpContextAccessor.HttpContext, который является службой выставляемого хостинга слоем.

2

Если вы вызвали AddIdentity() в свой Startup.cs или где бы вы ни настраивали инъекцию зависимостей, он автоматически регистрирует однотонный HttpContextAccessor как удовлетворяющий службе IHttpContextAccessor.

На этом этапе в вашем сервисном слое вы можете ввести IHttpContextAccessor и получить контекст оттуда. Это предполагает, что вы понимаете, как работает система Injection Dependency, и использует ее для создания экземпляров ваших классов уровня обслуживания, а не только new.

Если вы хотите, чтобы иметь возможность удобно получить доступ к Id или Name из ClaimsPrincipal, которая подвергается в HttpContext убедитесь, что вы импортируете System.Security.Claims, так что у вас есть доступ к расширениям, которые предоставляют Вам с методами расширения GetUserName() и GetUserId().

(Это уточненный как из beta4 пакетов, которые были выпущены с VS2015 RC1)

+0

Я бы даже рекомендовал сделать этот шаг дальше и полностью удалить любое упоминание о чем-либо «HttpContext», связанном с вашим кодом, так как все, что вы действительно хотите, это услуга, которая дает вам текущий «ClaimsPrincipal». Создайте интерфейс ICurrentClaimsPrincipal, который предоставляет свойство CurrentProincipal. Создайте класс, который его реализует, который использует зависимость 'IHttpContextAccessor' для чтения текущего принципала и возвращает его из свойства CurrentPrincipal. –

+0

Полный пример: https://gist.github.com/cherrydev/5c7168c8947eb1a1b5b8 –

Смежные вопросы