Vor kurzem habe ich im Projekt auf ein Problem gestoßen: Das Front-End und das Back-End sind getrennt, das Front-End wird mit VUE durchgeführt, alle Datenanfragen verwenden Vue-Ressourcen, und es wird kein Formular verwendet, sodass die Dateninteraktion von JSON verwendet wird, der Hintergrund verwendet Sprungstiefel und die Überprüfung der Berechtigte verwendet die Sicherheit von Frühlingssicherheit. Da die Frühlingssicherheit zuvor verwendet wurde, verarbeiteten sie Seiten und verarbeiteten diesmal einfach AJAX -Anfragen, sodass sie einige Probleme aufzeichneten, denen sie begegneten. Die Lösung hier ist nicht nur für AJAX -Anfragen geeignet, sondern löst auch die Überprüfung der mobilen Anforderung.
Ein Projekt erstellen
Zunächst müssen wir ein Spring Boot -Projekt erstellen. Beim Erstellen müssen wir Web, Spring Security, MySQL und MyBatis vorstellen (das Datenbank -Framework ist tatsächlich willkürlich, ich verwende MyBatis hier). Nach der Erstellung lautet die Abhängigkeitsdatei wie folgt:
<Depopenty> <gruppe> org.mybatis.spring.boot </Groupid> <artifactId> MyBatis-String-Boot-Starter </artifactID> <version> 1.3.1 </Version> </abhängig> <ding <artifactid> Spring-Boot-Starter-Security </artifactId> </abhängig> <depecled> <GroupId> org.springFramework.boot </Groupid> <artifactid> Spring-Boot-Starter-Web </artifactid> </abhängig> </gruupid> mysql </artifactId> <artifactId> mysql-connector-java </artifactId> <Scope> Laufzeit </scope> </abhängig> <depeopcy> <gruppe> commons-codec </Groupid> <artifactID> Commons-codec </artifactId> <version> 1.11 </Version> </abhängig>
Beachten Sie, dass die letzte Commons-CODEC- Abhängigkeit von mir manuell hinzugefügt wurde. Dies ist ein Open -Source -Projekt von Apache, mit dem MD5 -Nachrichtenverdauungen generiert werden können. Ich werde das Passwort einfach im folgenden Text verarbeiten.
Erstellen Sie eine Datenbank und konfigurieren Sie sie
Um die Logik zu vereinfachen, habe ich hier drei Tabellen erstellt, nämlich die Benutzertabelle, die Rollentabelle und die Benutzerrolle -Assoziationstabelle wie folgt:
Als nächstes müssen wir eine einfache Konfiguration unserer Datenbank in application.Properties erstellen. Hier werden wir von Ihrer spezifischen Situation bestimmt.
spring.datasource.url = jdbc: mysql: ///vueblogsspring.datasource.username=rootspring.datasource.password=123
Konstrukt -Entitätsklasse konstruieren
Hier bezieht sich hauptsächlich auf den Bau von Benutzerklassen. Die Benutzerklassen hier sind ganz besonders und müssen wie folgt die Benutzerdetail -Schnittstelle implementieren:
Public Class User implementiert UserDetails {private long id; privater String -Benutzername; privates Zeichenfolgenkennwort; privater String -Spitzname; privat boolean aktiviert; Private List <Rolle> Rollen; @Override public boolean iscountnonexpired () {return true; } @Override public boolean isAccountnonLocked () {return true; } @Override public boolean is credentialsNonexpired () {return true; } @Override public boolean isenabled () {return aktiviert; } @Override öffentliche Liste <GrantedAuthority> getAuthorities () {list <GrantedAuthority> Autorities = New ArrayList <> (); für (Rollenrolle: Rollen) {Autorities.Add (new SimpleGrantedAuthority ("rollen_" + rollen.getName ())); } Rückkehrbehörden; } // Getter/Setter weglassen ...} Nach der Implementierung der Benutzerdetail -Schnittstelle gibt es in dieser Schnittstelle verschiedene Methoden, die wir implementieren müssen. Die vier Methoden, die Boolean zurückgeben, sind alle bekannt und bekannt. Aktiviert gibt an, ob das Periodenkonto aktiviert ist. Dieses Feld existiert in meiner Datenbank. Daher kehrt die anderen Abfrageergebnisse direkt für einfache Zeiträume zurück. Die GetAuthorities -Methode gibt die Rolleninformationen des aktuellen Benutzers zurück. Die Rolle des Benutzers sind tatsächlich die Daten in Rollen. Die Daten in den Rollen werden in die Liste <StrainedAuthority> konvertiert und dann zurückgegeben. Hier gibt es einen Punkt zu beachten. Da die Rollennamen, die ich in der Datenbank speichere, alle wie "Super Administrator", "gewöhnlicher Benutzer" usw. sind, und nicht mit Zeichen ROLE_ ROLE_ beginnen.
Es gibt auch eine Rollenentitätsklasse, die relativ einfach ist und gemäß den Feldern der Datenbank erstellt werden kann. Ich werde es hier nicht wiederholen.
UserService erstellen
Der UserService hier ist auch ganz Besonderem und es ist erforderlich, die BenutzerdetailsService -Schnittstelle wie folgt zu implementieren:
@ServicePublic Class UserService implementiert BenutzerdetailsService {@autowired UsMapper UsMapper; @Autowired Rollenmapper Rollenmapper; @Override public userDetails loadUserByUserName (String s) löst userernamenotFoundException aus {user usermaper.loadUserByUserName (s); if (user == null) {// Vermeiden Sie die Rückgabe von NULL, hier gibt hier ein Benutzerobjekt zurück, das keinen Wert enthält, und die Überprüfung fällt auch im späteren Kennwortvergleichsvorgang zurück, den neuen Benutzer () zurückgeben. } // Abfragen Sie die Rolle des Benutzers und kehren Sie zum Benutzer zurück. Liste <Rollen> rollen = rolesmapper.getrolesByUID (user.getId ()); user.setroles (Rollen); Benutzer zurückgeben; }}Nach der Implementierung der BenutzerdetailsService -Schnittstelle müssen wir die LOADUSERBYUSERNAME -Methode in der Schnittstelle implementieren, dh den Benutzer basierend auf dem Benutzernamen abfragen. Zwei Mapper in MyBatis werden hier injiziert, UsMapper wird verwendet, um Benutzer abzufragen, und Rollenmapper wird verwendet, um Rollen abzufragen. Fragen Sie in der LOADUSERBYUSERNAME -Methode zunächst den Benutzer gemäß den übergebenen Parametern ab (der Parameter ist der Benutzername, der beim Anmeldung des Benutzers eingegeben wird). Wenn der Benutzer NULL ist, können Sie eine Ausnahme von ustamenotFoundException direkt auswerfen. Für die Bequemlichkeit der Verarbeitung habe ich jedoch ein Benutzerobjekt ohne Wert zurückgegeben. Auf diese Weise werden während des nachfolgenden Kennwortvergleichsprozesses festgestellt, dass die Anmeldung fehlgeschlagen ist (hier können Sie ihn an Ihre Geschäftsanforderungen anpassen). Wenn der Benutzer nicht null ist, werden wir die Rolle des Benutzers basierend auf der Benutzer -ID abfragen und das Abfrageergebnis in das Benutzerobjekt einsetzen. Dieses Abfrageergebnis wird in der GetAuthorities -Methode des Benutzerobjekts verwendet.
Sicherheitskonfiguration
Schauen wir uns zuerst meine Sicherheitskonfiguration an, und dann werde ich sie nacheinander erklären:
@ConfigurationPublic Class WebSecurityConfig erweitert WebSecurityConFigurerAdapter {@autowired UserService UserService; @Override Protected void configure (AuthenticationManagerBuilder -Auth) löst Ausnahme aus {Auth.UserDetailsService (UserService) .PasswordEncoder (new PasswordEncoder () {@Override Public String code (charsequence charsequence) {return digestUtils.md5digestasEx (charsequence.toStoString (). @param charsequence plainText* @param s ciphERText* @return*/ @Override public boolean Matches (Charsequence Charsequence, String s) {return s.equals (Digestutils.md5Digestashex (charsequence.toString (). GetBytes ()); } @Override Protected void configure (httpsecurity http) löst Ausnahme aus {http.authorizeRequests () .AntMatchers ("/admin/**"). in.and().formLogin().loginPage("/login_page").successHandler(new AuthenticationSuccessHandler() { @Override public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {httpServletResponse.SetContType ("Anwendung/JSON; charset = utf-8"); .FailureHandler (neue AuthentifizierungFailureHandler () {@Override public void OnAuthenticationFailure (httpServletRequest httpServletRequest, httpServletResponse httpServletResponse, Authentifizierung EXCTION E) IOException, servletException, ServletException, ServletException, ServletException {{{{{{{{{{{{{ httpServletResponse.setContType ("Anwendung/JSON; Charset = UTF-8"); }). LoginProcessingurl ("/login") .usernameParameter ("Benutzername"). PasswordParameter ("Passwort"). Genug () .and (). Logout (). Genehmigungen (). und (). Csrf (). Disable (); } @Override public void configure (WebSecurity Web) löst eine Ausnahme aus {web.ignoring (). Anmatchers ("/reg"); }}Dies ist der Kern unserer Konfiguration. Bitte hören Sie mir zu:
1. Erstens ist dies eine Konfigurationsklasse. Denken Sie also daran, die @Configuration -Annotation hinzuzufügen. Da dies die Konfiguration der Spring Security ist, müssen Sie das WebSecurityConFigurerAdapter erben.
2. Injizieren Sie den gerade erstellten Userservice und wir werden es später verwenden.
3.Configure (AuthenticationManagerBuilder -Auth) wird verwendet, um unsere Authentifizierungsmethode zu konfigurieren und Userservice in der Auth.UserDetailsService () zu übergeben, sodass die LoadUserByusername -Methode im Userservice automatisch aufgerufen wird, wenn der Benutzer -Logs -Protokoll eingeschrieben ist. Das PlainText -Passwort ist auch erforderlich, um es beim Anmelden zu verarbeiten. Daher habe ich PasswordEncoder hinzugefügt, und nach dem Hinzufügen von PasswordEns kann ich eine anonyme interne interne Klasse von PasswordEncoder direkt neu neu machen. Hier sind zwei Methoden zu implementieren, und Sie können die Bedeutung der Methode kennen, indem Sie den Namen betrachten. Die erste Methode verschlüsselt offensichtlich den Klartext. Hier verwende ich den MD5 Message Digest. Die spezifische Implementierungsmethode wird durch die Abhängigkeit von Commons-CODEC bereitgestellt. Die zweite Methode übereinstimmt Kennwortvergleich, zwei Parameter, der erste Parameter ist das Klartextkennwort und der zweite Ciphertext. Hier müssen Sie nur den Klartext verschlüsseln und ihn mit dem Chiffretext vergleichen (wenn Sie daran interessiert sind, können Sie weiterhin das Hinzufügen von Salz zum Passwort hinzufügen).
4.Configure (httpecurity http) wird verwendet, um unsere Authentifizierungsregeln usw. zu konfigurieren usw. Die Methode der AutorizeSequests bedeutet, dass die Konfiguration der /admin/** aktiviert ist. Ich habe im Internet gesehen, dass meine Freunde Fragen dazu haben, ob ROLE_ in der HASROLE -Methode hinzugefügt werden soll. Fügen Sie es hier nicht hinzu. Wenn Sie die HasAuthority -Methode verwenden, müssen Sie sie hinzufügen. AnyRequest (). authenticated () bedeutet, dass alle anderen Pfade vor dem Zugriff authentifiziert/angemeldet werden müssen. Als nächstes haben wir die Anmeldeseite als login_page konfiguriert, der Anmeldungsverarbeitungspfad ist /login, der Anmeldebername ist ein Benutzername und das Kennwort ist Passwort. Wir haben diese Pfade so konfiguriert, dass sie direkt zugänglich sind, und melden Sie sich auch direkt auf die Anmeldung an und schließen schließlich auf CSRF. Verwenden Sie in SuccessHandler die Antwort, um den JSON zurückzugeben, der erfolgreich angemeldet ist. Denken Sie daran, defaultSuccessurl nicht zu verwenden. defaultSuccessurl ist eine Seite, die erst nach erfolgreichem Anmelden umgeleitet wird. Der gleiche Grund wird auch für Misserfolgshandler verwendet.
5. Ich habe einige Filterregeln in der Methode der Konfiguration (WebSecurity Web) konfiguriert, sodass ich nicht in Details eingehe.
6. Zusätzlich wird für statische Dateien wie /images/** , /css/** und /js/** die Standardeinstellung nicht abgefangen.
Regler
Schauen wir uns schließlich wie folgt auf unseren Controller an:
@RestControllerPublic Class LoginRegcontroller {/** * Wenn Sie automatisch zu dieser Seite springen, bedeutet dies, dass der Benutzer nicht angemeldet ist und die entsprechende Eingabeaufforderung * <p> * zurückgeben kann. Wenn Sie die Form von Formular -Anmeldung unterstützen, können Sie die Art der Anfrage in dieser Methode beurteilen. RespBean loginpage () {return new respBean ("Fehler", "Noch nicht angemeldet, bitte melden Sie sich an!"); }} Insgesamt ist dieser Controller relativ einfach. RespBean gibt einen einfachen JSON zurück, der nicht detailliert ist. Was Sie hier achten müssen, ist login_page . Die von uns konfigurierte Anmeldeseite ist eine login_page . Tatsächlich ist login_page jedoch keine Seite, sondern ein JSON. Dies liegt daran, dass die Spring Security, wenn ich andere Seiten ohne Anmeldung besuche, automatisch zur Seite login_page springt. In der Ajax -Anfrage ist diese Art von Sprung jedoch nicht erforderlich. Alles was ich möchte, ist eine Aufforderung, sich anzumelden oder nicht, damit ich JSON hier zurückgeben kann.
prüfen
Schließlich können Freunde Tools wie Postman oder RESTClient verwenden, um Login- und Berechtigungsprobleme zu testen, sodass ich es nicht demonstrieren werde.
OK, nach der obigen Einführung glaube ich, dass Freunde Spring Boot+Spring Security bereits verstanden haben. Okay, das ist alles für diesen Artikel. Wenn Sie Fragen haben, überlassen Sie bitte eine Nachricht, um zu diskutieren.