JavaRush /Blog Java /Random-PL /Wprowadźmy regularne logowanie przez e-mail i OAuth2 do S...

Wprowadźmy regularne logowanie przez e-mail i OAuth2 do Spring Security na przykładzie usługi notatek

Opublikowano w grupie Random-PL
Pisząc moją aplikację, napotkałem brak jasnych artykułów na temat tego, jak nakłonić użytkownika do rejestracji zarówno za pośrednictwem poczty elektronicznej, jak i sieci społecznościowych. Były dobre tutoriale na temat konfigurowania klasycznego formularza logowania. Były dobre tutoriale na temat OAuth2 . Było kryminalnie mało informacji na temat łączenia obu metod. W trakcie poszukiwań udało nam się znaleźć wykonalne rozwiązanie. Nie rości sobie pretensji do prawdy ostatecznej, ale spełnia swoją funkcję. W tym artykule pokażę jak od podstaw zaimplementować usługę przechowywania notatek przy podobnej konfiguracji Spring Security. Wprowadźmy regularne logowanie poprzez e-mail i OAuth2 do Spring Security na przykładzie usługi notatek - 1Uwaga: dobrze, jeśli czytelnik przeszedł chociaż kilka tutoriali na temat Springa, gdyż uwaga skupiona zostanie wyłącznie na Spring Security, bez szczegółowych opisów repozytoriów, kontrolerów itp. Inaczej wyszedłby już dość obszerny artykuł być gigantyczny. Treść
  1. Tworzenie projektu
  2. Tworzenie encji i logiki aplikacji
    1. Podmioty
    2. Repozytoria
    3. Kontrolery
    4. Strony
  3. Konfigurowanie zabezpieczeń Spring dla logowania klasycznego
    1. Konfiguracja podstawowa SecurityConfig
    2. Niestandardowy login użytkownika
    3. Ulepszmy kontroler
    4. Początek
  4. Konfigurowanie OAuth2 na przykładzie Google w Spring Security
    1. Konfiguracja filtra i właściwości aplikacji
    2. Najważniejsze informacje dotyczące rejestracji aplikacji w Google Cloud Platform
    3. Niestandardowe usługiUserInfoTokenServices
  5. Ostateczne uruchomienie projektu

Tworzenie projektu

Wchodzimy na start.spring.io i tworzymy podstawę projektu:
  • Web - uruchomienie aplikacji na wbudowanym Tomcacie, mapowanie adresów URL i tym podobne;
  • JPA - połączenie z bazą danych;
  • Mustache to silnik szablonów używany do generowania stron internetowych;
  • Bezpieczeństwo - ochrona aplikacji. Właśnie po to powstał ten artykuł.
Pobierz powstałe archiwum i rozpakuj je w potrzebnym folderze. Uruchamiamy go w IDE. Bazę danych możesz wybrać według własnego uznania. Używam MySQL jako bazy danych dla projektu, dlatego dodaję następującą zależność do pliku pom.xml w bloku <zależności>:
<dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
     <version>5.1.34</version>
</dependency>
Konfiguracja application.properties wygląda obecnie następująco:
spring.datasource.url=jdbc:mysql://localhost:3306/springsectut?createDatabaseIfNotExist=true&useSSL=false&autoReconnect=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=yes&characterEncoding=UTF-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=yourUsername
spring.datasource.password=yourPassword

spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update

spring.jpa.properties.connection.characterEncoding=utf-8
spring.jpa.properties.connection.CharSet=utf-8
spring.jpa.properties.connection.useUnicode=true

spring.mustache.expose-request-attributes=true

Tworzenie encji i logiki aplikacji

Podmioty

Stwórzmy pakiet, entitiesw którym umieścimy encje bazy danych. Użytkownik zostanie opisany przez klasę Userimplementującą interfejs UserDetails, który będzie potrzebny do konfiguracji Spring Security. Użytkownik będzie miał identyfikator, nazwę użytkownika (jest to adres e-mail), hasło, nazwę, rolę, flagę aktywności, nazwę konta Google i adres e-mail ( googleNamei googleUsername).
@Entity
@Table(name = "user")
public class User implements UserDetails
{
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  private String username;
  private String password;
  private String name;
  private boolean active;
  private String googleName;
  private String googleUsername;

  @ElementCollection(targetClass = Role.class, fetch = FetchType.EAGER)
  @CollectionTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"))
  @Enumerated(EnumType.STRING)
  private Set<Role> roles;

    //Геттеры, сеттеры, toString(), equals(), hashcode(), имплементация UserDetails
}
Role użytkowników służą do regulowania dostępu w Spring Security. Nasza aplikacja będzie używać tylko jednej roli:
public enum Role implements GrantedAuthority
{
  USER;

  @Override
  public String getAuthority()
  {
     return name();
  }
}
Stwórzmy klasę notatki zawierającą identyfikator, tytuł notatki, treść notatki i identyfikator użytkownika, do którego ona należy:
@Entity
@Table(name = "note")
public class Note
{
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  private String title;
  private String note;
  private Long userId;

    //Геттеры, сеттеры, toString(), equals(), hashcode()
}

Repozytoria

Aby zapisywać encje do bazy danych potrzebujemy repozytoriów, które wykonają za nas całą brudną robotę. Stwórzmy pakiet repos, w nim utworzymy interfejsy UserRepoodziedziczone NoteRepoz interfejsu JpaRepository<Entity, Id>.
@Service
@Repository
public interface UserRepo extends JpaRepository<User, Long>
{}

@Service
@Repository
public interface NoteRepo extends JpaRepository<Note, Long>
{
  List<Note> findByUserId(Long userId);
}

Kontrolery

Nasz serwis notatek będzie miał następujące strony:
  • Dom;
  • Rejestracja;
  • Wejście;
  • Lista notatek użytkownika.
Dostęp do listy notatek powinien mieć wyłącznie uprawniony użytkownik. Pozostałe strony są publiczne. Stwórzmy pakiet controllerszawierający klasę IndexControllerzawierającą zwykłe mapowanie strony głównej. Klasa RegistrationControllerodpowiedzialna jest za rejestrację użytkownika. Post-mapping pobiera dane z formularza, zapisuje użytkownika do bazy danych i przekierowuje na stronę logowania. PasswordEncoderzostanie opisane później. Służy do szyfrowania haseł.
@Controller
public class RegistrationController
{
  @Autowired
  private UserRepo userRepo;

  @Autowired
  private PasswordEncoder passwordEncoder;

  @GetMapping("/registration")
  public String registration()
  {
     return "registration";
  }

  @PostMapping("/registration")
  public String addUser(String name, String username, String password)
  {
     User user = new User();
     user.setName(name);
     user.setUsername(username);
     user.setPassword(passwordEncoder.encode(password));
     user.setActive(true);
     user.setRoles(Collections.singleton(Role.USER));

     userRepo.save(user);

     return "redirect:/login";
  }
Kontroler odpowiedzialny za stronę z listą notatek zawiera obecnie uproszczoną funkcjonalność, która stanie się bardziej złożona po wdrożeniu Spring Security.
@Controller
public class NoteController
{
  @Autowired
  private NoteRepo noteRepo;

  @GetMapping("/notes")
  public String notes(Model model)
  {
     List<Note> notes = noteRepo.findAll();
     model.addAttribute("notes", notes);

     return "notes";
  }

  @PostMapping("/addnote")
  public String addNote(String title, String note)
  {
     Note newNote = new Note();
     newNote.setTitle(title);
     newNote.setNote(note);

     noteRepo.save(newNote);

     return "redirect:/notes";
  }
}
Nie będziemy pisać kontrolera dla strony logowania, ponieważ jest on używany przez Spring Security. Zamiast tego będziemy potrzebować specjalnej konfiguracji. Jak zwykle utwórzmy kolejny pakiet, nazwijmy go configi umieśćmy w nim klasę MvcConfig. Kiedy napiszemy konfigurację Spring Security, będzie ona wiedzieć, do której strony się odwołujemy, gdy użyjemy „/login”.
@Configuration
public class MvcConfig implements WebMvcConfigurer
{
  public void addViewControllers(ViewControllerRegistry registry)
  {
     registry.addViewController("/login").setViewName("login");
     registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
  }
}

Strony

Do tworzenia stron używam silnika szablonów Mustache . Możesz wdrożyć inny, to nie ma znaczenia. Utworzono plik meta.mustache dla metainformacji używanych na wszystkich stronach. Zawiera także Bootstrap, dzięki któremu strony naszego projektu wyglądają ładniej. Strony tworzone są w katalogu „src/main/resources/templates”. Pliki mają rozszerzenie wąsy. Umieszczenie kodu HTML bezpośrednio w artykule spowoduje, że będzie on zbyt duży, dlatego poniżej znajduje się link do folderu szablonów w repozytorium GitHub projektu .

Konfigurowanie zabezpieczeń Spring dla logowania klasycznego

Spring Security pomaga nam chronić aplikację i jej zasoby przed nieautoryzowanym dostępem. Stworzymy zwięzłą konfigurację roboczą w klasie SecurityConfigodziedziczonej z WebSecurityConfigurerAdapter, którą umieścimy w pakiecie config. Oznaczmy to adnotacją @EnableWebSecurity, która umożliwi obsługę Spring Security, oraz adnotacją @Configuration, która wskazuje, że ta klasa zawiera pewną konfigurację. Uwaga: automatycznie skonfigurowany plik pom.xml zawierał wersję komponentu nadrzędnego Spring Boot 2.1.4.RELEASE, co uniemożliwiało wdrożenie zabezpieczeń w ustalony sposób. Aby uniknąć konfliktów w projekcie zaleca się zmianę wersji na 2.0.1.RELEASE.

Konfiguracja podstawowa SecurityConfig

Nasza konfiguracja będzie mogła:
  1. Szyfruj hasła za pomocą BCryptPasswordEncoder:

    @Autowired
    private PasswordEncoder passwordEncoder;
    
    @Bean
    PasswordEncoder passwordEncoder()
    {
      PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
      return passwordEncoder;
    }
  2. Zaloguj się przy użyciu specjalnie napisanego dostawcy uwierzytelniania:

    @Autowired
    private AuthProvider authProvider;
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth)
    {
      auth.authenticationProvider(authProvider);
    }
  3. Zezwól anonimowym użytkownikom na dostęp do strony głównej, stron rejestracji i logowania. Wszystkie pozostałe żądania muszą być realizowane przez zalogowanych użytkowników. Przypiszmy wcześniej opisaną „/login” jako stronę logowania. Jeżeli logowanie przebiegło pomyślnie, użytkownik zostanie przeniesiony na stronę z listą notatek, w przypadku błędu pozostanie na stronie logowania. Po pomyślnym wyjściu użytkownik zostanie przeniesiony na stronę główną.

    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
      http
            .authorizeRequests()
            .antMatchers("/resources/**", "/", "/login**", "/registration").permitAll()
            .anyRequest().authenticated()
            .and().formLogin().loginPage("/login")
            .defaultSuccessUrl("/notes").failureUrl("/login?error").permitAll()
            .and().logout().logoutSuccessUrl("/").permitAll();
    }

Niestandardowy login użytkownika

Samodzielnie napisany AuthProviderpozwoli użytkownikowi zalogować się nie tylko za pomocą adresu e-mail, ale także nazwy użytkownika.
@Component
public class AuthProvider implements AuthenticationProvider
{
  @Autowired
  private UserService userService;

  @Autowired
  private PasswordEncoder passwordEncoder;

  public Authentication authenticate(Authentication authentication) throws AuthenticationException
  {
     String username = authentication.getName();
     String password = (String) authentication.getCredentials();

     User user = (User) userService.loadUserByUsername(username);

     if(user != null && (user.getUsername().equals(username) || user.getName().equals(username)))
     {
        if(!passwordEncoder.matches(password, user.getPassword()))
        {
           throw new BadCredentialsException("Wrong password");
        }

        Collection<? extends GrantedAuthority> authorities = user.getAuthorities();

        return new UsernamePasswordAuthenticationToken(user, password, authorities);
     }
     else
        throw new BadCredentialsException("Username not found");
  }

  public boolean supports(Class<?> arg)
  {
     return true;
  }
}
Jak zapewne zauważyłeś, klasa UserServiceznajdująca się w pakiecie odpowiedzialna jest za załadowanie użytkownika services. W naszym przypadku wyszukuje użytkownika nie tylko według pola username, jak ma to miejsce w przypadku wbudowanej implementacji, ale także według nazwy użytkownika, nazwy konta Google i adresu e-mail konta Google. Dwie ostatnie metody przydadzą nam się przy implementacji logowania poprzez OAuth2. Tutaj klasa jest podana w wersji skróconej.
@Service
public class UserService implements UserDetailsService
{
  @Autowired
  private UserRepo userRepo;

  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
  {
     User userFindByUsername = userRepo.findByUsername(username);
     //Остальные поиски

     if(userFindByUsername != null)
     {
        return userFindByUsername;
     }
     //Остальные проверки
     return null;
  }
}
Uwaga: nie zapomnij wpisać niezbędnych metod w UserRepo!

Ulepszmy kontroler

Skonfigurowaliśmy Spring Security. Nadszedł czas, aby skorzystać z tego w kontrolerze notatek. Teraz każde mapowanie zaakceptuje dodatkowy parametr główny, za pomocą którego będzie próbował znaleźć użytkownika. Dlaczego nie mogę bezpośrednio wstrzyknąć klasy User? Wtedy wystąpi konflikt z powodu niedopasowania typów użytkowników, gdy napiszemy login za pośrednictwem sieci społecznościowych. Z góry zapewniamy niezbędną elastyczność. Nasz kod kontrolera notatek wygląda teraz tak:
@GetMapping("/notes")
public String notes(Principal principal, Model model)
{
  User user = (User) userService.loadUserByUsername(principal.getName());
  List<Note> notes = noteRepo.findByUserId(user.getId());
  model.addAttribute("notes", notes);
  model.addAttribute("user", user);

  return "notes";
}

@PostMapping("/addnote")
public String addNote(Principal principal, String title, String note)
{
  User user = (User) userService.loadUserByUsername(principal.getName());

  Note newNote = new Note();
  newNote.setTitle(title);
  newNote.setNote(note);
  newNote.setUserId(user.getId());

  noteRepo.save(newNote);

  return "redirect:/notes";
}
Uwaga: projekt ma domyślnie włączoną ochronę CSRF , więc albo wyłącz ją dla siebie (http.csrf().disable()), albo nie zapomnij jako autor artykułu dodać ukrytego pola z tokenem csrf na wszystkie prośby o publikację.

Początek

Próbujemy uruchomić projekt.
Wprowadźmy regularne logowanie poprzez e-mail i OAuth2 do Spring Security na przykładzie usługi notatek - 1
Wprowadźmy regularne logowanie przez e-mail i OAuth2 do Spring Security na przykładzie usługi notatek - 2
Widzimy, że w bazie pojawił się nowy użytkownik. Hasło jest zaszyfrowane.
Wprowadźmy regularne logowanie przez e-mail i OAuth2 do Spring Security na przykładzie usługi notatek - 3
Wprowadźmy regularne logowanie przez e-mail i OAuth2 do Spring Security na przykładzie usługi notatek - 4
Wprowadźmy regularne logowanie poprzez e-mail i OAuth2 do Spring Security na przykładzie usługi notatek - 5
Wprowadźmy regularne logowanie przez e-mail i OAuth2 do Spring Security na przykładzie usługi notatek - 6
Notatki zapisywane są w bazie danych.
Wprowadźmy regularne logowanie przez e-mail i OAuth2 do Spring Security na przykładzie usługi notatek - 7
Widzimy, że projekt został pomyślnie uruchomiony i działa. Do pełni szczęścia wystarczy nam jedynie możliwość logowania się poprzez portale społecznościowe. Cóż, zaczynajmy!

Konfigurowanie OAuth2 na przykładzie Google w Spring Security

Wdrażając OAuth2, polegałem na tym oficjalnym tutorialu ze Springa . Aby obsługiwać OAuth2, dodaj następującą bibliotekę do pom.xml:
<dependency>
  <groupId>org.springframework.security.oauth.boot</groupId>
  <artifactId>spring-security-oauth2-autoconfigure</artifactId>
  <version>2.0.0.RELEASE</version>
</dependency>
Zmodyfikujmy naszą konfigurację Spring Security w pliku SecurityConfig. Najpierw dodajmy adnotację @EnableOAuth2Client. Automatycznie wyświetli dane potrzebne do zalogowania się za pośrednictwem sieci społecznościowych.

Konfiguracja filtra i właściwości aplikacji

Wstrzyknijmy OAuth2ClientContext do użycia w naszej konfiguracji zabezpieczeń.
@Autowired
private OAuth2ClientContext oAuth2ClientContext;
OAuth2ClientContext jest używany podczas tworzenia filtru sprawdzającego żądanie logowania użytkownika w mediach społecznościowych. Filtr jest dostępny dzięki adnotacji @EnableOAuth2Client. Wszystko, co musimy zrobić, to wywołać go we właściwej kolejności, przed głównym filtrem Spring Security. Tylko wtedy będziemy mogli wyłapać przekierowania podczas procesu logowania za pomocą OAuth2. W tym celu używamy FilterRegistrationBean, w którym ustawiamy priorytet naszego filtra na -100.
@Bean
public FilterRegistrationBean oAuth2ClientFilterRegistration(OAuth2ClientContextFilter oAuth2ClientContextFilter)
{
  FilterRegistrationBean registration = new FilterRegistrationBean();
  registration.setFilter(oAuth2ClientContextFilter);
  registration.setOrder(-100);
  return registration;
}

private Filter ssoFilter()
{
  OAuth2ClientAuthenticationProcessingFilter googleFilter = new OAuth2ClientAuthenticationProcessingFilter("/login/google");
  OAuth2RestTemplate googleTemplate = new OAuth2RestTemplate(google(), oAuth2ClientContext);
  googleFilter.setRestTemplate(googleTemplate);
  CustomUserInfoTokenServices tokenServices = new CustomUserInfoTokenServices(googleResource().getUserInfoUri(), google().getClientId());
  tokenServices.setRestTemplate(googleTemplate);
  googleFilter.setTokenServices(tokenServices);
  tokenServices.setUserRepo(userRepo);
  tokenServices.setPasswordEncoder(passwordEncoder);
  return googleFilter;
}
Musisz także dodać nowy filtr do funkcji konfiguracji(HttpSecurity http):
http.addFilterBefore(ssoFilter(), UsernamePasswordAuthenticationFilter.class);
Filtr musi także wiedzieć, że klient zarejestrował się przez Google. Adnotacja @ConfigurationProperties określa, których właściwości konfiguracyjnych należy szukać w application.properties.
@Bean
@ConfigurationProperties("google.client")
public AuthorizationCodeResourceDetails google()
{
  return new AuthorizationCodeResourceDetails();
}
Aby zakończyć uwierzytelnianie, musisz określić punkt końcowy informacji o użytkowniku Google:
@Bean
@ConfigurationProperties("google.resource")
public ResourceServerProperties googleResource()
{
  return new ResourceServerProperties();
}
Po zarejestrowaniu naszej aplikacji w Google Cloud Platform dodamy właściwości z odpowiednimi przedrostkami do application.properties:
google.client.clientId=yourClientId
google.client.clientSecret=yourClientSecret
google.client.accessTokenUri=https://www.googleapis.com/oauth2/v4/token
google.client.userAuthorizationUri=https://accounts.google.com/o/oauth2/v2/auth
google.client.clientAuthenticationScheme=form
google.client.scope=openid,email,profile
google.resource.userInfoUri=https://www.googleapis.com/oauth2/v3/userinfo
google.resource.preferTokenInfo=true

Najważniejsze informacje dotyczące rejestracji aplikacji w Google Cloud Platform

Ścieżka: Interfejsy API i usługi -> Poświadczenia Okno żądania dostępu OAuth:
  • Nazwa aplikacji: Spring formularz logowania i tutorial OAuth2
  • Adres e-mail pomocy technicznej: Twój e-mail
  • Zakres API Google: e-mail, profil, openid
  • Autoryzowane domeny: me.org
  • Link do strony głównej aplikacji: http://me.org:8080
  • Link do polityki prywatności aplikacji: http://me.org:8080
  • Link do warunków korzystania z aplikacji: http://me.org:8080
Referencje:
  • Typ: aplikacja internetowa
  • Tytuł: Springowy formularz logowania i tutorial OAuth2
  • Dozwolone źródła JavaScript: http://me.org, http://me.org:8080
  • Dozwolone identyfikatory URI przekierowań: http://me.org:8080/login, http://me.org:8080/login/google
Uwaga: ponieważ Google nie chce pracować z adresem localhost:8080, dodaj na końcu linię „127.0.0.1 me.org” lub coś podobnego do pliku C:\Windows\System32\drivers\etc\hosts. Najważniejsze, że domena ma klasyczną formę.

Niestandardowe usługiUserInfoTokenServices

Czy zauważyłeś słowo Custom w opisie funkcji filtra? Klasa CustomUserInfoTokenServices. Tak, stworzymy własną klasę z blackjackiem i możliwością zapisania użytkownika w bazie danych! Używając skrótu klawiaturowego Ctrl-N w IntelliJ IDEA, możesz znaleźć i zobaczyć, jak UserInfoTokenServiceszaimplementowano ustawienie domyślne. Skopiujmy jego kod do nowo utworzonej klasy CustomUserInfoTokenServices. Większość z nich można pozostawić bez zmian. Zanim zmienimy logikę funkcji, dodajmy UserRepoi jako pola prywatne klasy PasswordEncoder. Stwórzmy dla nich setery. Dodajmy @Autowired UserRepo userRepo do klasy SecurityConfig. Patrzymy, jak znika wskaźnik błędu w metodzie tworzenia filtra i cieszymy się. Dlaczego nie można zastosować @Autowired bezpośrednio do CustomUserInfoTokenServices? Ponieważ ta klasa nie przejmie zależności, ponieważ sama nie jest oznaczona żadną adnotacją Springa, a jej konstruktor jest tworzony jawnie podczas deklaracji filtra. W związku z tym mechanizm DI Springa o tym nie wie. Jeśli dodamy adnotację @Autowired do czegokolwiek w tej klasie, otrzymamy wyjątek NullPointerException. Ale dzięki jawnym ustawieniom wszystko działa bardzo dobrze. Po zaimplementowaniu niezbędnych komponentów głównym obiektem zainteresowania staje się funkcja loadingAuthentication, w ramach której pobierana jest funkcja Map<String, Object> z informacjami o użytkowniku. To właśnie w tym projekcie zaimplementowałem zapisywanie do bazy danych użytkownika zalogowanego przez portal społecznościowy. Ponieważ jako dostawca OAuth2 korzystamy z konta Google, sprawdzamy, czy mapa zawiera typowe dla Google pole „sub”. Jeżeli jest obecny, oznacza to, że informacja o użytkowniku została otrzymana prawidłowo. Tworzymy nowego użytkownika i zapisujemy go do bazy danych.
@Override
public OAuth2Authentication loadAuthentication(String accessToken)
     throws AuthenticationException, InvalidTokenException
{
  Map<String, Object> map = getMap(this.userInfoEndpointUrl, accessToken);

  if(map.containsKey("sub"))
  {
     String googleName = (String) map.get("name");
     String googleUsername = (String) map.get("email");

     User user = userRepo.findByGoogleUsername(googleUsername);

     if(user == null)
     {
        user = new User();
        user.setActive(true);
        user.setRoles(Collections.singleton(Role.USER));
     }

     user.setName(googleName);
     user.setUsername(googleUsername);
     user.setGoogleName(googleName);
     user.setGoogleUsername(googleUsername);
     user.setPassword(passwordEncoder.encode("oauth2user"));

     userRepo.save(user);
  }

  if (map.containsKey("error"))
  {
     this.logger.debug("userinfo returned error: " + map.get("error"));
     throw new InvalidTokenException(accessToken);
  }
  return extractAuthentication(map);
}
W przypadku korzystania z kilku dostawców można określić różne opcje w jednym CustomUserInfoTokenServices i zarejestrować różne klasy podobnych usług w metodzie deklaracji filter. Teraz zarówno użytkownik, jak i OAuth2Authentication mogą działać jako zleceniodawcy. Ponieważ w UserService uwzględniliśmy z wyprzedzeniem ładowanie użytkownika przez dane Google, aplikacja będzie działać dla obu typów użytkowników. Modyfikujemy kontroler strony głównej projektu tak, aby przekierowywał użytkowników zalogowanych przy użyciu OAuth2 na stronę notatek.
@GetMapping("/")
public String index(Principal principal)
{
  if(principal != null)
  {
     return "redirect:/notes";
  }
  return "index";
}

Ostateczne uruchomienie projektu

Po drobnych kosmetycznych zmianach i dodaniu przycisku wyjścia, przeprowadzamy ostateczne uruchomienie projektu.
Wprowadźmy regularne logowanie poprzez e-mail i OAuth2 do Spring Security na przykładzie usługi notatek - 8
Wprowadźmy regularne logowanie przez e-mail i OAuth2 do Spring Security na przykładzie usługi notatek - 9
Wprowadźmy regularne logowanie przez e-mail i OAuth2 do Spring Security na przykładzie usługi notatki - 10
Wprowadźmy regularne logowanie przez e-mail i OAuth2 do Spring Security na przykładzie usługi notatki - 11
Wprowadźmy regularne logowanie przez e-mail i OAuth2 do Spring Security na przykładzie usługi notatki - 12
Wprowadźmy regularne logowanie przez e-mail i OAuth2 do Spring Security na przykładzie usługi notatki - 13
Wprowadźmy regularne logowanie przez e-mail i OAuth2 do Spring Security na przykładzie usługi notatki - 14
Wprowadźmy regularne logowanie poprzez e-mail i OAuth2 do Spring Security na przykładzie usługi notatek - 15
Użytkownik pomyślnie loguje się zarówno poprzez zwykły formularz, jak i poprzez konto Google. Tego właśnie chcieliśmy! Mam nadzieję, że ten artykuł wyjaśnił niektóre kwestie dotyczące tworzenia aplikacji internetowej, zabezpieczania jej za pomocą Spring Security i łączenia różnych metod logowania. Dzięki pełnemu kodowi projektu możesz to zrobić
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION