Heim > Java > javaLernprogramm > Spring-Autorisierungsserver-Spring-Sicherheit mit benutzerdefiniertem Benutzerdetaildienst für flexible datengesteuerte Authentifizierung

Spring-Autorisierungsserver-Spring-Sicherheit mit benutzerdefiniertem Benutzerdetaildienst für flexible datengesteuerte Authentifizierung

Susan Sarandon
Freigeben: 2025-01-23 12:07:09
Original
599 Leute haben es durchsucht

Spring-Autorisierungsserver

Der Spring Authorization Server ist ein Framework zur Implementierung der OAuth 2.1- und OpenID Connect 1.0-Spezifikationen sowie anderer verwandter Standards. Es basiert auf Spring Security und bietet eine sichere, leichte und anpassbare Grundlage für die Erstellung von Identitätsanbietern, die mit OpenID Connect 1.0- und OAuth2-Autorisierungsserver-Lösungen kompatibel sind.

Funktionsliste

Was ist Spring Security und wie funktioniert es?

kurze Antwort
Spring Security ist ein leistungsstarkes und hochgradig anpassbares Authentifizierungs- und Zugriffskontroll-Framework. Es ist der De-facto-Standard für die Sicherung von Spring-basierten Anwendungen.

Im Kern ist Spring Security im Wesentlichen eine Sammlung von Servlet-Filtern, die Ihre Webanwendung mit robusten Authentifizierungs- und Autorisierungsfunktionen erweitern sollen.

Spring Security lässt sich auch gut mit Frameworks wie Spring Web MVC oder Spring Boot kombinieren und unterstützt Standards wie OAuth2 und SAML. Es generiert automatisch Anmelde- und Abmeldeschnittstellen und schützt Ihre Anwendung vor häufigen Sicherheitslücken wie CSRF.

Nun, das ist nicht sehr hilfreich, oder?

Lassen Sie uns tiefer in die Websicherheit eintauchen, um die Grundlagen ihres Sicherheitsworkflows zu verstehen.

Um ein Spring Security-Experte zu werden, müssen Sie zunächst diese drei Kernkonzepte verstehen:

  • Authentifizierung
  • Autorisierung
  • Servlet-Filter

Hinweis - Überspringen Sie diesen Abschnitt nicht; Es legt den Grundstein für alle Funktionalitäten von Spring Security.

Authentifizierung

Sie müssen online auf Ihr Bankkonto zugreifen, um Ihren Kontostand zu überprüfen oder eine Transaktion durchzuführen. Normalerweise erfolgt dies mit Benutzername und Passwort

Benutzer: „Ich bin John Doe. Mein Benutzername ist: johndoe1985.“
System der Bank: „Bitte überprüfen Sie Ihre Identität. Wie lautet Ihr Passwort?“
Benutzer: „Mein Passwort lautet: secureB@nk2023.“
System der Bank: „Willkommen, John Doe. Hier ist Ihre Kontoübersicht.“

Genehmigung

Für Basisanwendungen kann allein die Authentifizierung ausreichen: Sobald sich ein Benutzer anmeldet, erhält er Zugriff auf alle Bereiche der Anwendung.

In den meisten Anwendungen spielen jedoch Berechtigungen oder Rollen eine Rolle.

Benutzer: „Lass mich mit dieser Transaktion spielen …​.“
System der Bank: „Eine Sekunde, ich muss zuerst Ihre Berechtigungen überprüfen …​..Ja, Herr John Doe, Sie haben die richtige Freigabestufe. Viel Spaß.“
Benutzer: „Ich überweise 1 Mio. ha ha ha … Scherz, Scherz“

Servlet-Filter

Lassen Sie uns nun Servlet-Filter erkunden. In welcher Beziehung stehen sie zur Authentifizierung und Autorisierung?

Warum Servlet-Filter verwenden?
Jede Spring-Webanwendung dreht sich um ein einziges Servlet: das vertrauenswürdige DispatcherServlet. Seine Hauptaufgabe besteht darin, eingehende HTTP-Anfragen (z. B. von einem Browser) zur Verarbeitung an den entsprechenden @Controller oder @RestController weiterzuleiten.

Hier ist der Deal: Das DispatcherServlet selbst verfügt über keine integrierten Sicherheitsfunktionen, und Sie möchten wahrscheinlich keine rohen HTTP Basic Auth-Header direkt in Ihren @Controllern verarbeiten. Im Idealfall sollte die Authentifizierung und Autorisierung erledigt sein, bevor eine Anfrage überhaupt Ihre @Controller erreicht

Glücklicherweise können Sie dies in der Java-Webumgebung erreichen, indem Sie Filter vor Servlets platzieren. Dies bedeutet, dass Sie erwägen könnten, einen SecurityFilter zu erstellen und ihn in Ihrem Tomcat (Servlet-Container/Anwendungsserver) einzurichten, um jede eingehende HTTP-Anfrage abzufangen und zu verarbeiten, bevor sie Ihr Servlet erreicht.

Security context

Ein SecurityFilter hat ungefähr 4 Aufgaben

  1. Zuerst muss der Filter einen Benutzernamen/ein Passwort aus der Anfrage extrahieren. Dies kann über einen Basic Auth-HTTP-Header, Formularfelder, ein Cookie usw. erfolgen.
  2. Dann muss der Filter diese Kombination aus Benutzername und Passwort anhand einer Datenbank validieren.
  3. Der Filter muss nach erfolgreicher Authentifizierung prüfen, ob der Benutzer berechtigt ist, auf den angeforderten URI zuzugreifen.
  4. Wenn die Anfrage alle diese Prüfungen übersteht, kann der Filter l Und die Anfrage wird an Ihr DispatcherServlet weitergeleitet, d. h. an Ihre @Controller.

FilterChains

In der Praxis würden wir einen einzelnen Filter in mehrere aufteilen, die Sie dann miteinander verknüpfen würden.

So würde eine eingehende HTTP-Anfrage weitergeleitet werden:

  1. Zuerst durchläuft es einen LoginMethodFilter...
  2. Als nächstes durchläuft es einen AuthenticationFilter...
  3. Dann wird es zu einem AuthorizationFilter verschoben...
  4. Und schließlich erreicht es Ihr Servlet.

Dieses Setup wird als FilterChain bezeichnet.

Durch die Verwendung eines Filters (oder einer Filterkette) können Sie alle Authentifizierungs- und Autorisierungsherausforderungen in Ihrer Anwendung effektiv verwalten, ohne die Kernimplementierung Ihrer @RestControllers oder @Controllers zu ändern.

Springs DefaultSecurityFilterChain

Stellen Sie sich vor, Sie haben Spring Security richtig konfiguriert und Ihre Webanwendung gestartet. Sie werden eine Protokollmeldung bemerken, die so aussieht:

2020-02-25 10:24:27.875  INFO 11116 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@46320c9a, org.springframework.security.web.context.SecurityContextPersistenceFilter@4d98e41b, org.springframework.security.web.header.HeaderWriterFilter@52bd9a27, org.springframework.security.web.csrf.CsrfFilter@51c65a43, org.springframework.security.web.authentication.logout.LogoutFilter@124d26ba, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@61e86192, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@10980560, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@32256e68, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@52d0f583, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5696c927, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@5f025000, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5e7abaf7, org.springframework.security.web.session.SessionManagementFilter@681c0ae6, org.springframework.security.web.access.ExceptionTranslationFilter@15639d09, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@4f7be6c8]|
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Das Erweitern dieser einzelnen Zeile zeigt, dass Spring Security nicht nur einen Filter hinzufügt, sondern eine ganze Filterkette mit 15 (!) verschiedenen Filtern einrichtet.

Wenn eine HTTP-Anfrage eintrifft, durchläuft sie nacheinander jeden dieser 15 Filter, bevor sie schließlich Ihre @RestControllers erreicht. Die Reihenfolge dieser Filter ist entscheidend, da die Anfrage von oben nach unten in der Kette verarbeitet wird.

security chain

Analyse der FilterChain von Spring

Es würde zu weit führen, auf die Details jedes Filters in der Kette einzugehen, aber hier finden Sie Erklärungen für einige wichtige Filter. Für ein tieferes Verständnis der anderen können Sie den Quellcode von Spring Security erkunden.

  1. BasicAuthenticationFilter: Versucht, einen Basic Auth-HTTP-Header in der Anfrage zu finden, und versucht, wenn er gefunden wird, den Benutzer mit dem Benutzernamen und dem Passwort des Headers zu authentifizieren.
  2. UsernamePasswordAuthenticationFilter: Versucht, einen Benutzernamen/Passwort-Anforderungsparameter/POST-Text zu finden und, falls gefunden, versucht, den Benutzer mit diesen Werten zu authentifizieren.
  3. DefaultLoginPageGeneratingFilter: Erstellt eine Anmeldeseite für Sie, wenn Sie diese Funktion nicht explizit deaktivieren. DIESER Filter ist der Grund, warum Sie beim Aktivieren von Spring Security eine Standard-Anmeldeseite erhalten.
  4. DefaultLogoutPageGeneratingFilter: Erstellt eine Abmeldeseite für Sie, wenn Sie diese Funktion nicht explizit deaktivieren.
  5. FilterSecurityInterceptor: Erfüllt Ihre Autorisierung.

Witz

Frage - Warum brach die HTTP-Anfrage mit dem Spring Security-Filter zusammen?
Antwort - Denn jedes Mal, wenn es versuchte, näher zu kommen, sagte der Filter: „Warte! Lass mich dich zuerst überprüfen!“ ?

Ja Pause ........ Whoa, warte... das war viel zu viel Sicherheitsgerede für einen einzigen Versuch!

Richten Sie den Spring-Autorisierungsserver ein

Der einfachste Weg, mit der Verwendung von Spring Authorization Server zu beginnen, ist die Erstellung einer Spring Boot-basierten Anwendung. Sie können start.spring.io verwenden, um ein Basisprojekt zu generieren.

Die einzige erforderliche Abhängigkeit ist die Implementierung("org.springframework.boot:spring-boot-starter-oauth2-authorization-server")

Wir werden zwei weitere hinzufügen, um mehr Action zu machen

2020-02-25 10:24:27.875  INFO 11116 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@46320c9a, org.springframework.security.web.context.SecurityContextPersistenceFilter@4d98e41b, org.springframework.security.web.header.HeaderWriterFilter@52bd9a27, org.springframework.security.web.csrf.CsrfFilter@51c65a43, org.springframework.security.web.authentication.logout.LogoutFilter@124d26ba, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@61e86192, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@10980560, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@32256e68, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@52d0f583, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5696c927, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@5f025000, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5e7abaf7, org.springframework.security.web.session.SessionManagementFilter@681c0ae6, org.springframework.security.web.access.ExceptionTranslationFilter@15639d09, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@4f7be6c8]|
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

So konfigurieren Sie Spring Security

Mit den neuesten Spring Security- und/oder Spring Boot-Versionen können Sie Spring Security über eine Klasse konfigurieren, die: mit @EnableWebSecurity annotiert ist.

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-oauth2-authorization-server")
    implementation("org.springframework.boot:spring-boot-starter-webflux")
    implementation("org.springframework.boot:spring-boot-starter-validation")
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

(1) : Eine Spring Security-Filterkette für die Protokollendpunkte.
(2): Eine Spring Security-Filterkette zur Authentifizierung.
(3): Eine Instanz von com.nimbusds.jose.jwk.source.JWKSource zum Signieren von Zugriffstokens.
(4): Eine Instanz von JwtDecoder zum Dekodieren signierter Zugriffstoken.
(5): Eine Instanz von AuthorizationServerSettings zum Konfigurieren von Spring Authorization Server.

Lasst uns CORS so konfigurieren, dass bestimmte URLs zu unserer Anwendung zugelassen werden

2020-02-25 10:24:27.875  INFO 11116 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@46320c9a, org.springframework.security.web.context.SecurityContextPersistenceFilter@4d98e41b, org.springframework.security.web.header.HeaderWriterFilter@52bd9a27, org.springframework.security.web.csrf.CsrfFilter@51c65a43, org.springframework.security.web.authentication.logout.LogoutFilter@124d26ba, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@61e86192, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@10980560, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@32256e68, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@52d0f583, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5696c927, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@5f025000, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5e7abaf7, org.springframework.security.web.session.SessionManagementFilter@681c0ae6, org.springframework.security.web.access.ExceptionTranslationFilter@15639d09, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@4f7be6c8]|
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

CorsConfiguration
Diese Klasse wird zum Definieren der CORS-Regeln verwendet. In diesem Fall:

  • addAllowedOrigin("http://localhost:3000/"): Ermöglicht Anfragen von http://localhost:3000. Dies ist nützlich für die lokale Entwicklung, wenn Ihr Frontend auf einem anderen Port läuft. Ersetzen Sie dies in der Produktion durch Ihre tatsächlichen Domänen.
  • addAllowedMethod("*"): Ermöglicht alle HTTP-Methoden (z. B. GET, POST, PUT, DELETE usw.).
  • addAllowedHeader("*"): Erlaubt alle HTTP-Header in Anfragen.

UrlBasedCorsConfigurationSource

  • Eine Klasse, die URL-Muster (wie /**) bestimmten CORS-Konfigurationen zuordnet.
  • registerCorsConfiguration("/", Konfiguration): Wendet die definierten CORS-Regeln (Konfiguration) auf alle Endpunkte (/) in der Anwendung an.

Wow, das ist eine Menge Konfiguration! Aber das ist die Magie des Spring Frameworks – es übernimmt die ganze schwere Arbeit hinter den Kulissen.

Es ist Zeit, die Clients zu konfigurieren

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-oauth2-authorization-server")
    implementation("org.springframework.boot:spring-boot-starter-webflux")
    implementation("org.springframework.boot:spring-boot-starter-validation")
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Einige Dinge, die wir oben getan haben

  1. clientId: Eine eindeutige Kennung, um den Zugriff zu ermöglichen
  2. clientAuthenticationMethod: Definieren der Authentifizierungsmethode
  3. redirectUris Nur die definierten URLs zulassen
  4. authorizationGrantTypesauthorization_code

UserDetailsService

UserDetailsService wird von DaoAuthenticationProvider zum Abrufen eines Benutzernamens, eines Passworts und anderer Attribute für die Authentifizierung mit einem Benutzernamen und einem Passwort verwendet. Spring Security bietet In-Memory-, JDBC- und Caching-Implementierungen von UserDetailsService.

Sie können eine benutzerdefinierte Authentifizierung definieren, indem Sie einen benutzerdefinierten UserDetailsService als Bean verfügbar machen.

InMemoryUserDetailsManager

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    private static final String[] ALLOW_LIST = {"/oauth2/token", "/userinfo"};
    //This is primarily configured to handle OAuth2 and OpenID Connect specific endpoints. It sets up the security for the authorization server, handling token endpoints, client authentication, etc.
    @Bean (1)
    @Order(1)
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
        OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = OAuth2AuthorizationServerConfigurer.authorizationServer();
        http
                .cors(Customizer.withDefaults())
                .authorizeHttpRequests(authz -> authz
                        .requestMatchers(ALLOW_LIST).permitAll()
                        .requestMatchers("/**", "/oauth2/jwks/").hasAuthority("SCOPE_keys.write")
                        .anyRequest()
                        .authenticated())
                .securityMatchers(matchers ->
                        matchers.requestMatchers(antMatcher("/oauth2/**"), authorizationServerConfigurer.getEndpointsMatcher()))
                .with(authorizationServerConfigurer, (authorizationServer) ->
                        authorizationServer
                        .oidc(Customizer.withDefaults()))    // Enable OpenID Connect 1.0

                // Redirect to the login page when not authenticated from the
                // authorization endpoint
                .exceptionHandling((exceptions) -> exceptions
                        .defaultAuthenticationEntryPointFor(
                                new LoginUrlAuthenticationEntryPoint("/login"),
                                new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
                        ))
                // Accept access tokens for User Info and/or Client Registration
                .oauth2ResourceServer((oauth2) -> oauth2.jwt(Customizer.withDefaults()));
        return http.build();
    }

    // This configuration is set up for general application security, handling standard web security features like form login for paths not specifically managed by the OAuth2 configuration.
    @Bean (2)
    @Order(2)
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)
            throws Exception {
        http
                .authorizeHttpRequests((authorize) -> authorize
                        .requestMatchers("/login", "/error", "/main.css")
                        .permitAll()
                        .anyRequest()
                        .authenticated()
                )
                // Form login handles the redirect to the login page from the
                // authorization server filter chain
                .formLogin((login) -> login.loginPage("/login"));

        return http.build();
    }

    @Bean (3)
    public JWKSource<SecurityContext> jwkSource() {
        KeyPair keyPair = generateRsaKey();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        RSAKey rsaKey = new RSAKey.Builder(publicKey)
                .privateKey(privateKey)
                .keyID(UUID.randomUUID().toString())
                .build();
        JWKSet jwkSet = new JWKSet(rsaKey);
        return new ImmutableJWKSet<>(jwkSet);
    }

    private static KeyPair generateRsaKey() {
        KeyPair keyPair;
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(2048);
            keyPair = keyPairGenerator.generateKeyPair();
        } catch (Exception ex) {
            throw new IllegalStateException(ex);
        }
        return keyPair;
    }


    @Bean (4)
    public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
        return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
    }

    @Bean (5)
    public AuthorizationServerSettings authorizationServerSettings() {
        return AuthorizationServerSettings
                .builder()
                .build();
    }

}
Nach dem Login kopieren
Nach dem Login kopieren

Sobald wir die Anwendung starten, sollte unser OIDC- und OAuth2-Setup mit Spring Authorization Server ordnungsgemäß funktionieren. Sie werden jedoch feststellen, dass wir InMemoryUserDetailsManager verwendet haben, der sich gut für Demos oder Prototyping eignet. Für eine Produktionsumgebung ist dies jedoch nicht ratsam, da alle Daten beim Neustart der Anwendung verschwinden.

JdbcUserDetailsManager in Spring Security

JdbcUserDetailsManager ist eine Funktion in Spring Security, die JDBC verwendet, um Benutzeranmeldeinformationen und -rollen durch Herstellen einer Verbindung zu einer relationalen Datenbank zu verwalten. Ideal ist es, wenn Ihre Anwendung mit dem Standardschema für Benutzertabellen arbeiten kann, das Spring Security erwartet.

Das Schema, das unter Spring security org/springframework/security/core/userdetails/jdbc/users.ddl verfügbar ist

@Configuration
public class CorsConfig {

    @Bean
    public UrlBasedCorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.addAllowedOrigin("http://localhost:3000/"); // Change to specific domains in production
        configuration.addAllowedMethod("*");
        configuration.addAllowedHeader("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}
Nach dem Login kopieren
Nach dem Login kopieren

Die einzige Anpassung, die für den Übergang von InMemoryUserDetailsManager zu JdbcUserDetailsManager erforderlich ist

2020-02-25 10:24:27.875  INFO 11116 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@46320c9a, org.springframework.security.web.context.SecurityContextPersistenceFilter@4d98e41b, org.springframework.security.web.header.HeaderWriterFilter@52bd9a27, org.springframework.security.web.csrf.CsrfFilter@51c65a43, org.springframework.security.web.authentication.logout.LogoutFilter@124d26ba, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@61e86192, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@10980560, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@32256e68, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@52d0f583, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5696c927, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@5f025000, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5e7abaf7, org.springframework.security.web.session.SessionManagementFilter@681c0ae6, org.springframework.security.web.access.ExceptionTranslationFilter@15639d09, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@4f7be6c8]|
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Diese Konfiguration ist effektiv für Anwendungen, die sich an das Standardtabellenschema von Spring Security halten. Wenn Sie jedoch Anpassungen vornehmen müssen (z. B. die Verwendung einer E-Mail-Adresse anstelle eines Benutzernamens für die Anmeldung), bietet die Implementierung eines benutzerdefinierten UserDetailsService die erforderliche Anpassungsfähigkeit.

Benutzerdefinierter UserDetailsService mit einer Kundenentität

Fügen wir dem Anbieter einen benutzerdefinierten CustomUserDetailsService hinzu. Legen Sie im AuthenticationProvider den benutzerdefinierten Dienst mit setUserDetailsService
fest

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-oauth2-authorization-server")
    implementation("org.springframework.boot:spring-boot-starter-webflux")
    implementation("org.springframework.boot:spring-boot-starter-validation")
}
Nach dem Login kopieren
Nach dem Login kopieren
Nach dem Login kopieren

Kundenspezifischer Service

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    private static final String[] ALLOW_LIST = {"/oauth2/token", "/userinfo"};
    //This is primarily configured to handle OAuth2 and OpenID Connect specific endpoints. It sets up the security for the authorization server, handling token endpoints, client authentication, etc.
    @Bean (1)
    @Order(1)
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
        OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = OAuth2AuthorizationServerConfigurer.authorizationServer();
        http
                .cors(Customizer.withDefaults())
                .authorizeHttpRequests(authz -> authz
                        .requestMatchers(ALLOW_LIST).permitAll()
                        .requestMatchers("/**", "/oauth2/jwks/").hasAuthority("SCOPE_keys.write")
                        .anyRequest()
                        .authenticated())
                .securityMatchers(matchers ->
                        matchers.requestMatchers(antMatcher("/oauth2/**"), authorizationServerConfigurer.getEndpointsMatcher()))
                .with(authorizationServerConfigurer, (authorizationServer) ->
                        authorizationServer
                        .oidc(Customizer.withDefaults()))    // Enable OpenID Connect 1.0

                // Redirect to the login page when not authenticated from the
                // authorization endpoint
                .exceptionHandling((exceptions) -> exceptions
                        .defaultAuthenticationEntryPointFor(
                                new LoginUrlAuthenticationEntryPoint("/login"),
                                new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
                        ))
                // Accept access tokens for User Info and/or Client Registration
                .oauth2ResourceServer((oauth2) -> oauth2.jwt(Customizer.withDefaults()));
        return http.build();
    }

    // This configuration is set up for general application security, handling standard web security features like form login for paths not specifically managed by the OAuth2 configuration.
    @Bean (2)
    @Order(2)
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)
            throws Exception {
        http
                .authorizeHttpRequests((authorize) -> authorize
                        .requestMatchers("/login", "/error", "/main.css")
                        .permitAll()
                        .anyRequest()
                        .authenticated()
                )
                // Form login handles the redirect to the login page from the
                // authorization server filter chain
                .formLogin((login) -> login.loginPage("/login"));

        return http.build();
    }

    @Bean (3)
    public JWKSource<SecurityContext> jwkSource() {
        KeyPair keyPair = generateRsaKey();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        RSAKey rsaKey = new RSAKey.Builder(publicKey)
                .privateKey(privateKey)
                .keyID(UUID.randomUUID().toString())
                .build();
        JWKSet jwkSet = new JWKSet(rsaKey);
        return new ImmutableJWKSet<>(jwkSet);
    }

    private static KeyPair generateRsaKey() {
        KeyPair keyPair;
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(2048);
            keyPair = keyPairGenerator.generateKeyPair();
        } catch (Exception ex) {
            throw new IllegalStateException(ex);
        }
        return keyPair;
    }


    @Bean (4)
    public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
        return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
    }

    @Bean (5)
    public AuthorizationServerSettings authorizationServerSettings() {
        return AuthorizationServerSettings
                .builder()
                .build();
    }

}
Nach dem Login kopieren
Nach dem Login kopieren

Repository

@Configuration
public class CorsConfig {

    @Bean
    public UrlBasedCorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.addAllowedOrigin("http://localhost:3000/"); // Change to specific domains in production
        configuration.addAllowedMethod("*");
        configuration.addAllowedHeader("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}
Nach dem Login kopieren
Nach dem Login kopieren

Entität

@Configuration
public class Clients {
    @Bean
    public RegisteredClientRepository registeredClientRepository() {
        RegisteredClient oidcClient = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId("stomble")
                .clientAuthenticationMethod(ClientAuthenticationMethod.NONE)
                .authorizationGrantTypes(types -> {
                    types.add(AuthorizationGrantType.AUTHORIZATION_CODE);
                    types.add(AuthorizationGrantType.REFRESH_TOKEN);
                })
                .redirectUris(redirectUri -> {
                    redirectUri.add("http://localhost:3000");
                    redirectUri.add("https://oauth.pstmn.io/v1/callback");
                    redirectUri.add("http://localhost:3000/signin-callback");
                })
                .postLogoutRedirectUri("http://localhost:3000")
                .scopes(score -> {
                    score.add(OidcScopes.OPENID);
                    score.add(OidcScopes.PROFILE);
                    score.add(OidcScopes.EMAIL);
                })
                .clientSettings(ClientSettings.builder()
                        .requireAuthorizationConsent(false)
                        .requireProofKey(true)
                        .build())
                .build();
        return new InMemoryRegisteredClientRepository(oidcClient);
    }
}
Nach dem Login kopieren

Im Sicherheitsfilter müssen wir Spring Security anweisen, diesen Dienst zu nutzen

.clientAuthentication(clientAuth -> clientAuth.authenticationProvider(authenticationProvider))

@Configuration
public class UserConfig {

    @Bean
    public UserDetailsService userDetailsService(PasswordEncoder passwordEncoder) {
        UserDetails userDetailFirst = User.builder()
                .username("user1")
                .password(passwordEncoder.encode("password"))
                .roles("USER")
                .build();
        UserDetails userDetailSecond = User.builder()
                .username("user2")
                .password(passwordEncoder.encode("password"))
                .roles("USER")
                .build();
        return new InMemoryUserDetailsManager(List.of(userDetailFirst, userDetailSecond));
    }
}

@Bean
public PasswordEncoder passwordEncoder() {
   return new BCryptPasswordEncoder();
}
Nach dem Login kopieren

Abschluss

Hier haben Sie zwei robuste Möglichkeiten für die Handhabung der Authentifizierung:

  • JdbcUserDetailsManager: Eine unkomplizierte Option, wenn Ihre Anwendung mit dem Standardschema von Spring übereinstimmt.
  • Benutzerdefinierter UserDetailsService: Bietet die Flexibilität, spezielle Felder und Rollen zu verwalten.

Ganz gleich, ob Sie sich für JdbcUserDetailsManager entscheiden oder sich für die Implementierung eines benutzerdefinierten UserDetailsService entscheiden, beides stattet Ihre Anwendung mit einem skalierbaren, datenbankgestützten Authentifizierungssystem aus.

Das obige ist der detaillierte Inhalt vonSpring-Autorisierungsserver-Spring-Sicherheit mit benutzerdefiniertem Benutzerdetaildienst für flexible datengesteuerte Authentifizierung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:dev.to
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage