Spring Security

Spring Security bietet Möglichkeiten zur Authentifizierung und Autorisierung in einer Webanwendung. Wir können Spring Security in jeder servletbasierten Webanwendung verwenden.

Vorteile der Verwendung von Spring Security

Spring-Sicherheitsbeispiel-TutorialEinige der Vorteile der Verwendung von Spring Security sind:

  • Bewährte Technologie, es ist besser, diese zu verwenden, als das Rad neu zu erfinden. Sicherheit ist etwas, bei dem wir besonders vorsichtig sein müssen, sonst ist unsere Anwendung für Angreifer anfällig.
  • Verhindert einige der häufigsten Angriffe wie CSRF, Session-Fixierung-Angriffe.
  • Einfach in jede Webanwendung zu integrieren. Wir müssen keine Webanwendungskonfigurationen ändern, Spring fügt automatisch Sicherheitsfilter in die Webanwendung ein.
  • Bietet Unterstützung für Authentifizierung auf verschiedene Weisen – im Speicher, DAO, JDBC, LDAP und viele mehr.
  • Bietet die Möglichkeit, spezifische URL-Muster zu ignorieren, gut für die Bereitstellung statischer HTML-, Bild-Dateien.
  • Unterstützung für Gruppen und Rollen.

Spring Security Beispiel

Wir werden eine Webanwendung erstellen und sie mit Spring Security integrieren. Erstellen Sie eine Webanwendung mit der Option „Dynamic Web Project“ in Eclipse, damit unser Grundgerüst der Webanwendung bereit ist. Stellen Sie sicher, dass Sie es in ein Maven-Projekt umwandeln, da wir Maven für Build und Deployment verwenden. Sobald unsere Anwendung gesichert ist, wird die endgültige Projektstruktur wie das folgende Bild aussehen.

Wir werden uns drei Spring Security-Authentifizierungsmethoden ansehen.

  • im Speicher
  • DAO
  • JDBC

Datenbankskript für JDBC-Authentifizierung

Für JDBC verwenden wir eine MySQL-Datenbank und haben folgendes Skript ausgeführt, um die Benutzerdetailtabellen zu erstellen.

CREATE TABLE `Employees` (
  `username` varchar(20) NOT NULL DEFAULT '',
  `password` varchar(20) NOT NULL DEFAULT '',
  `enabled` tinyint(1) NOT NULL DEFAULT '1',
  PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `Roles` (
  `username` varchar(20) NOT NULL DEFAULT '',
  `role` varchar(20) NOT NULL DEFAULT '',
  PRIMARY KEY (`username`,`role`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `Employees` (`username`, `password`, `enabled`)
VALUES
    ('pankaj', 'pankaj123', 1);

INSERT INTO `Roles` (`username`, `role`)
VALUES
    ('pankaj', 'Admin'),
    ('pankaj', 'CEO');

commit;

Wir müssen auch JDBC DataSource als JNDI in unserem Servlet-Container konfigurieren, um mehr darüber zu erfahren, lesen Sie bitte das Tomcat JNDI DataSource-Beispiel.

Spring Security Maven-Abhängigkeiten

Hier ist unsere endgültige pom.xml-Datei.

<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>WebappSpringSecurity</groupId>
    <artifactId>WebappSpringSecurity</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <dependencies>
        <!-- Spring Security Artifacts - START -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>3.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>3.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
            <version>3.0.5.RELEASE</version>
        </dependency>
        <!-- Spring Security Artifacts - END -->

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.0.2.RELEASE</version>
        </dependency>
    </dependencies>
    <build>
        <sourceDirectory>src</sourceDirectory>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <warSourceDirectory>WebContent</warSourceDirectory>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Spring Security Beispiel UserDetailsService DAO-Implementierung

Da wir auch eine DAO-basierte Authentifizierung verwenden werden, müssen wir das UserDetailsService-Interface implementieren und die Implementierung für die Methode loadUserByUsername() bereitstellen. Idealerweise sollten wir eine Ressource verwenden, um den Benutzer zu validieren, aber zur Vereinfachung machen wir nur eine grundlegende Validierung.

AppUserDetailsServiceDAO.java

package com.journaldev.webapp.spring.dao;

import java.util.Collection;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

public class AppUserDetailsServiceDAO implements UserDetailsService {

    protected final Log logger = LogFactory.getLog(getClass());
    
    @Override
    public UserDetails loadUserByUsername(final String username)
            throws UsernameNotFoundException {
        
        logger.info("loadUserByUsername username="+username);
        
        if(!username.equals("pankaj")){
            throw new UsernameNotFoundException(username + " nicht gefunden");
        }
        
        // Erstellen von Dummy-Benutzerdetails, sollte JDBC-Operationen durchführen
        return new UserDetails() {
            
            private static final long serialVersionUID = 2059202961588104658L;

            @Override
            public boolean isEnabled() {
                return true;
            }
            
            @Override
            public boolean isCredentialsNonExpired() {
                return true;
            }
            
            @Override
            public boolean isAccountNonLocked() {
                return true;
            }
            
            @Override
            public boolean isAccountNonExpired() {
                return true;
            }
            
            @Override
            public String getUsername() {
                return username;
            }
            
            @Override
            public String getPassword() {
                return "pankaj123";
            }
            
            @Override
            public Collection<? extends GrantedAuthority> getAuthorities() {
                List<SimpleGrantedAuthority> auths = new java.util.ArrayList<SimpleGrantedAuthority>();
                auths.add(new SimpleGrantedAuthority("admin"));
                return auths;
            }
        };
    }

}

Beachten Sie, dass wir eine anonyme innere Klasse von UserDetails erstellen und zurückgeben. Sie können eine Implementierungsklasse dafür erstellen und dann instanziieren und zurückgeben. Normalerweise ist das der Weg, den man in tatsächlichen Anwendungen gehen sollte.

Spring Security Beispiel WebSecurityConfigurer-Implementierung

Wir können das WebSecurityConfigurer-Interface implementieren oder die Basisklasse WebSecurityConfigurerAdapter erweitern und die Methoden überschreiben.

SecurityConfig.java

package com.journaldev.webapp.spring.security;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

import com.journaldev.webapp.spring.dao.AppUserDetailsServiceDAO;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

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

        // In-Memory-Authentifizierung
        // auth.inMemoryAuthentication().withUser("pankaj").password("pankaj123").roles("USER");

        // Verwendung des benutzerdefinierten UserDetailsService DAO
        // auth.userDetailsService(new AppUserDetailsServiceDAO());

        // Verwendung von JDBC
        Context ctx = new InitialContext();
        DataSource ds = (DataSource) ctx
                .lookup("java:/comp/env/jdbc/MyLocalDB");

        final String findUserQuery = "select username,password,enabled "
                + "from Employees " + "where username = ?";
        final String findRoles = "select username,role " + "from Roles "
                + "where username = ?";
        
        auth.jdbcAuthentication().dataSource(ds)
                .usersByUsernameQuery(findUserQuery)
                .authoritiesByUsernameQuery(findRoles);
    }
    
    @Override
    public void configure(WebSecurity web) throws Exception {
        web
            .ignoring()
                // Spring Security sollte URLs, die auf .html enden, komplett ignorieren
                .antMatchers("/*.html");
    }

}

Beachten Sie, dass wir alle HTML-Dateien ignorieren, indem wir die Methode configure(WebSecurity web) überschreiben. Der Code zeigt, wie man JDBC-Authentifizierung einbindet. Wir müssen es konfigurieren, indem wir DataSource bereitstellen. Da wir benutzerdefinierte Tabellen verwenden, müssen wir auch die Select-Abfragen bereitstellen, um die Benutzerdetails und deren Rollen zu erhalten. Die Konfiguration der In-Memory- und DAO-basierten Authentifizierung ist einfach, sie sind im obigen Code kommentiert. Sie können sie entkommentieren, um sie zu verwenden, stellen Sie sicher, dass Sie jeweils nur eine Konfiguration haben. Die Annotationen @Configuration und @EnableWebSecurity sind erforderlich, damit das Spring-Framework weiß, dass diese Klasse für die Spring Security-Konfiguration verwendet wird. Die Spring Security-Konfiguration verwendet das Builder-Muster und basierend auf der Methode authenticate stehen einige der Methoden später nicht mehr zur Verfügung. Zum Beispiel gibt auth.userDetailsService() die Instanz von UserDetailsService zurück und dann können wir keine anderen Optionen mehr haben, wie z.B. können wir DataSource danach nicht mehr festlegen.

Integration von Spring Security Web mit Servlet API

Der letzte Teil besteht darin, unsere Spring Security-Konfigurationsklasse in das Servlet API zu integrieren. Dies kann einfach erfolgen, indem man die Klasse AbstractSecurityWebApplicationInitializer erweitert und die Sicherheitskonfigurationsklasse im Superklassenkonstruktor übergibt.

SecurityWebApplicationInitializer.java

package com.journaldev.webapp.spring.security;

import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

public class SecurityWebApplicationInitializer extends
        AbstractSecurityWebApplicationInitializer {

    public SecurityWebApplicationInitializer() {
        super(SecurityConfig.class);
    }
}

Wenn unser Kontext startet, verwendet er ServletContext, um den ContextLoaderListener-Listener hinzuzufügen und unsere Konfigurationsklasse als Servlet-Filter zu registrieren. Beachten Sie, dass dies nur in Servlet-3-konformen Servlet-Containern funktionieren wird. Wenn Sie also Apache Tomcat verwenden, stellen Sie sicher, dass seine Version 7.0 oder höher ist. Unser Projekt ist bereit, deployen Sie es einfach in Ihrem bevorzugten Servlet-Container. Ich verwende Apache Tomcat-7, um diese Anwendung auszuführen. Die folgenden Bilder zeigen die Antwort in verschiedenen Szenarien.

Zugriff auf HTML-Seite ohne Sicherheit

Authentifizierung fehlgeschlagen bei schlechten Anmeldeinformationen

Startseite mit Spring Security JDBC-Authentifizierung

Startseite mit Spring Security UserDetailsService DAO-Authentifizierung

Startseite mit Spring Security In-Memory-Authentifizierung

Abmeldeseite

Wenn Sie einen Servlet-Container verwenden möchten, der die Servlet-Spezifikationen 3 nicht unterstützt, müssen Sie den DispatcherServlet über den Bereitstellungsdeskriptor registrieren. Das ist alles für den Spring Security-Leitfaden und seine Integration in servletbasierte Webanwendungen.

Kostenlosen Account erstellen

Registrieren Sie sich jetzt und erhalten Sie Zugang zu unseren Cloud Produkten.

Das könnte Sie auch interessieren:

centron Managed Cloud Hosting in Deutschland

Google Places API Anleitung

Google Places API Anleitung Die Google Places API kann verwendet werden, um nahegelegene Orte zu finden. In diesem Tutorial entwickeln wir eine Anwendung, die die nahegelegenen Orte unserer Wahl zusammen…
centron Managed Cloud Hosting in Deutschland

Extended Security Updates für Windows Server

Security
Extended Security Updates für Windows Server Extended Security Updates (ESU) für Windows Server umfassen Sicherheitsupdates und Bulletins, die als kritisch und wichtig eingestuft sind. Content1 Wie Sie ESUs erhalten, hängt…