DE EN

Wie verwende ich Spring Security um eine einfache Login-Seite zur erstellen?

von

Alle Artikel dieser Serie

Einführung in Spring Security 5

Wenn du den Weg zu dieser Seite gefunden hast, weißt du wahrscheinlich, was Spring für Java ist. Möglicherweise hast du eine Webanwendung mit Spring Web oder besser Spring Boot erstellt und willst deine Benutzer jetzt über eine Anmeldeseite authentifizieren und autorisieren.

Spring Security 5 wurde genau dafür entwickelt und wird das für uns erledigen. Ich bin ehrlich, es gibt eine gewisse Lernkurve und die Dokumentation ist nicht immer hilfreich, aber sobald man die Grundlagen verstanden hat, ist es recht einfach zu verwenden.

Außerdem wird Spring Security 5 die meisten unserer Sicherheitsprobleme lösen und seien wir ehrlich: Wir Anwendungsentwickler haben viel zu tun und können jede Hilfe gebrauchen, die wir bekommen können!

Was brauchst du dafür?

Ich gehe davon aus, dass du mindestens Grundkenntnisse von Spring hast und dich Begriffe wie “Dependency Injection” nicht erschrecken. Abgesehen davon ist es hilfreich, wenn du bereits eine Java-Webanwendung mit Spring Boot entwickelt hast, in der du den Code ausprobieren kannst, den wir in diesem Artikel behandeln.

Begrifflichkeiten

Jetzt ist es wirklich wichtig, dass du diese Begriffe kennst und dich an ihre Bedeutung erinnerst, wenn du diesen Artikel liest.

  • Principal: bezieht sich auf das von Spring Security bereitgestellte authentifizierte Benutzerobjekt
  • Authentication: bezieht sich auf die erfolgreiche Anmeldung mit einem Benutzernamen und einem Passwort
  • Authorization: bezieht sich darauf, auf bestimmte Teile Ihrer Anwendung zugreifen zu dürfen
  • Role: bezieht sich auf ein Handle, dem Berechtigungsregeln zugewiesen werden können

Erstellen wir ein einfaches Anmeldeformular

Spring Security ist eigentlich sehr einfach, wenn die Sicherheitsanforderungen unkompliziert sind. Darauf aufbauend können aber auch Anwendungen für komplexere Szenarien erstellt werden.

Das Hinzufügen von Spring Security zu deiner Anwendung ist ganz einfach. Füge deiner pom.xml einfach die folgende Abhängigkeit hinzu:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Ich gehe davon aus, dass du bereits andere Abhängigkeiten wie Spring-Web, Spring-Core usw. in deinem Klassenpfad hast. Hoffentlich verwendest du Spring Boot, da es die bevorzugte Methode zum Erstellen von Anwendung dieser Art ist.

Außerdem benötigst du eine Controller-Klasse, auf die du mittels Browser zugreifen kannst:

@Controller
public class HomeController {

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

Dies ist eine sehr einfache Controller-Klasse mit einer einzelnen Methode, die dem Stammverzeichnis der Anwendung zugeordnet ist. root of your application = Stammverzeichnis?

Und natürlich brauchst du auch eine HTML-Seite. Platziere diese unter /src/main/resources/templates/index.html

Hier ein sehr einfaches Beispiel:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Welcome</title>
  </head>
  <body>
    <h1>Welcome</h1>
  </body>
</html>

Übrigens verwende ich in diesem Beispiel Thymeleaf. Du kannst wahlweise eine andere Template-Engine verwenden. Dies hat keinen Einfluss auf das Thema, dass in diesem Artikel behandelt wird.

Eine weitere Sache ist, Spring mitzuteilen, dass die Anwendung abgesichert werden soll. Dazu musst du deiner Konfigurationsklasse die Annotation [\@EnableWebSecurity]{.citation data-cites=”EnableWebSecurity”} hinzufügen. Dabei handelt es sich um eine Klasse, die du bereits für deine Sicherheitskonfigurationen erstellt haben solltest.

@EnableWebSecurity
public class SecurityConfiguration {
}

Fahren wir fort und starten die Anwendung neu.

Deine Anwendung ist jetzt schon sicherer als zuvor. Du erhältst eine schöne Anmeldeseite, wenn du versuchst, auf die Anwendung zuzugreifen.

Das ist nur die Spitze des Eisbergs, den wir Spring Security nennen. Wenn du es näher betrachtest, wirst du feststellen, dass Spring Security nicht nur jede Seite in deiner Anwendung schützt, sondern auch einen Benutzer für dich erstellt hat.

Du findest das Kennwort in der Befehlszeile und solltest dich jetzt anmelden können.

Spring Security konfigurieren: Benutzer

Widmen wird uns nun den interessanten Themen.

Beginnen wir mit dem Hinzufügen von zwei Benutzern. Emma und Chris. Emma ist die Chefin von Chris. Sie hat also die Rollen “boss” und “dev” (ja, Emmas Codierungsfähigkeiten sind sehr gut, deshalb ist sie die Chefin).

Chris hat die Rolle “dev”. Nehmen wir an, dass sowohl Chris als auch Emma ihre Namen als Kennwörter verwenden (macht das nicht zu Hause, sondern verwendet immer einen Kennwort-Manager).

Dazu müssen wir einige Konfigurationen hinzufügen. Es ist schön, dass Spring Security uns einige Adapterklassen standardmäßig zur Verfügung stellt. Hiervon sehen wir uns den WebSecurityConfigurerAdapter an. Ein Adapter ist eine Klasse, die eine bestimmte Schnittstelle implementiert. Der Adapter stellt bereits einige nützliche Standardimplementierungen bereit, so dass wir nicht alle Methoden selbst implementieren müssen.

Der WebSecurityConfigurerAdapter implementiert den WebSecurityConfigurer und hat einige nette Implementierungen, die uns weiter helfen.

Es gibt eine Methode, die ich mit eigenen Funktionalität überschreiben möchte. Dabei handelt es sich um die, die das Passwort in die Kommandozeile geschrieben hat. Da wir die Passwörter natürlich nicht veröffentlichen wollen, müssen wir diese Methode selbst implementieren.

Der Name der Methode lautet “configure” und es wird ein AuthenticationManagerBuilder als einziges Argument verwendet - siehe das folgende Codesegment.

@EnableWebSecurity
public class MemorySecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

    }
}

Wie der Name schon sagt, ist der AuthenticationManagerBuilder eine Klasse, die eine erweiterte Konfiguration für die Authentifizierung erstellt. Beginnen wir zunächst mit der In-Memory-Authentifizierung und verwenden die Schnittstelle:

@EnableWebSecurity
public class MemorySecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .inMemoryAuthentication();
    }
}

Jetzt weiß Spring, dass wir unseren RAM zum Speichern von Benutzern verwenden möchten. Natürlich gibt es noch keine Benutzer und wir müssen selbst ein paar hinzufügen.

Zurück zu Chris und Emma.

@EnableWebSecurity
public class MemorySecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
            .withUser("emma")
                .password("emma")
                .roles("boss", "dev")
            .and().withUser("chris")
                .password("chris")
                .roles("dev");
    }
}

Dieser Code sollte ziemlich verständlich sein. Wenn er es nicht ist, mach dir keine Sorgen. Hier haben wir Spring lediglich mitgeteilt, dass wir eine In-Memory-Authentifizierung mit dem Benutzer “emma” wünschen, die das Kennwort “emma” verwendet und die Rollen “boss” und “dev” hat. Anschließend haben wird dasselbe mit Chris gemacht.

Außerdem speichern wir Passwörter im Klartext in unserem Code. Dies ist definitiv keine gute Idee. Die Passwortverschlüsselung ist eine Voraussetzung für eine GDPR-Zertifizierung (die du anstreben solltest).

Fügen wir also unseren Passwörtern eine Verschlüsselung hinzu. Es macht nicht viel Sinn, wenn wir sie in unserem Code speichern, aber das ist so einfacher, deswegen machen wir es trotzdem.

Wir werden “BCrypt” verwenden, um unsere Passwörter zu verschlüsseln. Die Verschlüsselung ist in diesem Blog nicht enthalten (und ich habe davon auch keine Ahnung), daher verweise ich dich auf kompetente Blogs an anderer Stelle, wenn du mehr wissen möchtest.

Hier ist die vollständige Klasse, einschließlich der BCrypt-Verschlüsselung:

@EnableWebSecurity
public class MemorySecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .inMemoryAuthentication()
                .withUser("emma").password("emma").roles("boss", "dev").and()
                .withUser("chris").password("chris").roles("dev").and()
                .passwordEncoder(new BCryptPasswordEncoder();
    }
}

Wie du siehst, erstellen wir einfach eine neue Instanz von BCryptPasswordEncoder und fügen sie dem “passwordEncoder” hinzu.

Starte jetzt die Spring-Anwendung neu. Jetzt solltest du dich entweder als Emma oder als Chris anmelden können.

Wir haben keine der Rollen verwendet, die diesen Benutzern zugewiesen wurden. Obwohl wir authentifiziert sind, findet noch keine echte Autorisierung statt. Um dies zu erreichen, muss noch eine andere Methode überschrieben werden.

Wieder wird configure aufgerufen, aber in der MemorySecurityConfiguration-Klasse wird jetzt ein anderes Argument verwendet: HttpSecurity.

@EnableWebSecurity
public class MemorySecurityConfiguration extends WebSecurityConfigurerAdapter {

    ...

    @Override
    protected void configure(HttpSecurity http) throws Exception {
    }
}

HttpSecurity ist dem Authentifizierungs-Builder sehr ähnlich und verfügt auch über ein Interface. Als erstes muss Spring angewiesen werden, formLogin zu verwenden. Das ist die Standardeinstellung, aber lass es uns explizit machen.

@EnableWebSecurity
public class MemorySecurityConfiguration extends WebSecurityConfigurerAdapter {

    ...

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin();
    }
}

Fügen wir nun einige Autorisierungsregeln hinzu.

@EnableWebSecurity
public class MemorySecurityConfiguration extends WebSecurityConfigurerAdapter {

    ...

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin();

        http.authorizeRequests()
                .antMatchers("/devs/*").hasAnyRole("boss", "dev")
                .antMatchers("/boss/*").hasRole("boss")
                .antMatchers("/").permitAll();
    }
}

Rufen wir zunächst authorizeRequests() auf, da wir Zugriff auf ein “Registry”-Objekt benötigen, in dem die für jede Rolle zulässigen Webrouten gespeichert sind. Anschließend werden wir “antMatcher” verwenden, um das Mapping zu identifizieren.

Alles, was wir in dieser Methode getan haben, ist, Spring zu informieren, dass nur Benutzer mit der Rolle “boss” auf die “/boss/"-Routen und Benutzer mit der Rollen "dev" auf die "/dev/“-Routen zugreifen dürfen. Zusätzlich haben alle Benutzer auf die “/”-Route Zugriff.

Ant-Matcher sind ein Beschreibungsstil aus dem Projekt Apache Ant. Es ist ein bisschen wie bei Regular Expressions, aber einfacher. Mehr zu den Optionen findest du hier.

Was sollte ich als nächstes lesen?

Die formularbasierte Authentifizierung ist in Ordnung. Aber im Ernst, wer speichert Benutzer im Speicher? Als Nächstes solltest du lesen, wie man Benutzer über eine Datenbank authentifiziert.

Image Credits

Tags: #Java #Spring #Spring Security #Login

Newsletter

ABMELDEN