Zabezpieczanie aplikacji Java Spring Boot przy użyciu identyfikatora Entra firmy Microsoft
W tym artykule przedstawiono aplikację internetową Java Spring Boot, która loguje użytkowników w dzierżawie identyfikatora Entra firmy Microsoft przy użyciu biblioteki klienta Microsoft Entra ID Spring Boot Starter dla języka Java. Używa on protokołu openID Połączenie.
Na poniższym diagramie przedstawiono topologię aplikacji:
Aplikacja kliencka używa biblioteki klienta Microsoft Entra ID Spring Boot Starter dla języka Java do logowania użytkownika i uzyskiwania tokenu identyfikatora z witryny Microsoft Entra ID. Token identyfikatora potwierdza, że użytkownik jest uwierzytelniany za pomocą identyfikatora Microsoft Entra ID i umożliwia użytkownikowi dostęp do chronionych tras.
Wymagania wstępne
- Zestaw JDK w wersji 17. Ten przykład został opracowany w systemie z językiem Java 17, ale może być zgodny z innymi wersjami.
- Maven 3
- Pakiet rozszerzenia Java dla programu Visual Studio Code jest zalecany do uruchamiania tego przykładu w programie Visual Studio Code.
- Dzierżawa identyfikatora entra firmy Microsoft. Aby uzyskać więcej informacji, zobacz How to get a Microsoft Entra ID tenant (Jak uzyskać dzierżawę identyfikatora entra firmy Microsoft).
- Konto użytkownika w dzierżawie microsoft Entra ID. Ten przykład nie działa z osobistym kontem Microsoft. W związku z tym jeśli zalogowałeś się do witryny Azure Portal przy użyciu konta osobistego i nie masz konta użytkownika w katalogu, musisz go utworzyć teraz.
- Visual Studio Code
- Azure Tools for Visual Studio Code
Zalecenia
- Znajomość struktury Spring
- Znajomość terminalu systemu Linux/OSX lub programu Windows PowerShell
- jwt.ms na potrzeby inspekcji tokenów.
- Program Fiddler do monitorowania aktywności sieci i rozwiązywania problemów.
- Postępuj zgodnie z blogiem Microsoft Entra ID, aby być na bieżąco z najnowszymi wydarzeniami.
Konfigurowanie przykładu
W poniższych sekcjach pokazano, jak skonfigurować przykładową aplikację.
Klonowanie lub pobieranie przykładowego repozytorium
Aby sklonować przykład, otwórz okno powłoki Bash i użyj następującego polecenia:
git clone https://github.com/Azure-Samples/ms-identity-java-spring-tutorial.git
cd ms-identity-java-spring-tutorial
cd 1-Authentication/sign-in
Alternatywnie przejdź do repozytorium ms-identity-java-spring-tutorial , a następnie pobierz go jako plik .zip i wyodrębnij go na dysk twardy.
Ważne
Aby uniknąć ograniczeń długości ścieżki w systemie Windows, zalecamy sklonowanie do katalogu w pobliżu katalogu głównego dysku.
Rejestrowanie przykładowych aplikacji w dzierżawie identyfikatora entra firmy Microsoft
W tym przykładzie istnieje jeden projekt. Aby zarejestrować aplikację w witrynie Azure Portal, możesz wykonać kroki konfiguracji ręcznej lub użyć skryptu programu PowerShell. Skrypt wykonuje następujące zadania:
- Tworzy aplikacje Microsoft Entra ID i powiązane obiekty, takie jak hasła, uprawnienia i zależności.
- Modyfikuje pliki konfiguracji projektu.
- Domyślnie konfiguruje aplikację, która działa tylko z kontami w katalogu organizacyjnym.
Aby uruchomić skrypt programu PowerShell, wykonaj następujące czynności:
W systemie Windows otwórz program PowerShell i przejdź do katalogu głównego sklonowanego katalogu.
Użyj następującego polecenia, aby ustawić zasady wykonywania dla programu PowerShell:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process -Force
Użyj następujących poleceń, aby uruchomić skrypt konfiguracji:
cd .\AppCreationScripts\ .\Configure.ps1
Uwaga
Inne sposoby uruchamiania skryptów są opisane w temacie Skrypty tworzenia aplikacji. Skrypty zawierają również przewodnik po automatycznej rejestracji, konfiguracji i usuwaniu aplikacji, które mogą pomóc w scenariuszach ciągłej integracji/ciągłego wdrażania.
Konfigurowanie aplikacji (java-spring-webapp-auth) do korzystania z rejestracji aplikacji
Aby skonfigurować aplikację, wykonaj następujące kroki:
Uwaga
W poniższych krokach ClientID
jest to samo co Application ID
lub AppId
.
Otwórz projekt w środowisku IDE.
Otwórz plik src\main\resources\application.yml.
Znajdź symbol zastępczy
Enter_Your_Tenant_ID_Here
i zastąp istniejącą wartość identyfikatorem dzierżawy firmy Microsoft Entra.Znajdź symbol zastępczy
Enter_Your_Client_ID_Here
i zastąp istniejącą wartość identyfikatorem aplikacji lubclientId
java-spring-webapp-auth
aplikacją skopiowaną z witryny Azure Portal.Znajdź symbol zastępczy
Enter_Your_Client_Secret_Here
i zastąp istniejącą wartość wartością zapisaną podczas tworzeniajava-spring-webapp-auth
kopii z witryny Azure Portal.
Uruchamianie aplikacji przykładowej
W poniższych sekcjach pokazano, jak wdrożyć przykład w usłudze Azure Spring Apps.
Wymagania wstępne
Jeśli wdrażasz wystąpienie planu Usługi Azure Spring Apps Enterprise po raz pierwszy w subskrypcji docelowej, zobacz sekcję Wymagania planu przedsiębiorstwa w witrynie Azure Marketplace.
Wtyczka Maven dla usługi Azure Spring Apps. Jeśli narzędzie Maven nie jest preferowanym narzędziem programistycznym, zobacz następujące podobne samouczki korzystające z innych narzędzi:
Przygotowywanie projektu Spring
Aby przygotować projekt, wykonaj następujące czynności:
Użyj następującego polecenia narzędzia Maven , aby skompilować projekt:
mvn clean package
Uruchom przykładowy projekt lokalnie, używając następującego polecenia:
mvn spring-boot:run
Konfigurowanie wtyczki Maven
Uruchom następujące polecenie w katalogu głównym projektu, aby skonfigurować aplikację przy użyciu wtyczki Maven dla usługi Azure Spring Apps:
mvn com.microsoft.azure:azure-spring-apps-maven-plugin:1.19.0:config
Poniższa lista zawiera opis interakcji poleceń:
- Logowanie OAuth2: musisz autoryzować logowanie do platformy Azure na podstawie protokołu OAuth2.
- Wybierz subskrypcję: wybierz numer listy subskrypcji, w którym chcesz utworzyć wystąpienie usługi Azure Spring Apps, które jest domyślnie pierwszą subskrypcją na liście. Jeśli chcesz użyć numeru domyślnego, naciśnij klawisz Enter.
- Wprowadź nazwę usługi Azure Spring Apps: wprowadź nazwę wystąpienia aplikacji spring, które chcesz utworzyć. Jeśli chcesz użyć nazwy domyślnej, naciśnij klawisz Enter.
- Wprowadź nazwę grupy zasobów: wprowadź nazwę grupy zasobów, w której chcesz utworzyć wystąpienie aplikacji spring. Jeśli chcesz użyć nazwy domyślnej, naciśnij klawisz Enter.
- Jednostki SKU: wybierz jednostkę SKU, której chcesz użyć dla wystąpienia aplikacji spring. Jeśli chcesz użyć numeru domyślnego, naciśnij klawisz Enter.
- Wprowadź nazwę aplikacji (pokaz): podaj nazwę aplikacji. Jeśli chcesz użyć domyślnego identyfikatora artefaktu projektu, naciśnij klawisz Enter.
- Środowiska uruchomieniowe: wybierz środowisko uruchomieniowe, którego chcesz użyć dla wystąpienia aplikacji spring. W takim przypadku należy użyć numeru domyślnego, więc naciśnij klawisz Enter.
- Uwidaczniaj publiczny dostęp dla tej aplikacji (boot-for-azure): Naciśnij klawisz y.
- Potwierdź, aby zapisać wszystkie powyższe konfiguracje: naciśnij klawisz y. Jeśli naciśniesz n, konfiguracja nie zostanie zapisana w pliku .pom .
W poniższym przykładzie przedstawiono dane wyjściowe procesu wdrażania:
Summary of properties:
Subscription id : 12345678-1234-1234-1234-123456789101
Resource group name : rg-ms-identity-spring-boot-webapp
Azure Spring Apps name : cluster-ms-identity-spring-boot-webapp
Runtime Java version : Java 11
Region : eastus
Sku : Standard
App name : ms-identity-spring-boot-webapp
Public access : true
Instance count/max replicas : 1
CPU count : 1
Memory size(GB) : 2
Confirm to save all the above configurations (Y/n):
[INFO] Configurations are saved to: /home/user/ms-identity-java-spring-tutorial/1-Authentication/sign-in/pom. xml
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:57 min
[INFO] Finished at: 2024-02-14T13:50:44Z
[INFO] ------------------------------------------------------------------------
Po potwierdzeniu wybranych opcji wtyczka dodaje wymagany element i ustawienia wtyczki do pliku pom.xml projektu w celu skonfigurowania aplikacji do uruchamiania w usłudze Azure Spring Apps.
Odpowiednia część pliku pom.xml powinna wyglądać podobnie do poniższego przykładu:
<plugin>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-spring-apps-maven-plugin</artifactId>
<version>1.19.0</version>
<configuration>
<subscriptionId>12345678-1234-1234-1234-123456789101</subscriptionId>
<resourceGroup>rg-ms-identity-spring-boot-webapp</resourceGroup>
<clusterName>cluster-ms-identity-spring-boot-webapp</clusterName>
<region>eastus</region>
<sku>Standard</sku>
<appName>ms-identity-spring-boot-webapp</appName>
<isPublic>true</isPublic>
<deployment>
<cpu>1</cpu>
<memoryInGB>2</memoryInGB>
<instanceCount>1</instanceCount>
<runtimeVersion>Java 11</runtimeVersion>
<resources>
<resource>
<directory>${project.basedir}/target</directory>
<includes>
<include>*.jar</include>
</includes>
</resource>
</resources>
</deployment>
</configuration>
</plugin>
Konfiguracje usługi Azure Spring Apps można modyfikować bezpośrednio w pliku pom.xml . Niektóre typowe konfiguracje są wymienione w poniższej tabeli:
Właściwości | Wymagania | opis |
---|---|---|
subscriptionId |
fałsz | Identyfikator subskrypcji. |
resourceGroup |
prawda | Grupa zasobów platformy Azure dla wystąpienia usługi Azure Spring Apps. |
clusterName |
prawda | Nazwa klastra usługi Azure Spring Apps. Jeśli używasz subskrypcji i grupy zasobów, która ma już wdrożone wystąpienie usługi Azure Spring Apps, możesz również użyć tego istniejącego klastra do wdrożenia. |
appName |
prawda | Nazwa aplikacji w usłudze Azure Spring Apps. |
region |
fałsz | Region, w którym ma być hostowane wystąpienie usługi Azure Spring Apps. Domyślna wartość to eastus . Aby zapoznać się z prawidłowymi regionami, zobacz Obsługiwane regiony. |
sku |
fałsz | Warstwa cenowa wystąpienia usługi Azure Spring Apps. Wartość domyślna to Basic , która jest odpowiednia tylko dla środowisk deweloperskich i testowych. |
runtime |
fałsz | Konfiguracja środowiska uruchomieniowego. Aby uzyskać więcej informacji, zobacz Szczegóły konfiguracji. |
deployment |
fałsz | Konfiguracja wdrożenia. Aby uzyskać więcej informacji, zobacz Szczegóły konfiguracji. |
Pełną listę konfiguracji można znaleźć w dokumentacji referencyjnej wtyczki. Wszystkie wtyczki usługi Azure Maven mają wspólny zestaw konfiguracji. Aby uzyskać te konfiguracje, zobacz Typowe konfiguracje. Aby uzyskać informacje o konfiguracjach specyficznych dla usługi Azure Spring Apps, zobacz Azure Spring Apps: Configuration Details (Azure Spring Apps: Szczegóły konfiguracji).
Pamiętaj, aby zapisać wartości i appName
do późniejszego clusterName
użycia.
Przygotowywanie aplikacji do wdrożenia
Podczas wdrażania aplikacji w usłudze Azure Spring Apps adres URL przekierowania zmieni się na adres URL przekierowania wdrożonego wystąpienia aplikacji w usłudze Azure Spring Apps. Wykonaj następujące kroki, aby zmienić te ustawienia w pliku application.yml :
Przejdź do pliku src\main\resources\application.yml aplikacji i zmień wartość
post-logout-redirect-uri
na nazwę domeny wdrożonej aplikacji, jak pokazano w poniższym przykładzie. Jeśli na przykład wybranocluster-ms-identity-spring-boot-webapp
wystąpienie usługi Azure Spring Apps w poprzednim kroku ims-identity-spring-boot-webapp
nazwę aplikacji, musisz teraz użyćhttps://cluster-ms-identity-spring-boot-webapp-ms-identity-spring-boot-webapp.azuremicroservices.io
wartościpost-logout-redirect-uri
.post-logout-redirect-uri: https://<cluster-name>-<app-name>.azuremicroservices.io
Po zapisaniu tego pliku użyj następującego polecenia, aby ponownie skompilować aplikację:
mvn clean package
Ważne
Plik application.yml aplikacji przechowuje obecnie wartość klucza tajnego klienta w parametrze client-secret
. Nie jest dobrym rozwiązaniem, aby zachować tę wartość w tym pliku. Możesz również podejmowania ryzyka, jeśli zatwierdzisz je w repozytorium Git.
W ramach dodatkowego kroku zabezpieczeń możesz przechowywać tę wartość w usłudze Azure Key Vault i załadować wpis tajny z usługi Key Vault, aby udostępnić ją w aplikacji.
Aktualizowanie rejestracji aplikacji Microsoft Entra ID
Ponieważ identyfikator URI przekierowania zmienia się w wdrożonej aplikacji w usłudze Azure Spring Apps, musisz również zmienić identyfikator URI przekierowania w rejestracji aplikacji Microsoft Entra ID. Aby wprowadzić tę zmianę, wykonaj następujące czynności:
Przejdź do strony Platforma tożsamości Microsoft dla deweloperów Rejestracje aplikacji.
Użyj pola wyszukiwania, aby wyszukać rejestrację aplikacji — na przykład
java-servlet-webapp-authentication
.Otwórz rejestrację aplikacji, wybierając jej nazwę.
Wybierz Uwierzytelnianie z menu poleceń.
W sekcji Identyfikatory URI przekierowania sieci Web - wybierz pozycję Dodaj identyfikator URI.
Wypełnij identyfikator URI aplikacji, dołączając
/login/oauth2/code/
na przykładhttps://<cluster-name>-<app-name>.azuremicroservices.io/login/oauth2/code/
.Wybierz pozycję Zapisz.
Wdrażanie aplikacji
Aby wdrożyć aplikację, użyj następującego polecenia:
mvn azure-spring-apps:deploy
Na poniższej liście opisano interakcję z poleceniem:
- Logowanie OAuth2: musisz autoryzować logowanie do platformy Azure na podstawie protokołu OAuth2.
Po wykonaniu polecenia można zobaczyć następujące komunikaty dziennika, że wdrożenie zakończyło się pomyślnie:
[INFO] Deployment(default) is successfully created
[INFO] Starting Spring App after deploying artifacts...
[INFO] Deployment Status: Running
[INFO] InstanceName:demo-default-x-xxxxxxxxxx-xxxxx Status:Running Reason:null DiscoverStatus:UNREGISTERED
[INFO] InstanceName:demo-default-x-xxxxxxxxx-xxxxx Status:Terminating Reason:null DiscoverStatus:UNREGISTERED
[INFO] Getting public url of app(demo)...
[INFO] Application url: https://<your-Azure-Spring-Apps-instance-name>-demo.azuremicroservices.io
Weryfikowanie aplikacji
Po zakończeniu wdrażania uzyskaj dostęp do aplikacji przy użyciu adresu URL aplikacji wyjściowej. Wykonaj następujące kroki, aby sprawdzić dzienniki aplikacji w celu zbadania dowolnego problemu z wdrażaniem:
Uzyskaj dostęp do adresu URL aplikacji wyjściowej na stronie Dane wyjściowe sekcji Wdrażanie.
W okienku nawigacji na stronie Przegląd wystąpienia usługi Azure Spring Apps wybierz pozycję Dzienniki, aby sprawdzić dzienniki aplikacji.
Eksplorowanie przykładu
Aby zapoznać się z przykładem, wykonaj następujące czynności:
- Zwróć uwagę na stan logowania lub wylogowania wyświetlany na środku ekranu.
- Wybierz przycisk kontekstowy w rogu. Ten przycisk odczytuje pozycję Zaloguj po pierwszym uruchomieniu aplikacji. Alternatywnie wybierz szczegóły tokenu. Ponieważ ta strona jest chroniona i wymaga uwierzytelniania, nastąpi automatyczne przekierowanie do strony logowania.
- Na następnej stronie postępuj zgodnie z instrukcjami i zaloguj się przy użyciu konta w dzierżawie Microsoft Entra ID.
- Na ekranie zgody zwróć uwagę na żądane zakresy.
- Po pomyślnym zakończeniu przepływu logowania powinno nastąpić przekierowanie do strony głównej , która pokazuje stan logowania — lub stronę szczegółów tokenu, w zależności od tego, który przycisk wyzwolił przepływ logowania.
- Zwróć uwagę, że przycisk kontekstowy zawiera teraz pozycję Wyloguj się i wyświetla nazwę użytkownika.
- Jeśli jesteś na stronie głównej, wybierz pozycję Szczegóły tokenu identyfikatora, aby wyświetlić niektóre zdekodowane oświadczenia tokenu identyfikatora.
- Użyj przycisku w rogu, aby się wylogować. Strona stanu odzwierciedla nowy stan.
Informacje o kodzie
W tym przykładzie pokazano, jak używać biblioteki klienta Microsoft Entra ID Spring Boot Starter dla języka Java do logowania użytkowników do dzierżawy microsoft Entra ID. Przykład korzysta również z szablonów startowych Spring Oauth2 Client i Spring Web Boot. W przykładzie użyto oświadczeń z tokenu identyfikatora uzyskanego z identyfikatora firmy Microsoft Entra, aby wyświetlić szczegóły zalogowanego użytkownika.
Zawartość
W poniższej tabeli przedstawiono zawartość przykładowego folderu projektu:
Plik/folder | opis |
---|---|
AppCreationScripts/ | Skrypty do automatycznego konfigurowania rejestracji aplikacji Microsoft Entra ID. |
pom.xml | Zależności aplikacji. |
src/main/resources/templates/ | Szablony Thymeleaf dla interfejsu użytkownika. |
src/main/resources/application.yml | Konfiguracja biblioteki startowej rozruchu aplikacji i programu Microsoft Entra ID. |
src/main/java/com/microsoft/azuresamples/msal4j/msidentityspringbootwebapp/ | Ten katalog zawiera główne klasy wejścia aplikacji, kontrolera i konfiguracji. |
.../MsIdentitySpringBootWebappApplication.java | Klasa główna. |
.../SampleController.java | Kontroler z mapowaniami punktów końcowych. |
.../SecurityConfig.java | Konfiguracja zabezpieczeń — na przykład trasy wymagają uwierzytelniania. |
.../Utilities.java | Klasa narzędzia — na przykład filtruj oświadczenia tokenu identyfikatora. |
CHANGELOG.md | Lista zmian w przykładzie. |
CONTRIBUTING.md | Wskazówki dotyczące współtworzenia przykładu. |
LICENCJI | Licencja dla przykładu. |
Oświadczenia tokenu identyfikatora
Aby wyodrębnić szczegóły tokenu, aplikacja korzysta z obiektów i OidcUser
obiektów spring security AuthenticationPrincipal
w mapowaniu żądania, jak pokazano w poniższym przykładzie. Zobacz Przykładowy kontroler, aby uzyskać szczegółowe informacje na temat sposobu korzystania z oświadczeń tokenu identyfikatora.
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
//...
@GetMapping(path = "/some_path")
public String tokenDetails(@AuthenticationPrincipal OidcUser principal) {
Map<String, Object> claims = principal.getIdToken().getClaims();
}
Linki logowania i wylogowywanie
W przypadku logowania aplikacja wysyła żądanie do punktu końcowego logowania Microsoft Entra ID automatycznie skonfigurowanego przez bibliotekę klienta Microsoft Entra ID Spring Boot Starter dla języka Java, jak pokazano w poniższym przykładzie:
<a class="btn btn-success" href="/oauth2/authorization/azure">Sign In</a>
W przypadku wylogowania aplikacja wysyła żądanie POST do punktu końcowego logout
, jak pokazano w poniższym przykładzie:
<form action="#" th:action="@{/logout}" method="post">
<input class="btn btn-warning" type="submit" value="Sign Out" />
</form>
Elementy interfejsu użytkownika zależne od uwierzytelniania
Aplikacja ma prostą logikę na stronach szablonu interfejsu użytkownika do określania zawartości do wyświetlenia na podstawie tego, czy użytkownik jest uwierzytelniony, jak pokazano w poniższym przykładzie przy użyciu tagów Spring Security Thymeleaf:
<div sec:authorize="isAuthenticated()">
this content only shows to authenticated users
</div>
<div sec:authorize="isAnonymous()">
this content only shows to not-authenticated users
</div>
Ochrona tras za pomocą polecenia AADWebSecurityConfigurerAdapter
Domyślnie aplikacja chroni stronę Szczegóły tokenu identyfikatora, aby tylko zalogowani użytkownicy mogli do niej uzyskać dostęp. Aplikacja konfiguruje te trasy przy użyciu app.protect.authenticated
właściwości z pliku application.yml . Aby skonfigurować określone wymagania aplikacji, zastosuj metodę AadWebApplicationHttpSecurityConfigurer#aadWebApplication
do HttpSecurity
wystąpienia. Aby zapoznać się z przykładem, zobacz klasę SecurityConfig tej aplikacji, pokazaną w następującym kodzie:
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
@Value("${app.protect.authenticated}")
private String[] allowedOrigins;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// @formatter:off
http.apply(AadWebApplicationHttpSecurityConfigurer.aadWebApplication())
.and()
.authorizeHttpRequests(auth -> auth
.requestMatchers(allowedOrigins).authenticated()
.anyRequest().permitAll()
);
// @formatter:on
return http.build();
}
@Bean
@RequestScope
public ServletUriComponentsBuilder urlBuilder() {
return ServletUriComponentsBuilder.fromCurrentRequest();
}
}
Więcej informacji
- Platforma tożsamości Microsoft (Microsoft Entra ID dla deweloperów)
- Omówienie biblioteki Microsoft Authentication Library (MSAL)
- Szybki start: Rejestrowanie aplikacji za pomocą platformy tożsamości firmy Microsoft
- Szybki start: konfigurowanie aplikacji klienckiej w celu uzyskiwania dostępu do internetowych interfejsów API
- Omówienie środowisk wyrażania zgody aplikacji Entra ID firmy Microsoft
- Omówienie zgody użytkownika i administratora
- Obiekty aplikacji i jednostki usługi w usłudze Microsoft Entra ID
- Chmury krajowe
- Przykłady kodu biblioteki MSAL
- Microsoft Entra ID Spring Boot Starter biblioteka kliencka dla języka Java
- Biblioteka uwierzytelniania firmy Microsoft dla języka Java (MSAL4J)
- MSAL4J Wiki
- Tokeny identyfikatorów
- Tokeny dostępu w Platforma tożsamości Microsoft
Aby uzyskać więcej informacji na temat sposobu działania protokołów OAuth 2.0 w tym scenariuszu i innych scenariuszach, zobacz Scenariusze uwierzytelniania dla identyfikatora Entra firmy Microsoft.
Opinia
https://aka.ms/ContentUserFeedback.
Dostępne już wkrótce: W 2024 r. będziemy stopniowo wycofywać zgłoszenia z serwisu GitHub jako mechanizm przesyłania opinii na temat zawartości i zastępować go nowym systemem opinii. Aby uzyskać więcej informacji, sprawdź:Prześlij i wyświetl opinię dla