In diesem Artikel befassen wir uns mit der Sicherheit von Spring und erstellen ein Authentifizierungssystem mit OAuth 2.0.
Spring Security ist ein leistungsstarkes, hochgradig anpassbares Framework zur Implementierung robuster Authentifizierungs- und Zugriffskontrollmechanismen in Java-basierten Anwendungen. Es ist eine Kernkomponente des Spring-?kosystems und wird h?ufig zur Sicherung von Webanwendungen, REST-APIs und anderen Backend-Diensten verwendet. Mit Spring Security erhalten Sie eine solide Grundlage für den Aufbau und die Durchsetzung sicherer Praktiken in Ihrer Anwendung.
So funktioniert Spring Security
Bevor wir uns mit der Funktionsweise von Spring Security befassen, ist es wichtig, den Lebenszyklus der Anforderungsverarbeitung in einem Java-basierten Webserver zu verstehen. Spring Security l?sst sich nahtlos in diesen Lebenszyklus integrieren, um eingehende Anfragen zu schützen.
Lebenszyklus der Anforderungsbearbeitung mit Spring Security
Der Lebenszyklus der Bearbeitung einer HTTP-Anfrage in einer Spring-basierten Anwendung mit Spring Security umfasst mehrere Phasen, von denen jede eine entscheidende Rolle bei der Verarbeitung, Validierung und Sicherung der Anfrage spielt.
1. Kundenanfrage
Der Lebenszyklus beginnt, wenn ein Client (z. B. Browser, mobile App oder API-Tool wie Postman) eine HTTP-Anfrage an den Server sendet.
Beispiel:
GET /api/admin/dashboard HTTP/1.1
2. Servlet-Container
Der Servlet-Container (z. B. Tomcat) empf?ngt die Anfrage und delegiert sie an das DispatcherServlet, den Front-Controller in einer Spring-Anwendung. Hier beginnt die Verarbeitungspipeline der Anwendung.
3. Feder-Sicherheitsfilterkette
Bevor das DispatcherServlet die Anfrage verarbeitet, wird sie von der Filterkette von Spring Security abgefangen. Die Filterkette ist eine Folge von Filtern, von denen jeder für die Bearbeitung bestimmter Sicherheitsaufgaben verantwortlich ist. Diese Filter stellen sicher, dass die Anfrage die Authentifizierungs- und Autorisierungsanforderungen erfüllt, bevor sie die Anwendungslogik erreicht.
Schlüsselfilter in der Kette:
Authentifizierungsfilter:
Diese Filter überprüfen, ob die Anfrage gültige Anmeldeinformationen enth?lt, z. B. einen Benutzernamen/ein Passwort, ein JWT oder Sitzungscookies.Autorisierungsfilter:
Nach der Authentifizierung stellen diese Filter sicher, dass der authentifizierte Benutzer über die erforderlichen Rollen oder Berechtigungen verfügt, um auf die angeforderte Ressource zuzugreifen.Andere Filter:
* **CsrfFilter**: Validates CSRF tokens to prevent Cross-Site Request Forgery attacks. * **CorsFilter**: Manages Cross-Origin Resource Sharing (CORS) rules for secure API access from different domains. * **ExceptionTranslationFilter**: Handles security-related exceptions (e.g., invalid credentials) and sends appropriate responses to the client.
4. Sicherheitskontext
Wenn die Authentifizierung erfolgreich ist, erstellt Spring Security ein Authentifizierungsobjekt und speichert es im SecurityContext. Auf dieses Objekt, das h?ufig in einem Thread-lokalen Speicher gespeichert ist, kann w?hrend des gesamten Anforderungslebenszyklus zugegriffen werden.
Das Authentifizierungsobjekt:
Principal: Stellt den authentifizierten Benutzer dar (z. B. Benutzername).
Anmeldeinformationen: Enth?lt Authentifizierungsdetails wie JWT-Tokens oder Passw?rter.
Autorit?ten: Enth?lt dem Benutzer zugewiesene Rollen und Berechtigungen.
Beispielablauf in der Filterkette:
Eine Anfrage durchl?uft die Authentifizierungsfilter.
Wenn die Anmeldeinformationen gültig sind, wird das Authentifizierungsobjekt erstellt und dem SecurityContext hinzugefügt.
Wenn die Anmeldeinformationen ungültig sind, sendet der ExceptionTranslationFilter eine 401 Unauthorized-Antwort an den Client.
5. DispatcherServlet
Sobald die Anfrage die Spring Security Filter Chain erfolgreich durchlaufen hat, übernimmt das DispatcherServlet:
Handler-Zuordnung:
Es ordnet die eingehende Anfrage basierend auf der URL und der HTTP-Methode der entsprechenden Controller-Methode zu.Controller-Aufruf:
Der zugeordnete Controller verarbeitet die Anfrage und gibt die entsprechende Antwort zurück, h?ufig mit Hilfe anderer Spring-Komponenten wie Dienste und Repositorys.
Wie Spring Security in den Lebenszyklus passt
Spring Security integriert sich über seine Filter in diesen Lebenszyklus und f?ngt Anfragen im frühesten Stadium ab. Wenn eine Anfrage die Anwendungslogik erreicht, ist sie bereits authentifiziert und autorisiert, wodurch sichergestellt wird, dass nur legitimer Datenverkehr von der Kernanwendung verarbeitet wird.
Das Design von Spring Security stellt sicher, dass Authentifizierung, Autorisierung und andere Sicherheitsma?nahmen deklarativ gehandhabt werden, was Entwicklern die Flexibilit?t gibt, das Verhalten nach Bedarf anzupassen oder zu erweitern. Es setzt nicht nur Best Practices durch, sondern vereinfacht auch die Umsetzung komplexer Sicherheitsanforderungen in modernen Anwendungen.
Federsicherheitskomponenten: Jenseits der Filterkette
Nachdem wir die Filterkette in Spring Security untersucht haben, wollen wir uns mit einigen anderen Schlüsselkomponenten befassen, die eine entscheidende Rolle im Authentifizierungs- und Autorisierungsprozess spielen.
AuthenticationManager
AuthenticationManager ist eine Schnittstelle, die eine einzelne Methode definiert, Authenticate(Authentication Authentication) , die verwendet wird, um die Anmeldeinformationen eines Benutzers zu überprüfen und festzustellen, ob sie gültig sind. Sie k?nnen sich AuthenticationManager als einen Koordinator vorstellen, bei dem Sie mehrere Anbieter registrieren k?nnen und der je nach Anforderungstyp eine Authentifizierungsanfrage an den richtigen Anbieter übermittelt.
AuthenticationProvider
Ein AuthenticationProvider ist eine Schnittstelle, die einen Vertrag zur Authentifizierung von Benutzern basierend auf ihren Anmeldeinformationen definiert. Es stellt einen bestimmten Authentifizierungsmechanismus dar, z. B. Benutzername/Passwort, OAuth oder LDAP. Es k?nnen mehrere AuthenticationProvider-Implementierungen nebeneinander existieren, sodass die Anwendung verschiedene Authentifizierungsstrategien unterstützen kann.
Kernkonzepte:
Authentifizierungsobjekt:
Der AuthenticationProvider verarbeitet ein Authentication-Objekt, das die Anmeldeinformationen des Benutzers (z. B. Benutzername und Passwort) kapselt.Authentifizierungsmethode:
Jeder AuthenticationProvider implementiert die Methode ?authenticate“ (Authentifizierungsauthentifizierung), in der sich die eigentliche Authentifizierungslogik befindet. Diese Methode:
* **CsrfFilter**: Validates CSRF tokens to prevent Cross-Site Request Forgery attacks. * **CorsFilter**: Manages Cross-Origin Resource Sharing (CORS) rules for secure API access from different domains. * **ExceptionTranslationFilter**: Handles security-related exceptions (e.g., invalid credentials) and sends appropriate responses to the client.
- unterstützt die Methode: Die Methode ?supports(Class> Authentication)“ gibt an, ob der AuthenticationProvider den angegebenen Authentifizierungstyp verarbeiten kann. Dadurch kann Spring Security den richtigen Anbieter für die Bearbeitung bestimmter Authentifizierungsanfragen ermitteln.
Beispiel:
Ein datenbankgestützter AuthenticationProvider validiert Benutzernamen und Passw?rter.
Ein OAuth-basierter AuthenticationProvider validiert von einem externen Identit?tsanbieter ausgegebene Token.
UserDetailsService
UserDetailsService?wird in der Spring-Dokumentation als Kernschnittstelle beschrieben, die benutzerspezifische Daten l?dt. Es enth?lt eine einzelne Methode ?loadUserByUsername“, die den Benutzernamen als Parameter akzeptiert und das Identit?tsobjekt ==User== zurückgibt. Grunds?tzlich erstellen wir eine Implementierungsklasse von UserDetailsService, in der wir die Methode ?loadUserByUsername“ überschreiben.
* Validates the user’s credentials. * Returns an authenticated `Authentication` object upon success. * Throws an `AuthenticationException` if authentication fails.
Wie all diese drei nun zusammenwirken, ist, dass AuthenticationManager AuthenticationProvider auffordert, die Authentifizierung entsprechend dem angegebenen Anbietertyp fortzusetzen, und die UserDetailsService-Implementierung hilft dem AuthenticationProvider beim Nachweis der Benutzerdetails.
Bevor wir nun mit der Konfiguration und all dem fortfahren, finden Sie hier einen kurzen überblick über Spring Security für die JWT-basierte Authentifizierung:
1. Benutzeranfrage
Der Benutzer sendet eine Anfrage mit seinen Anmeldeinformationen (Benutzername und Passwort) oder einem JWT-Token (im Header) an den authentifizierten Endpunkt und die Anfrage wird an den Authentifizierungsfilter weitergeleitet
-
AuthenticationFilter (z. B. UsernamePasswordAuthenticationFilter):
- Verwaltet die Benutzerauthentifizierung basierend auf den übermittelten Anmeldeinformationen (normalerweise in Form eines Benutzernamens und eines Passworts). Hier kommt der UsernamePasswordAuthenticationFilter ins Spiel.
- Es wartet auf die Anfrage, extrahiert den Benutzernamen und das Passwort und übergibt sie an den AuthenticationManager.
- Aber wir geben nicht den Benutzernamen und das Passwort weiter, sondern nur das Token. Daher sollte vor diesem AuthenticationFilter ein Filter vorhanden sein, der dem Authentifizierungsprozess mitteilt, dass der Benutzer authentifiziert ist und keine überprüfung auf Benutzernamen und Passwort usw. erforderlich ist erfolgt durch die Erstellung eines JWTFilter
2. JWTFilter
Dieser benutzerdefinierte Filter erweitert OncePerRequestFilter und wird vor UsernamePasswordAuthenticationFilter platziert. Er extrahiert das Token aus der Anfrage und validiert es.
Wenn das Token gültig ist, erstellt es ein UsernamePasswordAuthenticationToken und setzt dieses Token in den Sicherheitskontext, der der Spring-Sicherheit mitteilt, dass die Anfrage authentifiziert ist, und wenn diese Anfrage an den UsernamePasswordAuthenticationFilter weitergeleitet wird, wird sie einfach weitergeleitet, da sie das UsernamePasswordAuthenticationToken hat
* **CsrfFilter**: Validates CSRF tokens to prevent Cross-Site Request Forgery attacks. * **CorsFilter**: Manages Cross-Origin Resource Sharing (CORS) rules for secure API access from different domains. * **ExceptionTranslationFilter**: Handles security-related exceptions (e.g., invalid credentials) and sends appropriate responses to the client.
Dieses UsernamePasswordAuthenticationToken wird mit Hilfe von AuthenticationManager und AuthenticationProvider generiert, wenn wir Benutzernamen und Passwort anstelle des Tokens übergeben haben, nachdem wir den Benutzernamen und das Passwort mit Hilfe unserer UserDetails-Klasse authentifiziert haben.
3. AuthenticationManager
- AuthenticationManager: Dieser empf?ngt die Authentifizierungsanforderung und delegiert sie an den entsprechenden AuthenticationProvider, den wir konfigurieren.
* Validates the user’s credentials. * Returns an authenticated `Authentication` object upon success. * Throws an `AuthenticationException` if authentication fails.
4. AuthenticationProvider
UserDetailsService: Der AuthenticationProvider verwendet UserDetailsService, um Benutzerdetails basierend auf dem Benutzernamen zu laden. Und wir stellen dies mit einer Implementierung von UserDetailsService
bereit
Anmeldeinformationsvalidierung: Es vergleicht das bereitgestellte Passwort mit dem in den Benutzerdetails gespeicherten (normalerweise mit einem PasswordEncoder).
package com.oauth.backend.services; import com.oauth.backend.entities.User; import com.oauth.backend.repositories.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Component; @Component public class CustomUserDetailsService implements UserDetailsService { private final UserRepository userRepository; public CustomUserDetailsService(UserRepository userRepository) { this.userRepository = userRepository; } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username); if(user==null){ throw new UsernameNotFoundException(username); } return new UserDetailsImpl(user); } public UserDetails loadUserByEmail(String email) throws UsernameNotFoundException { User user = userRepository.findByEmail(email); if(user==null){ throw new UsernameNotFoundException(email); } return new UserDetailsImpl(user); } }
Jetzt müssen all diese verschiedenen Filter und Beans konfiguriert werden, damit Spring Security wei?, was zu tun ist. Daher erstellen wir eine Konfigurationsklasse, in der wir die gesamte Konfiguration angeben.
@Component public class JWTFilter extends OncePerRequestFilter { private final JWTService jwtService; private final UserDetailsService userDetailsService; public JWTFilter(JWTService jwtService,UserDetailsService userDetailsService) { this.jwtService = jwtService; this.userDetailsService = userDetailsService; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { final String authHeader = request.getHeader("Authorization"); if(authHeader == null || !authHeader.startsWith("Bearer")) { filterChain.doFilter(request,response); return; } final String jwt = authHeader.substring(7); final String userName = jwtService.extractUserName(jwt); Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if(userName !=null && authentication == null) { //Authenticate UserDetails userDetails = userDetailsService.loadUserByUsername(userName); if(jwtService.isTokenValid(jwt,userDetails)) { UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities() ); SecurityContextHolder.getContext() .setAuthentication(authenticationToken); } } filterChain.doFilter(request,response); } }
Bis jetzt haben wir unsere Authentifizierung mit Hilfe von Spring Security verstanden und konfiguriert, jetzt ist es an der Zeit, sie zu testen.
Wir erstellen eine einfache App mit zwei Controllern: AuthController (verwaltet Anmeldung und Registrierung) und ProductController (geschützter Dummy-Controller)
* **CsrfFilter**: Validates CSRF tokens to prevent Cross-Site Request Forgery attacks. * **CorsFilter**: Manages Cross-Origin Resource Sharing (CORS) rules for secure API access from different domains. * **ExceptionTranslationFilter**: Handles security-related exceptions (e.g., invalid credentials) and sends appropriate responses to the client.
* Validates the user’s credentials. * Returns an authenticated `Authentication` object upon success. * Throws an `AuthenticationException` if authentication fails.
package com.oauth.backend.services; import com.oauth.backend.entities.User; import com.oauth.backend.repositories.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Component; @Component public class CustomUserDetailsService implements UserDetailsService { private final UserRepository userRepository; public CustomUserDetailsService(UserRepository userRepository) { this.userRepository = userRepository; } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username); if(user==null){ throw new UsernameNotFoundException(username); } return new UserDetailsImpl(user); } public UserDetails loadUserByEmail(String email) throws UsernameNotFoundException { User user = userRepository.findByEmail(email); if(user==null){ throw new UsernameNotFoundException(email); } return new UserDetailsImpl(user); } }
@Component public class JWTFilter extends OncePerRequestFilter { private final JWTService jwtService; private final UserDetailsService userDetailsService; public JWTFilter(JWTService jwtService,UserDetailsService userDetailsService) { this.jwtService = jwtService; this.userDetailsService = userDetailsService; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { final String authHeader = request.getHeader("Authorization"); if(authHeader == null || !authHeader.startsWith("Bearer")) { filterChain.doFilter(request,response); return; } final String jwt = authHeader.substring(7); final String userName = jwtService.extractUserName(jwt); Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if(userName !=null && authentication == null) { //Authenticate UserDetails userDetails = userDetailsService.loadUserByUsername(userName); if(jwtService.isTokenValid(jwt,userDetails)) { UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities() ); SecurityContextHolder.getContext() .setAuthentication(authenticationToken); } } filterChain.doFilter(request,response); } }
@Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception{ return config.getAuthenticationManager(); }
@Bean public AuthenticationProvider authenticationProvider(){ DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider(); authenticationProvider.setUserDetailsService(userDetailsServiceImpl); authenticationProvider.setPasswordEncoder(passwordEncoder); return authenticationProvider; }
Bisher haben wir eine Registrierung, Anmeldung und Verifizierung implementiert, aber was ist, wenn ich auch die Funktion ?Anmeldung mit Google/Github“ hinzufügen m?chte, dann k?nnen wir dies mit Hilfe von OAuth2.0 tun
OAuth 2.0
OAuth 2.0 ist ein Protokoll zur Autorisierung, mit dem Benutzer Anwendungen Dritter Zugriff auf Ressourcen gew?hren k?nnen, die auf anderen Plattformen (z. B. Google Drive, Github) gespeichert sind, ohne die Anmeldeinformationen dieser Plattformen weiterzugeben.
Es wird haupts?chlich zum Aktivieren sozialer Anmeldungen wie ?Mit Google anmelden“ oder ?Mit Github anmelden“ verwendet.
Plattformen wie Google, Facebook und Github bieten einen Autorisierungsserver, der das OAuth 2.0-Protokoll für diese soziale Anmeldung oder Autorisierung des Zugriffs implementiert.
Schlüsselkonzepte von OAuth 2.0
Ressourceneigentümer
Kunde
Autorisierungsserver
Ressourcenserver
Zugriffstoken
Bereiche
Zuschüsse
Jetzt werden wir uns jedes Konzept einzeln ansehen
Ressourceneigentümer
Ressourceneigentümer ist der Benutzer, der die Drittanbieteranwendung (Ihre Anwendung) autorisieren m?chte.
Kunde
Es ist Ihre (Drittanbieter-)Anwendung, die auf die Daten oder Ressourcen vom Ressourcenserver zugreifen m?chte.
Ressourcenserver
Es ist der Server, auf dem die Daten des Benutzers gespeichert werden und auf den die Drittanbieteranwendung zugreifen kann.
Autorisierungsserver
Der Server, der den Ressourcenbesitzer authentifiziert und Zugriffstokens an den Client ausgibt (z. B. Google-Konten).
Zugriffstoken
Ein vom Autorisierungsserver an den Client ausgestellter Berechtigungsnachweis, der es ihm erm?glicht, im Namen des Benutzers auf den Ressourcenserver zuzugreifen. Es ist im Allgemeinen nur von kurzer Dauer und l?uft sehr bald ab. Daher wird auch ein Aktualisierungstoken bereitgestellt, um dieses Zugriffstoken zu aktualisieren, sodass der Benutzer sich nicht erneut autorisieren muss.
Bereiche
Spezifische vom Benutzer gew?hrte Berechtigungen, die definieren, was der Client mit den Daten des Benutzers tun kann und was nicht. Für die Autorisierung ben?tigen wir beispielsweise nur Benutzerinformationen wie Profil, Name usw., für den Dateizugriff ist jedoch ein anderer Bereich erforderlich.
Zuschüsse
Es bezieht sich auf die Methoden, mit denen die Clientanwendung das Zugriffstoken vom Autorisierungsserver erhalten kann. Eine Gew?hrung definiert den Prozess und die Bedingungen, unter denen die Clientanwendung berechtigt ist, auf die geschützten Daten eines Ressourcenbesitzers zuzugreifen.
Es ist sicher, da wir unser Client-Geheimnis und andere Anmeldeinformationen nicht dem Browser preisgeben müssen
Es gibt zwei am h?ufigsten verwendete Grant-Typen, die von OAuth 2.0 bereitgestellt werden
-
Autorisierungscode-Gew?hrung
Es ist die am h?ufigsten verwendete Art der Gew?hrung/Methode, die sicherste und eignet sich für serverseitige Anwendungen
Dabei wird vom Client ein Autorisierungscode an das Backend übergeben und das Backend gibt dem Client das Zugriffstoken.
Prozess:
- Der Client leitet den Benutzer zum Autorisierungsserver weiter.
- Der Benutzer meldet sich an und stimmt zu.
- Der Autorisierungsserver gibt einen Autorisierungscode aus.
- Der Client tauscht den Autorisierungscode mit dem Backend gegen ein Zugriffstoken aus.
-
Implizite Gew?hrung
Wird von Single-Page-Apps (SPAs) oder Anwendungen ohne Backend verwendet. Dabei wird das Zugriffstoken direkt im Browser selbst generiert und ausgegeben.
Prozess:
- Der Client leitet den Benutzer zum Autorisierungsserver weiter.
- Der Benutzer meldet sich an und stimmt zu.
- Der Autorisierungsserver stellt direkt ein Zugriffstoken aus.
Wir werden beide zum vollst?ndigen Verst?ndnis separat implementieren, aber zuerst werden wir die Autorisierungscode-Gew?hrung implementieren, die wir dafür ben?tigen
-
Autorisierungsserver
Es kann eine Plattform sein (wie Google, Github) oder Sie k?nnen Ihre eigene erstellen, auch mit KeyCloak, oder Sie k?nnen auch Ihre eigene erstellen, die den OAuth 2.0-Standards entspricht (vielleicht machen wir das im n?chsten Blog?)
-
Spring Boot-Anwendung
Dies wird unsere wichtigste Backend-Anwendung/-Dienst sein, die alle Vorg?nge wie Codeaustausch, überprüfung, Speichern von Benutzerdetails und Zuweisen von JWT-Tokens abwickelt
-
React-Anwendung (Frontend)
Dies wird unser Client sein, der den Benutzer zur Autorisierung an den Autorisierungsserver weiterleitet.
In unserer Implementierung werden wir also Folgendes tun: Das Frontend (Web/App) leitet unseren Benutzer zum Google-Login mit einer Umleitungs-URI zu unserem Backend-Endpunkt weiter, der die Kontrolle weiter übernimmt. Darüber werden wir sp?ter und zusammen mit der Redirect_URL sprechen Wir übergeben auch die Client-ID unserer App. All diese werden in den Abfrageparametern gesendet.
Nein, wenn sich der Benutzer erfolgreich bei Google anmeldet, leitet der Autorisierungsserver (Google) unsere Anfrage an den Backend-Enpoint weiter und dort tauschen wir den Autorisierungscode mit dem Autorisierungsserver aus, um Zugriffstoken und Aktualisierungstoken zu erhalten, und dann Wir k?nnen die Authentifizierung nach Belieben durchführen und schlie?lich eine Antwort an unser Frontend zurücksenden, das ein Cookie enth?lt und zu unserem Dashboard weiterleitet oder m?glicherweise eine geschützte Seite ist.
Jetzt schauen wir uns den Code an, aber stellen Sie sicher, dass Sie die URL Ihres Backend-Endpunkts in den autorisierten Weiterleitungs-URLs im Google-Konsolen-Dashboard für den OAuth-Client hinzufügen.
* **CsrfFilter**: Validates CSRF tokens to prevent Cross-Site Request Forgery attacks. * **CorsFilter**: Manages Cross-Origin Resource Sharing (CORS) rules for secure API access from different domains. * **ExceptionTranslationFilter**: Handles security-related exceptions (e.g., invalid credentials) and sends appropriate responses to the client.
Und das ist alles, es wird gut funktionieren und zum Testen k?nnen Sie eine einfache Frontend-Anwendung erstellen, die nichts anderes bietet, als einen Kontext zu haben und Sie kennen die Anmelde- und Registrierungsfunktionen.
Vielen Dank, dass Sie bis hierhin gelesen haben. Wenn Sie einen Vorschlag haben, schreiben Sie ihn bitte in die Kommentare
Das obige ist der detaillierte Inhalt vonSpring Security und OAuth verstehen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Hei?e KI -Werkzeuge

Undress AI Tool
Ausziehbilder kostenlos

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Clothoff.io
KI-Kleiderentferner

Video Face Swap
Tauschen Sie Gesichter in jedem Video mühelos mit unserem v?llig kostenlosen KI-Gesichtstausch-Tool aus!

Hei?er Artikel

Hei?e Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Java unterstützt asynchrone Programmierungen, einschlie?lich der Verwendung von Vervollst?ndigungsfuture, reaktionsschnellen Streams (wie Projecreactor) und virtuellen Threads in Java19. 1.CompletableFuture verbessert die Code -Lesbarkeit und -wartung durch Kettenaufrufe und unterstützt Aufgabenorchestrierung und Ausnahmebehandlung. 2. Projecreactor bietet Mono- und Flusstypen zur Implementierung der reaktionsschnellen Programmierung mit Backpressure -Mechanismus und reichhaltigen Operatoren. 3.. Virtuelle Themen senken die Parallelit?tskosten, sind für E/O-intensive Aufgaben geeignet und sind leichter und leichter zu erweitern als herk?mmliche Plattformf?den. Jede Methode hat anwendbare Szenarien, und entsprechende Tools sollten entsprechend Ihren Anforderungen ausgew?hlt werden, und gemischte Modelle sollten vermieden werden, um die Einfachheit aufrechtzuerhalten

In Java eignen sich Enums für die Darstellung fester konstanter Sets. Zu den Best Practices geh?ren: 1. Enum verwenden, um festen Zustand oder Optionen zur Verbesserung der Sicherheit und der Lesbarkeit der Art darzustellen; 2. Fügen Sie ENUs Eigenschaften und Methoden hinzu, um die Flexibilit?t zu verbessern, z. B. Felder, Konstruktoren, Helfermethoden usw.; 3. Verwenden Sie ENUMMAP und Enumset, um die Leistung und die Typensicherheit zu verbessern, da sie basierend auf Arrays effizienter sind. 4. Vermeiden Sie den Missbrauch von Enums, wie z. B. dynamische Werte, h?ufige ?nderungen oder komplexe Logikszenarien, die durch andere Methoden ersetzt werden sollten. Die korrekte Verwendung von Enum kann die Codequalit?t verbessern und Fehler reduzieren. Sie müssen jedoch auf seine geltenden Grenzen achten.

Javanio ist ein neuer IOAPI, der von Java 1.4 eingeführt wurde. 1) richtet sich an Puffer und Kan?le, 2) enth?lt Puffer-, Kanal- und Selektorkomponenten, 3) unterstützt den nicht blockierenden Modus und 4) verhandelt gleichzeitiger Verbindungen effizienter als herk?mmliches IO. Die Vorteile spiegeln sich in: 1) Nicht blockierender IO reduziert den überkopf der Gewinde, 2) Puffer verbessert die Datenübertragungseffizienz, 3) Selektor realisiert Multiplexing und 4) Speicherzuordnungsgeschwindigkeit des Lesens und Schreibens von Dateien. Beachten Sie bei Verwendung: 1) Der Flip/Clear -Betrieb des Puffers ist leicht verwirrt zu sein, 2) unvollst?ndige Daten müssen manuell ohne Blockierung verarbeitet werden, 3) Die Registrierung der Selektor muss rechtzeitig storniert werden, 4) NIO ist nicht für alle Szenarien geeignet.

Der Klassenladermechanismus von Java wird über den Classloader implementiert und sein Kernworkflow ist in drei Stufen unterteilt: Laden, Verknüpfung und Initialisierung. W?hrend der Ladephase liest Classloader den Bytecode der Klasse dynamisch und erstellt Klassenobjekte. Zu den Links geh?ren die überprüfung der Richtigkeit der Klasse, die Zuweisung von Ged?chtnissen für statische Variablen und das Parsen von Symbolreferenzen; Die Initialisierung führt statische Codebl?cke und statische Variablenzuordnungen durch. Die Klassenbelastung übernimmt das übergeordnete Delegationsmodell und priorisiert den übergeordneten Klassenlader, um Klassen zu finden, und probieren Sie Bootstrap, Erweiterung und ApplicationClassloader. Entwickler k?nnen Klassenloader wie URLASSL anpassen

Der Schlüssel zur Behandlung von Java-Ausnahme besteht darin, zwischen überprüften und ungeprüften Ausnahmen zu unterscheiden und Try-Catch schlie?lich und angemessen zu verwenden. 1. überprüfte Ausnahmen wie IOException müssen gezwungen werden, um zu handhaben, was für erwartete externe Probleme geeignet ist. 2. Unkontrollierte Ausnahmen wie NullPointerexception werden normalerweise durch Programmlogikfehler verursacht und sind Laufzeitfehler. 3. Wenn Sie Ausnahmen erfassen, sollten sie spezifisch und klar sein, um die allgemeine Erfassung von Ausnahme zu vermeiden. 4.. Es wird empfohlen, Try-with-Resources zu verwenden, um die Ressourcen automatisch zu schlie?en, um die manuelle Reinigung des Codes zu verringern. 5. In der Ausnahmebehandlung sollten detaillierte Informationen in Kombination mit Protokoll -Frameworks aufgezeichnet werden, um sie sp?ter zu erleichtern

HashMap implementiert das Schlüsselwertpaarspeicher durch Hash-Tabellen in Java, und sein Kern liegt in schneller Positionierungsdatenorte. 1. Verwenden Sie zun?chst die HashCode () -Methode des Schlüssels, um einen Hash -Wert zu generieren und durch Bit -Operationen in einen Array -Index umzuwandeln. 2. Verschiedene Objekte k?nnen den gleichen Hash -Wert erzeugen, was zu Konflikten führt. Zu diesem Zeitpunkt ist der Knoten in Form einer verknüpften Liste montiert. Nach JDK8 ist die verknüpfte Liste zu lang (Standardl?nge 8) und wird in einen roten und schwarzen Baum umgewandelt, um die Effizienz zu verbessern. 3. Bei Verwendung einer benutzerdefinierten Klasse als Schlüssel müssen die Methoden Equals () und HashCode () umgeschrieben werden. 4.. Hashmap erweitert die Kapazit?t dynamisch. Wenn die Anzahl der Elemente die Kapazit?t und Multiplizierung mit dem Lastfaktor (Standard 0,75) überschreitet, erweitern und rehieren Sie sie. 5.

Polymorphismus ist eines der Kernmerkmale der java-objektorientierten Programmierung. Der Kern liegt in "One Interface, Mehrfachimplementierungen". Es implementiert eine einheitliche Schnittstelle, um das Verhalten verschiedener Objekte durch Vererbung, Umschreiben und Aufw?rtstransformation zu verarbeiten. 1. Polymorphismus erm?glicht es der übergeordneten Klasse, sich auf Subklassenobjekte zu beziehen, und die entsprechenden Methoden werden nach dem tats?chlichen Objekt w?hrend der Laufzeit aufgerufen. 2. Die Implementierung muss die drei Bedingungen der Erbschaftsbeziehung, der Umschreibung und der Aufw?rtstransformation erfüllen. 3. Es wird h?ufig verwendet, um verschiedene Subklassobjekte, ein Sammelspeicher und das Framework -Design gleichm??ig zu behandeln. 4. Bei Verwendung k?nnen nur die von der übergeordneten Klasse definierten Methoden aufgerufen werden. Neue Methoden zu Unterklassen müssen nach unten transformiert und zugegriffen werden und auf die Art der Type achten.

Java -Aufz?hlungen repr?sentieren nicht nur Konstanten, sondern k?nnen auch das Verhalten zusammenfassen, Daten tragen und Schnittstellen implementieren. 1. Aufz?hlung ist eine Klasse, mit der feste Instanzen wie Woche und Staat definiert werden, was sicherer ist als Saiten oder Ganzzahlen. 2. Es kann Daten und Methoden tragen, z. B. Werte über Konstruktoren übertragen und Zugriffsmethoden bereitstellen. 3.. Es kann Switch verwenden, um unterschiedliche Logik mit klarer Struktur zu verarbeiten. 4. Es kann Schnittstellen oder abstrakte Methoden implementieren, um differenzierte Verhaltensweisen verschiedener Aufz?hlungswerte vorzunehmen. 5. Achten Sie darauf, dass Missbrauch, Hartcode-Vergleich, Abh?ngigkeit von Ordnungswerten und ein vernünftiges Benennen und Serialisierung vermieden werden.
