BG Development


  Reply to this topicStart new topicStart Poll

> Създаване на HttpContext след валидация на токен, ASP.NET Core 2
relax4o
Публикувано на: 05-03-2020, 16:44
Quote Post



Име:
Група: Потребител
Ранг: Почетен член

Мнения: 2554
Регистриран на: 04.04.07



Здравейте.

Преди 2 месеца някъде 2-ма колеги от моя екип създадоха база за API на .NET Core.
Преди да продължа с въпроса си, ще кажа, че основно пишем на PHP и де факто никой не е имал взимане даване с .NET като цяло.

Този проект е създаден на база четене на статии, документации и т.н. и голяма част ми се струва, че е написана типично като PHP програмист.

Като цяло бих казал, че REST API в нашия случай не е въобще REST API, но това настрана.


Използваме автентикация чрез JWT токен. Накратко като информация, в нашите системи идентифицираме потребителите си по userId и firmId. Това е така, понеже един потребител може да подлежи на няколко фирми.

Към същността на въпроса ми:

В JwtBearerEvents, при OnTokenValidation се екстрактват userId и firmId от payload-а на токена, за да се установи потребителя. Това, което не ми харесва след това е, че колегата е създал DTO, в което подава данните, след което това DTO го добавя към

CODE

context.HttpContext.Items['some-key-here'] = new SomeDto(userId, firmId);


Идеята му е след това в контролера, когато се изпълнява някой action лесно да може да вземе данните за потребителя. Може би, за да спести редове, знам ли.
Всичко хубаво и удобнно, но ми изглежда грешно.

До колкото знам, в контекста на контролера имам User.Identity и мога да взема всички Claims, които са подадени на токена.

Правилно ли е да се записват по този начин данни в HttpContext или по-правилно да си използваме User.Identity въпреки че ще увеличи размера на методите в контролерите?
Тази информация естествено ни трябва, за да можем да вземем информация от базата данни.

Не съм сигурен какви са точно best practices за това и е трудно да се намери информация в интернет. Всеки де факто си драска, както си иска и го приема за правилно.

Ако случайно имате и добри примери за проекти в гитхъб ще е още по-добре.


П.П. За да не питате защо не питам него защо така го е направил, ще кажа, че с него не се говори нормално и де факто няма да ми даде основателна причина.

Това мнение е било редактирано от relax4o на 05-03-2020, 16:46


--------------------
Бисери :D

QUOTE (oveRLuckEd)
Ползваш някоя нова версия на PHP, която е вече ооп ориентирана и заради това ти я изкарва тази грешка.


QUOTE (nbacool2)
Щом няма input полета, значи няма откъде да се направи SQL инжекция Very Happy
PM
Top
r4nd0m
Публикувано на: 05-03-2020, 17:23
Quote Post



Име:
Група: Потребител
Ранг: Почетен член

Мнения: 1125
Регистриран на: 05.09.07



Това за User.Identity зависи от Authentication-а

в Startup.cs трябва да има нещо от сорта

CODE

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)


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

CODE

HttpContext.User.Claims.Where( c => ...)


edit:

ако забелязваш тези неща с юзъра пак са в HttpContext

Това мнение е било редактирано от r4nd0m на 05-03-2020, 17:25


--------------------
"Happiness only real when shared."
PMEmail Poster
Top
relax4o
Публикувано на: 05-03-2020, 17:58
Quote Post



Име:
Група: Потребител
Ранг: Почетен член

Мнения: 2554
Регистриран на: 04.04.07



QUOTE (r4nd0m @ 05-03-2020, 17:23)
Това за User.Identity зависи от Authentication-а

в Startup.cs трябва да има нещо от сорта

CODE

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)


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

CODE

HttpContext.User.Claims.Where( c => ...)


edit:

ако забелязваш тези неща с юзъра пак са в HttpContext

Да, да. Всичко това е ясно.

Въпроса тука беше: правилно ли е да създаваш DTO, което да съдържа userId и firmId и да го добавяш като нов item в HttpContext, когато валидацията на токена преминава, или е удачно да взимаш нужните claims във всеки индивидуален контролер/акшън, по начина, който си показал в последния ти код блок?

Идеята на колегата очевидно е да подава информация към репота и сървиси чрез подаване на това DTO, вместо да подава двете ID-та самостоятелно.


Сега също чета за UserManager също. Някои хора го използват, но не съм сигурен дали е удачно за API.
Доста варианти за имплементиране на автентикация и идентифициране на потребителя има, но колкото повече информация абсорбирам, толкова повече се объркваш кое в каква ситуация се използва. icon_lol.gif

П.П. Ето какво се случва в момента при валидация.

CODE

x.Events = new JwtBearerEvents
{
   OnTokenValidated = context =>
   {
       var userId = int.Parse(context.Principal.FindFirst(ClaimTypes.NameIdentifier).Value);
       var firmId = int.Parse(context.Principal.FindFirst(MyClaimTypes.FirmId).Value);

       context.HttpContext.Items[MyApiConstants.FirmUserDtoKey] = new FirmUserDto(firmId, userId);

       return Task.CompletedTask;
   }
};


и следователно, където е нужно, се взима в акшъна

CODE

var firmUserDto = HttpContext.Items[MyApiConstants.FirmUserDtoKey] as FirmUserDto;


Това мнение е било редактирано от relax4o на 05-03-2020, 18:00


--------------------
Бисери :D

QUOTE (oveRLuckEd)
Ползваш някоя нова версия на PHP, която е вече ооп ориентирана и заради това ти я изкарва тази грешка.


QUOTE (nbacool2)
Щом няма input полета, значи няма откъде да се направи SQL инжекция Very Happy
PM
Top
r4nd0m
Публикувано на: 05-03-2020, 18:40
Quote Post



Име:
Група: Потребител
Ранг: Почетен член

Мнения: 1125
Регистриран на: 05.09.07



Ако всички контролери ще искат тая информация не виждам нищо притеснително в

CODE

app.Use(async (context, next) =>
{
   context.Items["some-key"] = someValue
   await next.Invoke();
});


но ако искаш да е с claims просто на user - dto-то му кажи да наследи IClaimsTransformation и имплементирай

CODE

public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)


после в DI-a

CODE

services.AddScoped<IClaimsTransformation, UserInfoClaims>();


и вместо user обект ще имаш истински claim icon_smile.gif

Това мнение е било редактирано от r4nd0m на 05-03-2020, 18:41


--------------------
"Happiness only real when shared."
PMEmail Poster
Top
relax4o
Публикувано на: 05-03-2020, 18:56
Quote Post



Име:
Група: Потребител
Ранг: Почетен член

Мнения: 2554
Регистриран на: 04.04.07



Ще разгледам твоето предложение, благодаря.

Също намерих и друго предложение, с extension method.

CODE

public static FirmUserDto GetFirmUserDto(this IPrincipal principal)
{
   var claimsIdentity = (ClaimsIdentity)principal.Identity;

   var userId = int.Parse(claimsIdentity.FindFirst(ClaimTypes.NameIdentifier).Value);
   var firmId = int.Parse(claimsIdentity.FindFirst(MyClaimTypes.FirmId).Value);

   return new FirmUserDto(firmId, userId);
}


и след това, където ми трябва чрез User.

CODE

var user = User.GetFirmUserDto();


което изглежда доста удобно и чисто.


--------------------
Бисери :D

QUOTE (oveRLuckEd)
Ползваш някоя нова версия на PHP, която е вече ооп ориентирана и заради това ти я изкарва тази грешка.


QUOTE (nbacool2)
Щом няма input полета, значи няма откъде да се направи SQL инжекция Very Happy
PM
Top
0 потребители преглеждат тази тема в момента (0 гости, 0 анонимни потребители)
Потребители, преглеждащи темата в момента:

Topic Options Reply to this topicStart new topicStart Poll

 


Copyright © 2003-2019 | BG Development | All Rights Reserved
RSS 2.0