JavaRush /Java-Blog /Random-DE /Lassen Sie uns am Beispiel des Notes-Dienstes die regelmä...

Lassen Sie uns am Beispiel des Notes-Dienstes die regelmäßige Anmeldung per E-Mail und OAuth2 bei Spring Security einführen

Veröffentlicht in der Gruppe Random-DE
Während ich meine Bewerbung schrieb, stieß ich auf einen Mangel an klaren Artikeln darüber, wie man den Benutzer dazu bringen kann, sich sowohl per E-Mail als auch über soziale Netzwerke zu registrieren. Es gab gute Tutorials zum Einrichten des klassischen Anmeldeformulars. Es gab gute Tutorials zu OAuth2 . Es gab erschreckend wenige Informationen darüber, wie man die beiden Methoden kombinieren könnte. Während des Suchprozesses konnten wir eine praktikable Lösung finden. Es erhebt nicht den Anspruch, die ultimative Wahrheit zu sein, aber es erfüllt seine Funktion. In diesem Artikel werde ich zeigen, wie man einen Notizspeicherdienst mit einer ähnlichen Spring Security-Konfiguration von Grund auf implementiert. Lassen Sie uns am Beispiel des Notes-Dienstes die regelmäßige Anmeldung per E-Mail und OAuth2 bei Spring Security einführen – 1Hinweis: Es ist gut, wenn der Leser mindestens ein paar Tutorials zu Spring durchgelesen hat, da sich die Aufmerksamkeit nur auf Spring Security konzentriert, ohne detaillierte Erklärungen zu Repositorys, Controllern usw. Andernfalls würde sich herausstellen, dass der Artikel ohnehin schon recht umfangreich ist gigantisch sein. Inhalt
  1. Ein Projekt erstellen
  2. Erstellen von Entitäten und Anwendungslogik
    1. Entitäten
    2. Repositories
    3. Controller
    4. Seiten
  3. Konfigurieren von Spring Security für die klassische Anmeldung
    1. Grundkonfiguration SecurityConfig
    2. Benutzerdefinierte Benutzeranmeldung
    3. Lassen Sie uns den Controller verbessern
    4. Start
  4. Einrichten von OAuth2 am Beispiel von Google in Spring Security
    1. Filterkonfiguration und application.properties
    2. Highlights der Registrierung einer Anwendung bei der Google Cloud Platform
    3. CustomUserInfoTokenServices
  5. Endgültiger Start des Projekts

Ein Projekt erstellen

Wir gehen zu start.spring.io und bilden die Grundlage des Projekts:
  • Web – Starten einer Anwendung auf dem integrierten Tomcat, URL-Zuordnungen und dergleichen;
  • JPA – Datenbankverbindung;
  • Moustache ist eine Template-Engine zum Generieren von Webseiten.
  • Sicherheit – Anwendungsschutz. Dafür wurde dieser Artikel erstellt.
Laden Sie das resultierende Archiv herunter und entpacken Sie es in den gewünschten Ordner. Wir starten es in der IDE. Sie können die Datenbank nach eigenem Ermessen auswählen. Ich verwende MySQL als Datenbank für das Projekt, daher füge ich die folgende Abhängigkeit zur Datei pom.xml im Block <dependencies> hinzu:
<dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
     <version>5.1.34</version>
</dependency>
Die application.properties-Konfiguration sieht derzeit wie folgt aus:
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

Erstellen von Entitäten und Anwendungslogik

Entitäten

Erstellen wir ein Paket, entitiesin dem wir die Datenbankentitäten platzieren. Der Benutzer wird durch eine Klasse beschrieben User, die die Schnittstelle implementiert UserDetails, die für die Spring Security-Konfiguration benötigt wird. Der Benutzer verfügt über eine ID, einen Benutzernamen (dies ist eine E-Mail), ein Passwort, einen Namen, eine Rolle, eine Aktivitätsmarkierung, einen Google-Kontonamen und eine E-Mail-Adresse ( googleNameund 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
}
Benutzerrollen werden verwendet, um den Zugriff in Spring Security zu regulieren. Unsere Anwendung verwendet nur eine Rolle:
public enum Role implements GrantedAuthority
{
  USER;

  @Override
  public String getAuthority()
  {
     return name();
  }
}
Erstellen wir eine Notizklasse mit ID, Notiztitel, Notiztext und ID des Benutzers, zu dem sie gehört:
@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()
}

Repositories

Um Entitäten in der Datenbank zu speichern, benötigen wir Repositorys, die die ganze Drecksarbeit für uns erledigen. Lassen Sie uns ein Paket erstellen repos. Darin erstellen wir Schnittstellen, die von der Schnittstelle UserRepogeerbt werden . NoteRepoJpaRepository<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);
}

Controller

Unser Notizendienst wird die folgenden Seiten umfassen:
  • Heim;
  • Anmeldung;
  • Eingang;
  • Liste der Benutzernotizen.
Nur ein autorisierter Benutzer sollte Zugriff auf die Liste der Notizen haben. Die restlichen Seiten sind öffentlich. Erstellen wir ein Paket controllersmit einer Klasse, IndexControllerdie das übliche Get-Mapping der Hauptseite enthält. Die Klasse RegistrationControllerist für die Registrierung des Benutzers verantwortlich. Post-Mapping übernimmt Daten aus dem Formular, speichert den Benutzer in der Datenbank und leitet ihn zur Anmeldeseite weiter. PasswordEncoderwird später beschrieben. Es dient der Verschlüsselung von Passwörtern.
@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";
  }
Der für die Notizenlistenseite verantwortliche Controller enthält derzeit vereinfachte Funktionen, die nach der Implementierung von Spring Security komplexer werden.
@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";
  }
}
Wir werden keinen Controller für die Anmeldeseite schreiben, da dieser von Spring Security verwendet wird. Stattdessen benötigen wir eine spezielle Konfiguration. Erstellen wir wie üblich ein weiteres Paket, nennen es configund platzieren die Klasse dort MvcConfig. Wenn wir die Spring Security-Konfiguration schreiben, weiß sie, auf welche Seite wir uns beziehen, wenn wir „/login“ verwenden.
@Configuration
public class MvcConfig implements WebMvcConfigurer
{
  public void addViewControllers(ViewControllerRegistry registry)
  {
     registry.addViewController("/login").setViewName("login");
     registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
  }
}

Seiten

Ich verwende die Mustache-Vorlagen-Engine, um Seiten zu erstellen . Sie können eine andere implementieren, das spielt keine Rolle. Für die Metainformationen, die auf allen Seiten verwendet werden, wurde eine meta.mustache-Datei erstellt. Es enthält auch Bootstrap, um die Seiten unseres Projekts schöner aussehen zu lassen. Seiten werden im Verzeichnis „src/main/resources/templates“ erstellt. Die Dateien haben die Erweiterung mustache. Wenn Sie den HTML-Code direkt im Artikel platzieren, wird dieser zu groß. Daher finden Sie hier einen Link zum Vorlagenordner im GitHub-Repository des Projekts .

Konfigurieren von Spring Security für die klassische Anmeldung

Spring Security hilft uns, die Anwendung und ihre Ressourcen vor unbefugtem Zugriff zu schützen. Wir erstellen eine prägnante Arbeitskonfiguration in einer SecurityConfigvon geerbten Klasse WebSecurityConfigurerAdapter, die wir in das Paket einfügen config. Markieren wir es mit der Annotation @EnableWebSecurity, die die Spring Security-Unterstützung aktiviert, und der Annotation @Configuration, die angibt, dass diese Klasse einige Konfigurationen enthält. Hinweis: Die automatisch konfigurierte pom.xml enthielt die Version der übergeordneten Spring Boot-Komponente 2.1.4.RELEASE, die verhinderte, dass Security auf die etablierte Weise implementiert wurde. Um Konflikte im Projekt zu vermeiden, wird empfohlen, die Version auf 2.0.1.RELEASE zu ändern.

Grundkonfiguration SecurityConfig

Unsere Konfiguration wird in der Lage sein:
  1. Passwörter verschlüsseln mit BCryptPasswordEncoder:

    @Autowired
    private PasswordEncoder passwordEncoder;
    
    @Bean
    PasswordEncoder passwordEncoder()
    {
      PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
      return passwordEncoder;
    }
  2. Melden Sie sich mit einem speziell geschriebenen Authentifizierungsanbieter an:

    @Autowired
    private AuthProvider authProvider;
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth)
    {
      auth.authenticationProvider(authProvider);
    }
  3. Ermöglichen Sie anonymen Benutzern den Zugriff auf die Startseite sowie die Registrierungs- und Anmeldeseiten. Alle anderen Anfragen müssen von angemeldeten Benutzern durchgeführt werden. Lassen Sie uns das zuvor beschriebene „/login“ als Anmeldeseite zuweisen. Bei erfolgreicher Anmeldung wird der Benutzer auf eine Seite mit einer Liste von Notizen weitergeleitet; bei einem Fehler verbleibt der Benutzer auf der Anmeldeseite. Nach erfolgreichem Beenden wird der Benutzer zur Hauptseite weitergeleitet.

    @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();
    }

Benutzerdefinierte Benutzeranmeldung

Ein selbst verfasstes Formular AuthProviderermöglicht es dem Benutzer, sich nicht nur per E-Mail, sondern auch mit seinem Benutzernamen anzumelden.
@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;
  }
}
Wie Sie vielleicht bemerkt haben, ist die UserServiceim Paket enthaltene Klasse für das Laden des Benutzers verantwortlich services. In unserem Fall wird ein Benutzer nicht nur anhand des Felds gesucht username, wie bei der integrierten Implementierung, sondern auch anhand des Benutzernamens, des Google-Kontonamens und der E-Mail-Adresse des Google-Kontos. Die letzten beiden Methoden werden uns bei der Implementierung der Anmeldung über OAuth2 nützlich sein. Hier wird die Vorlesung in gekürzter Form wiedergegeben.
@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;
  }
}
Hinweis: Vergessen Sie nicht, die erforderlichen Methoden einzutragen UserRepo!

Lassen Sie uns den Controller verbessern

Wir haben Spring Security konfiguriert. Jetzt ist es an der Zeit, dies in Ihrem Notizen-Controller zu nutzen. Jetzt akzeptiert jede Zuordnung einen zusätzlichen Principal-Parameter, anhand dessen versucht wird, den Benutzer zu finden. Warum kann ich die Klasse nicht direkt einfügen User? Dann kommt es zu einem Konflikt aufgrund einer Nichtübereinstimmung der Benutzertypen, wenn wir uns über soziale Netzwerke anmelden. Wir sorgen schon im Vorfeld für die nötige Flexibilität. Unser Notizen-Controller-Code sieht jetzt so aus:
@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";
}
Hinweis: Im Projekt ist der CSRF- Schutz standardmäßig aktiviert . Deaktivieren Sie ihn also entweder für sich selbst (http.csrf().disable()) oder vergessen Sie als Autor des Artikels nicht, ein verstecktes Feld mit einem CSRF-Token hinzuzufügen an alle Postanfragen.

Start

Wir versuchen, das Projekt zu starten.
Lassen Sie uns am Beispiel des Notes-Dienstes die regelmäßige Anmeldung per E-Mail und OAuth2 bei Spring Security einführen – 1
Lassen Sie uns am Beispiel des Notes-Dienstes die regelmäßige Anmeldung per E-Mail und OAuth2 bei Spring Security einführen – 2
Wir sehen, dass ein neuer Benutzer in der Datenbank aufgetaucht ist. Das Passwort ist verschlüsselt.
Lassen Sie uns am Beispiel des Notes-Dienstes die regelmäßige Anmeldung per E-Mail und OAuth2 bei Spring Security einführen – 3
Lassen Sie uns am Beispiel des Notes-Dienstes die regelmäßige Anmeldung per E-Mail und OAuth2 bei Spring Security einführen – 4
Lassen Sie uns am Beispiel des Notes-Dienstes die regelmäßige Anmeldung per E-Mail und OAuth2 bei Spring Security einführen – 5
Lassen Sie uns am Beispiel des Notes-Dienstes die regelmäßige Anmeldung per E-Mail und OAuth2 bei Spring Security einführen – 6
Die Notizen werden in der Datenbank gespeichert.
Lassen Sie uns am Beispiel des Notes-Dienstes die regelmäßige Anmeldung per E-Mail und OAuth2 bei Spring Security einführen – 7
Wir sehen, dass das Projekt erfolgreich gestartet ist und läuft. Für vollkommenes Glück brauchen wir nur die Möglichkeit, uns über soziale Netzwerke anzumelden. Nun, fangen wir an!

Einrichten von OAuth2 am Beispiel von Google in Spring Security

Bei der Implementierung von OAuth2 habe ich mich auf dieses offizielle Tutorial von Spring verlassen . Um OAuth2 zu unterstützen, fügen Sie die folgende Bibliothek zu pom.xml hinzu:
<dependency>
  <groupId>org.springframework.security.oauth.boot</groupId>
  <artifactId>spring-security-oauth2-autoconfigure</artifactId>
  <version>2.0.0.RELEASE</version>
</dependency>
Ändern wir unsere Spring Security-Konfiguration im SecurityConfig. Fügen wir zunächst die Annotation @EnableOAuth2Client hinzu. Es wird automatisch angezeigt, was Sie für die Anmeldung über soziale Netzwerke benötigen.

Filterkonfiguration und application.properties

Fügen wir OAuth2ClientContext ein, um es in unserer Sicherheitskonfiguration zu verwenden.
@Autowired
private OAuth2ClientContext oAuth2ClientContext;
OAuth2ClientContext wird beim Erstellen eines Filters verwendet, der die Social-Login-Anfrage des Benutzers validiert. Der Filter ist dank der Annotation @EnableOAuth2Client verfügbar. Alles was wir tun müssen, ist es in der richtigen Reihenfolge vor dem Hauptfilter von Spring Security aufzurufen. Nur dann können wir Weiterleitungen während des Anmeldevorgangs mit OAuth2 abfangen. Dazu verwenden wir FilterRegistrationBean, in dem wir die Priorität unseres Filters auf -100 setzen.
@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;
}
Sie müssen außerdem einen neuen Filter zur Funktion configure(HttpSecurity http) hinzufügen:
http.addFilterBefore(ssoFilter(), UsernamePasswordAuthenticationFilter.class);
Der Filter muss außerdem wissen, dass sich der Kunde über Google registriert hat. Die Annotation @ConfigurationProperties gibt an, nach welchen Konfigurationseigenschaften in application.properties gesucht werden soll.
@Bean
@ConfigurationProperties("google.client")
public AuthorizationCodeResourceDetails google()
{
  return new AuthorizationCodeResourceDetails();
}
Um die Authentifizierung abzuschließen, müssen Sie den Endpunkt für Google-Benutzerinformationen angeben:
@Bean
@ConfigurationProperties("google.resource")
public ResourceServerProperties googleResource()
{
  return new ResourceServerProperties();
}
Nachdem wir unsere Anwendung in der Google Cloud Platform registriert haben , fügen wir Eigenschaften mit den entsprechenden Präfixen zu application.properties hinzu:
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

Highlights der Registrierung einer Anwendung bei der Google Cloud Platform

Pfad: APIs und Dienste -> Anmeldeinformationen OAuth-Zugriffsanforderungsfenster:
  • Anwendungsname: Spring-Anmeldeformular und OAuth2-Tutorial
  • Support-E-Mail-Adresse: Ihre E-Mail
  • Geltungsbereich für die Google-API: E-Mail, Profil, OpenID
  • Autorisierte Domains: me.org
  • Link zur Hauptseite der Anwendung: http://me.org:8080
  • Link zur Datenschutzrichtlinie der App: http://me.org:8080
  • Link zu den Nutzungsbedingungen der Anwendung: http://me.org:8080
Referenzen:
  • Typ: Webanwendung
  • Titel: Spring-Anmeldeformular und OAuth2-Tutorial
  • Zulässige JavaScript-Quellen: http://me.org, http://me.org:8080
  • Zulässige Weiterleitungs-URIs: http://me.org:8080/login, http://me.org:8080/login/google
Hinweis: Da Google nicht mit der Adresse localhost:8080 arbeiten möchte, fügen Sie am Ende die Zeile „127.0.0.1 me.org“ oder etwas Ähnliches der Datei C:\Windows\System32\drivers\etc\hosts hinzu. Hauptsache, die Domain hat eine klassische Form.

CustomUserInfoTokenServices

Ist Ihnen das Wort „Benutzerdefiniert“ in der Beschreibung der Filterfunktion aufgefallen? Klasse CustomUserInfoTokenServices. Ja, wir werden unsere eigene Klasse mit Blackjack und der Möglichkeit erstellen, den Benutzer in der Datenbank zu speichern! Mit der Tastenkombination Strg-N in IntelliJ IDEA können Sie herausfinden und sehen, wie die UserInfoTokenServicesStandardeinstellung implementiert ist. Kopieren wir den Code in die neu erstellte Klasse CustomUserInfoTokenServices. Das meiste davon kann unverändert bleiben. Bevor wir die Logik der Funktionen ändern, fügen wir UserRepound als private Felder der Klasse hinzu PasswordEncoder. Lassen Sie uns Setter für sie erstellen. Fügen wir @Autowired UserRepo userRepo zur SecurityConfig-Klasse hinzu. Wir schauen zu, wie der Hinweis auf den Fehler in der Filtererstellungsmethode verschwindet, und freuen uns. Warum konnte @Autowired nicht direkt auf CustomUserInfoTokenServices angewendet werden? Weil diese Klasse die Abhängigkeit nicht übernimmt, da sie nicht mit einer Spring-Annotation markiert ist und ihr Konstruktor explizit erstellt wird, wenn der Filter deklariert wird. Dementsprechend weiß der DI-Mechanismus von Spring nichts davon. Wenn wir @Autowired für irgendetwas in dieser Klasse mit Anmerkungen versehen, erhalten wir bei Verwendung eine NullPointerException. Aber durch explizite Setter funktioniert alles sehr gut. Nach der Implementierung der erforderlichen Komponenten wird das Hauptobjekt von Interesse zur Funktion „loadAuthentication“, in der die Map<String, Object> mit Informationen über den Benutzer abgerufen wird. In diesem Projekt habe ich die Speicherung eines über ein soziales Netzwerk angemeldeten Benutzers in der Datenbank implementiert. Da wir als OAuth2-Anbieter ein Google-Konto nutzen, prüfen wir, ob die Karte das für Google typische „sub“-Feld enthält. Wenn es vorhanden ist, bedeutet dies, dass die Informationen über den Benutzer korrekt empfangen wurden. Wir erstellen einen neuen Benutzer und speichern ihn in der Datenbank.
@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);
}
Wenn Sie mehrere Anbieter verwenden, können Sie unterschiedliche Optionen in einem CustomUserInfoTokenServices angeben und unterschiedliche Klassen ähnlicher Dienste in der Filterdeklarationsmethode registrieren. Jetzt können sowohl Benutzer als auch OAuth2Authentication als Principal fungieren. Da wir im UserService im Voraus die Belastung des Benutzers durch Google-Daten berücksichtigt haben, funktioniert die Anwendung für beide Benutzertypen. Wir ändern den Hauptseiten-Controller des Projekts so, dass er mit OAuth2 angemeldete Benutzer auf die Notizenseite umleitet.
@GetMapping("/")
public String index(Principal principal)
{
  if(principal != null)
  {
     return "redirect:/notes";
  }
  return "index";
}

Endgültiger Start des Projekts

Nach geringfügigen kosmetischen Änderungen und dem Hinzufügen eines Exit-Buttons führen wir den endgültigen Start des Projekts durch.
Lassen Sie uns am Beispiel des Notes-Dienstes die regelmäßige Anmeldung per E-Mail und OAuth2 bei Spring Security einführen – 8
Lassen Sie uns am Beispiel des Notes-Dienstes die regelmäßige Anmeldung per E-Mail und OAuth2 bei Spring Security einführen – 9
Lassen Sie uns am Beispiel des Notes-Dienstes die regelmäßige Anmeldung per E-Mail und OAuth2 bei Spring Security einführen – 10
Lassen Sie uns am Beispiel des Notes-Dienstes die regelmäßige Anmeldung per E-Mail und OAuth2 bei Spring Security einführen – 11
Lassen Sie uns am Beispiel des Notes-Dienstes die regelmäßige Anmeldung per E-Mail und OAuth2 bei Spring Security einführen – 12
Lassen Sie uns am Beispiel des Notes-Dienstes die regelmäßige Anmeldung per E-Mail und OAuth2 bei Spring Security einführen – 13
Lassen Sie uns am Beispiel des Notes-Dienstes die regelmäßige Anmeldung per E-Mail und OAuth2 bei Spring Security einführen – 14
Lassen Sie uns am Beispiel des Notes-Dienstes die regelmäßige Anmeldung per E-Mail und OAuth2 bei Spring Security einführen – 15
Der Benutzer meldet sich erfolgreich sowohl über das reguläre Formular als auch über ein Google-Konto an. Das ist es, was wir wollten! Ich hoffe, dieser Artikel hat einige Punkte zum Erstellen einer Webanwendung, deren Sicherung mit Spring Security und der Kombination verschiedener Anmeldemethoden geklärt. Mit dem vollständigen Projektcode können Sie
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION