luchob / softuni-spring-may-2024

Our common projects
16 stars 1 forks source link

Как може да се достъпи информация за логнатия user от navbar-a? #33

Closed ChrisHartarski closed 2 months ago

ChrisHartarski commented 2 months ago

Връзка към проекта: https://github.com/ChrisHartarski/MagnaTechnica-WebShop-SoftUniProject

Кратко описание:

  1. Какво очаквате да се случи В navbar имам 3 места, на които имам нужда от информация за логнатия user. = Когато user се логне в навбара се появява Welcome, {user full name} = В dropdown менюто като се кликне на "Welcome..." има Update profile където имам нужда от id (желания линк е /users/edit/{id}) = Когато логнатия user е с USER роля се появява иконка с количка в която в кръгче има броя на артикулите в количката (за по-кратко cartSize). Тази информация я имам в UserEntity и в CurrentUserDetails(implementing UserDetails).

Целта е в template-а на navbar-а да мога да достъпя тази информация. Тъй като нямам GetMapping за navbar няма как да създам модел в който да подам информация за @AuthenticationPrincipal.

  1. Какво всъщност се случва

  2. (Желателно) Какво опитахте Пробвах да достъпя чрез principal, но ми връща грешка, че principal.username е null.

Стъпки за репродуциране: Admin user credentials: email: admin@mail pass: asdasd

User user credentials: email: user01@mail pass: asdasd

За генериране на продукти в Spare Parts: login с ADMIN user -> Admin Panel -> Initialize Mock DB button

За добавяне на продукти в количката: login С USER user -> Spare Parts -> добавяте количество на част и Add to Cart бутон.

Благодаря!

luchob commented 2 months ago

Здравей!

Първо, допускам че имаш разширението за интеграцията със spring security

    implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'

Оттам нататък, един малък "recap":

  1. В "сърцето" на спринг секюрити има един обект Authentication в който са пази текущо аутентикирания принципал.
  2. Този принципал в нашия случай е същотото, което връща юзър детайл сървиса. Напр. в mobilele това е MobileleUserDetailsService който има метод fullName.

Навсякъде в темпейтите имаш достъп до Authentication-a (+principal-a) и той може да се осъществи по поне два начина.

Начин 1:

С помощта на authentication помощен обект:

      <div sec:authorize="isAuthenticated()">
          <div th:text="${#authentication.principal.fullName}">
              Pesho
          </div>
      </div>

Начин 2:

С помощта на thymeleaf-extra-та от секюрити диалекта, който споменах в началото:

        <div sec:authorize="isAuthenticated()">
          <div sec:authentication="principal.fullName">
              Anna
          </div>
        </div>

⚠️⚠️⚠️⚠️ Работи само докато си логнат, иначе principal e null. ⚠️⚠️⚠️⚠️

Забележка:

Ако става въпрос за логнат юзър не е правилно да използваш /users/edit/{id} тъй като това загатва че можеш да редактираш не само логнатия юзър :-)

Надявам се да помогне това.

Поздрави, Л.

ChrisHartarski commented 2 months ago

Мисля, че го подкарах да работи, но не знам дали това е най-добрия начин.

Не знам защо дори когато имах логнат user #authentication.principal.username ми връщаше null.

Създадох UserHelperService, който чрез SecurityContextHolder ми връща UserDetails, което го мапвам към CurrentUserDetails(допълнен UserDetails с малко допълнителна информация от UserEntity). В template-а викам th:text="${@userHelperService.getCurrentUserDetails().getFullName()}" и по този начин работи, но не знам дали е оптимално.

Колкото до /users/edit/{id} в контролера имам допълнителна проверка дали това id от линка е същото като id на логнатия user. Като се замисля, мога да го направя линка да е само /users/edit и по default да си взима данните за логнатия user. Благодаря!

luchob commented 2 months ago

И аз не знам, защо е връщало null :-) Сега дръпнах проекта и това нещо:

<a class="nav-link dropdown-toggle" id="navbarDropdownUser" role="button" data-bs-toggle="dropdown" aria-expanded="false">
                            Welcome,
<!--                            <span th:text="${@userHelperService.getCurrentUserDetails().getFullName()}">{user full name}</span>-->
                            <span th:text="${#authentication.principal.username}">{user full name}</span>
                            !
                        </a>

си изписва очакваното:

Screenshot 2024-07-13 at 11 43 19

Виждам, че си се спрял и на подхода описан по-горе, който също работи. И твоето си работи, всичко работи :)))

Поздрави, Л.