NET 6 WebAPI - powiązanie tokena z użytkownikiem

NET 6 WebAPI - powiązanie tokena z użytkownikiem
AdamWox
  • Rejestracja:ponad 7 lat
  • Ostatnio:około 9 godzin
  • Lokalizacja:Jastrzębie-Zdrój
  • Postów:2161
0

Witam.
Potrzebuje stworzyć mały serwer licencji do oprogramowania okienkowego. Stanęło na API, które będzie przechowywać odpowiednie informację, z którym to aplikacja okienkowa będzie się komunikować i podejmować odpowiednie decyzje.

Oprócz jakichś zmyślnych "kluczy", chciałbym też generować token, który byłby powiązany z danym klientem i jego licencją. Na tej podstawie również może działać wygaśnięcie licencji, ponieważ ważności tokena może o tym dodatkowo decydować.

Czy jedynym wyjściem jest wpisanie tokenów do bazy?

ID VAT_NUMBER EMAIL TOKEN EXPIRES_AT

Domyślam się, że wtedy też trzeba będzie zrobić jakiś middleware do atrybutu [Authorize], albo własny [CustomAuthorize], który to poprawnie zweryfikuje i zwróci odpowiedni response code.

Ogólnie to chciałbym, aby token nie był "uniwersalny", że dochodzi do niestandardowej autoryzacji. Żeby inny user nie mógł użyć tokena drugiego.

Aventus
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:UK
  • Postów:2235
1

Dosyć to abstrakcyjne więc ciężko coś jasno odpowiedzieć. Masz na myśli używanie swojego własnego tokena? Rozważałeś użycie JWT? Wtedy nie będziesz musiał wpisywać tego do bazy, bo wszelkie potrzebne informacje możesz przekazać w formie claimów.


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
edytowany 1x, ostatnio: Aventus
_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:3 miesiące
0

Najprostsze rozwiązanie: - W przypadku autoryzacji tokenem, przekazujesz ten jako login słowo np: "<Tokien>" zaś sam tokien przekazujesz jako hasło.
Więc tak jakby zostaje zalogowany użytkownik "<Tokien>".
W zasadzie jedyna zmiana w poleceniu SQL sprawdzającym czy można się zalogować.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
AdamWox
  • Rejestracja:ponad 7 lat
  • Ostatnio:około 9 godzin
  • Lokalizacja:Jastrzębie-Zdrój
  • Postów:2161
0

Tak, JWT. Tylko czy takie dane nie są zbyt "otwarte"? Takie JWT można edytować za pomocą jwt.io/. Czy już za daleko z tym idę i nikt nie jest na tyle mądry? Robienie jakichś hashy na podstawie sprzętu chyba już jest staroświeckie. Wiem, że licencjonowanie "online" jest najlepsze, ponieważ niczego nie muszę hardcodować, a żaden cwaniak mi tego nie skopiuje i nie zacznie używać bez mojej wiedzy/zgody.

Stąd też dodatkowa weryfikacja za pomocą tokena. Czyli, aby oprogramowanie klientowi działało to potrzebuje mieć numer nip w bazie. W naszym przypadku jest on wpisany w Comarch Optima i ten sam nip byłby u nas w bazie API, email do powiadomień, ze subskrypcja się kończy no i token, który dodatkowo zabezpieczyłby sparowane oprogramowanie.

SZ
  • Rejestracja:prawie 11 lat
  • Ostatnio:około 5 godzin
  • Postów:1492
1
AdamWox napisał(a):

Tak, JWT. Tylko czy takie dane nie są zbyt "otwarte"? Takie JWT można edytować za pomocą jwt.io/.

No możesz edytować ale nic Ci to nie da xD

_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:3 miesiące
0

Skoro widzisz to jako dodatkowe zabezpieczenie to wszystko to nie ma żadnego sensu, tylko utrudnisz logowanie.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
edytowany 1x, ostatnio: _13th_Dragon
Aventus
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:UK
  • Postów:2235
4

Tokeny JWT można edytować, ale wtedy ich sygnatura nie będzie się zgadzać. Innymi słowy, weryfikując token sprawdzasz czy został on przez Ciebie podpisany, i niezmieniony. Token podpisuje się za pomocą sekretu, i sprawdza za pomocą tegoż sekretu (synchroniczny token) lub publicznego klucza (niesynchroniczny token). Oczywiście jeśli weryfikujesz za pomocą teog samego sekretu, to musi się to odbyć tylko przez serwer który ten sekret posiada i z nikim się nie dzieli. W przypadku kluczy publicznych sprawa jest prostsza, bo będziesz mógł go sprawdzić przez jakiegokolwiek klienta, nawet po stronie Twojej aplikacji okienkowej.

Ze względu na to że token nie jest szyfrowany, to ważne aby nie przechowywać w claimach żadnych sekretów/poufnych informacji.

EDIT: Inna sprawa żę JWT nie rozwiązuje wszystkich problemów, jeśli np. zależy Ci na odwoływaniu tokenów przed ich wygaśnięciem. Wtedy będziesz musiał mieć jakiś stan sesji na serwerze.


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
edytowany 2x, ostatnio: Aventus
AdamWox
  • Rejestracja:ponad 7 lat
  • Ostatnio:około 9 godzin
  • Lokalizacja:Jastrzębie-Zdrój
  • Postów:2161
0

Ok, teraz rozumiem. Czyli generalnie rzecz biorąc ten token nie jest mi potrzebny do niczego, oraz mogę zrezygnować z samego [Authorize] w API, ponieważ wtedy jeden i ten sam token mógłby działać u każdego z klientów? Nikt, ręcznie, nie będzie mógł tego tokena wygenerować, tylko ja, osobnym oprogramowaniem dostępnym u mnie na serwerze. Token generowałby się w momencie dopisywania nowego klienta lub podczas odświeżania w razie wygaśnięcia licencji.

EDIT
Jedyne co, to własną weryfikacje NIP, Email i innych zmyślnych głupot.

edytowany 1x, ostatnio: AdamWox
_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:3 miesiące
0

Raczej tokien ma krótki żywot (przeważnie) ewentualnie jego czas życia określony przez samego użytkownika.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
AdamWox
  • Rejestracja:ponad 7 lat
  • Ostatnio:około 9 godzin
  • Lokalizacja:Jastrzębie-Zdrój
  • Postów:2161
0

Ja mogę zdefiniować w API jaki żywot ma mieć token.

Aventus
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:UK
  • Postów:2235
1

Tak, chociaż tak jak napisałem w edycji posta, wygasanie licencji wymagałoby dodatkowej obsługi po Twojej stronie. Token ma czas ważności, i raz wygenerowany z takim czasem ważności nie może zostać zmieniony. Więc bez podjęcia odpowiednich kroków, nawet jeśli w Twoim systemie już by nie było takiej licencji, techniczne token nadal byłby ważny.

Ja mogę zdefiniować w API jaki żywot ma mieć token.

A co jeśli okaże się że musisz anulować licencję wcześniej?


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
AdamWox
  • Rejestracja:ponad 7 lat
  • Ostatnio:około 9 godzin
  • Lokalizacja:Jastrzębie-Zdrój
  • Postów:2161
0

W tabeli miałby kolumnę ExpiresAt, która by przyjmowała datę wygaśnięcia licencji. Jeśli token byłby dalej ważny to nie przejdzie dalsza weryfikacja. To samo tyczyłoby się anulacji licencji.

SP
SP
  • Rejestracja:prawie 3 lata
  • Ostatnio:ponad 2 lata
  • Postów:181
1

Robisz na tej aplikacji zwykłe logowanie, po logowaniu możesz token zwrócić i refresh token, jeśli ktoś będzie używał dwóch tokenów to jak jeden wygaśnie, użyje refresh tokena, drugi ukradnięty token zostanie użyty to też wymusi refresh tokena przez co wykryjesz drugie użycie tokena refresh i możesz odciąć użytkownika bo ktoś mu się włamał.

Ale jak użytkownik kupił licencję to i tak musi mieć pełne prawo do produktu więc przy zalogowaniu musi mieć zawsze możliwość odzyskać dostęp.

Token JWT działa na zasadzie synchroniczny hmac-sha256, co w skrócie za pomocą hasła skomplikowanego klucza randomowego, wykonujesz podpis na danych jego login/id, exp/expires i tu podajesz jak długo ma być żywy token.
Token dajesz użytkownikowi.

Jak użytkownik wyśle token z zapytaniem do api, to serwer sprawdza czy podpis się zgadza za pomocą hmac-sha256 potem sprawdza expires czy nie wygasł i jak jest wszystko git to daje dostęp.


Knowledge Distiller
Aventus
Pominąłeś scenariusz w którym licencja wygasa/zostaje anulowana wcześniej niż token.
SP
Szalony Programista2
A w sumie myślałem, że historię zakupów licencji będzie trzymał na swoim serwerze w bazie, jak aplikacja nie będzie wymagała api z jakimiś danymi do działania to i tak wszystko będzie podane na tacy i pewnie pójdzie obejść i tak.
Aventus
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 2 lata
  • Lokalizacja:UK
  • Postów:2235
0
AdamWox napisał(a):

W tabeli miałby kolumnę ExpiresAt, która by przyjmowała datę wygaśnięcia licencji. Jeśli token byłby dalej ważny to nie przejdzie dalsza weryfikacja. To samo tyczyłoby się anulacji licencji.

To oznacza że każda weryfikacja będzie się musiała odbywać poprzez komunikację z serwerem (wspomniana wcześniej przeze mnie stanowość). Niekoniecznie to coś złego- po prostu coś z czego należy sobie zdawać sprawę. W takim przypadku faktycznie równie dobrze mógłbyś się obejść bez JWT, i stworzyć jakiś własny, uproszczony token.

Tylko mam wrażenie że zatoczyłeś koło, bo przecież w pierwszym poście sugerowałeś że chcesz uniknąć trzymania czegoś w bazie.


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
AdamWox
  • Rejestracja:ponad 7 lat
  • Ostatnio:około 9 godzin
  • Lokalizacja:Jastrzębie-Zdrój
  • Postów:2161
0

Bardziej mnie martwiło bezpieczeństwo trzymania tokenów w bazie, stąd pytanie czy to jedyne wyjście. A, że takiego typu licencjonowanie i zabezpieczenia robię pierwszy raz to chciałbym obrać jakiś jeden kierunek na przyszłość i tylko dopisywać licencje do odpowiedniego oprogramowania.

PS.
Wątpię, aby ktoś z naszym oprogramowaniem chciał się bawić w nielegalne kopiowanie. Szefy się uparły, że ma być, bo myślą, że ten program jest złotem i każdy będzie je chciał 😅

SP
Szalony Programista2
żeby wykryć kradzież tokena będziesz musiał trzymać historię refresh tokenów, ale jak dasz użytkownikowi całą aplikację, w której będzie wszystko potrzebne do działania i nie będzie niczego z neta potrzebował to i tak może sobie zcrackować. Tokenów raczej nie trzeba nigdzie trzymać bo one same się udowadniają, trzymasz tylko sekret i jak po wykonaniu hmac-sha256 z tym sekretem na tokenie, który ci wysłał użytkownik nie wyjdzie ci taka sama sygnatura jaką ci przysłał użytkownik, a on nie zna sekretu żeby taki token zrobić, to wiesz, że jest invalid.
SZ
  • Rejestracja:prawie 11 lat
  • Ostatnio:około 5 godzin
  • Postów:1492
0

Mi się wydaje, że nie jest potrzebny żaden JWT.
Pytanie jest takie jak chcesz, żeby to działało po zarejestrowaniu. Czy przy każdym uruchomieniu ma walidować ważność licencji?

Kiedyś siedziałem w nauce jazdy. Kupowałem program do egzaminu wewnętrznego. Opierało się to na podobnym rozwiązaniu. Tzn Uruchamiales program i wymagał podania klucza licencyjnego, Po wklepaniu klucza leciał request do serwera licencyjnego. Wracała odpowiedź że ważdny to tego i tego dnia. Potem czy offline czy online program działał. Ale jak np usunąłem program i ponownie zainstalowałem to nie mogłem użyć drugi raz tej licencji tylko był telefon do firmy o odblokowanie w celu ponownej rejestracji.

SP
Szalony Programista2
W tym wypadku, program do tej nauki miał algorytm do wyliczania licencji, który można odwrócić i zrobić generator dowolnej lub ze zmiany warunku sprawdzającego licencję na instrukcję NOP no operations. Ale zwykle takie zabezpieczenia wystarczają, jeszcze trochę zaciemnienia kodu, obfuskacji i może nikomu nie będzie się chciało przez to przebijać.
SZ
No nie zrobisz generatora bo licencja była zarejestrowana na konkretną firme. I jeśli producent nie miał takich danych na serwerze licencyjnym to generowanie ponownej licencji nic nie dało
SP
Szalony Programista2
Jeśli musiałeś na serwer wysyłać licencje to tak, jeśli lokalnie aplikacja sprawdzała czy się zgadza to nie.
AdamWox
  • Rejestracja:ponad 7 lat
  • Ostatnio:około 9 godzin
  • Lokalizacja:Jastrzębie-Zdrój
  • Postów:2161
0

Nie bardzo mogę to w ten sposób zrobić, ponieważ to są dwa programy, jeden jest usługą windows, który ogarnia całą logikę. Okno jest tylko do konfiguracji tej usługi. Zapytanie o ważność licencji leciałoby przy każdym wywołaniu zadania. Oprogramowanie bazuje na danych z internetu - Allegro, Baselinker, IdoSell, więc brak internetu nie popsuję licencjonowania, ponieważ brak połączenia do serwera licencji będzie najmniejszym problemem jeśli żadne dane nie zostaną przetworzone. Teraz teoretycznie wszystko zależy od instalatora - jeśli ktoś przeinstaluje program na tej samej maszynie to konfiguracja zostanie i licencja będzie aktywna. Jeśli zainstaluje na innym komputerze to trzeba będzie nową licencję, albo istniejącą zamienić na nowym sprzęcie.

AdamWox
  • Rejestracja:ponad 7 lat
  • Ostatnio:około 9 godzin
  • Lokalizacja:Jastrzębie-Zdrój
  • Postów:2161
0

Zastanawia mnie jeszcze jedno. Biorąc przykład Allegro:

  1. Token jest powiązany z danym kontem użytkownika
  2. Jeśli pobiorę zamówienie używając tokenu z innego konta to dostaje NotFound

Jak taki system łączy to wszystko? Czy to nie jest przypadkiem to samo co ja chciałem uzyskać?

G1
  • Rejestracja:około 4 lata
  • Ostatnio:8 dni
  • Postów:506
0

Ja bym zrobił to najprościej jak się da z użyciem JWT:

  1. Dodajesz do dbContext tabelę:
Kopiuj
public class Subscription
    {
        public Guid Id { get; set; }
        public Guid ApplicationUserId { get; set; }
        public DateTime? ExpiryTime { get; set; }
    }
  1. W akcji API dodajesz [Authorize(AuthenticationSchemes = "Bearer")], nie zapominając o AddJwtBearer()

  2. Na podstawie zalogowanego użytkownika pobierasz licencje, które posiada i tyle w temacie. :)

Kopiuj
var currentUser = await _userManager.GetUserAsync(User);
var activeSubsriptions = await _subscriptionManager.GetAllActiveForUser(currentUser.Id);
AdamWox
  • Rejestracja:ponad 7 lat
  • Ostatnio:około 9 godzin
  • Lokalizacja:Jastrzębie-Zdrój
  • Postów:2161
0

Po pierwsze nie używam EF, ale to akurat ma najmniejsze znaczenie. Po drugie, nikt się nigdzie nie loguje w takim sensie, że nie ma do tego żadnego frontu. API w tym przypadku jest transparentne A atrybut [Authorize] zadziała dla każdego kto ma token. Ja chce żeby API rzuciło dane tylko tego użytkownika, którego jest token.

USER 1 => token XYZ => nip 123
USER 2 => token ABC => nip 456

Jeśli odpytam API podając nip 456 ale używając tokena XYZ, to powinno zwrócić 404

G1
  • Rejestracja:około 4 lata
  • Ostatnio:8 dni
  • Postów:506
1

Nieistotne jakiej bazy używasz. Daję Tobie przykład dla Jeśli odpytam API podając nip 456 ale używając tokena XYZ, to powinno zwrócić 404

Kopiuj
public class Subscription
    {
        public Guid Id { get; set; }
        public Guid ApplicationUserId { get; set; }
        public string NIP { get; set; }
        public DateTime? ExpiryTime { get; set; }
    }
 [Authorize(AuthenticationSchemes = "Bearer")]
 public async Task<IActionResult> Example([FromQuery]ExampleInput input)
 {
    var currentUser = await _userManager.GetUserAsync(User);
    var activeSubsriptions = await _subscriptionManager.GetAllActiveForUser(currentUser.Id, input.NIP);
    if(activeSubsriptions == null)
      return NotFound();

Po prostu stwórz ten token ręcznie i wczytaj dynamicznie do aplikacji

edytowany 1x, ostatnio: gswidwa1

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.