Überblick
Wie wir alle wissen, verwenden Sie JWT zur Erlaubnisüberprüfung. Im Vergleich zur Sitzung besteht der Vorteil der Sitzung darin, dass die Sitzung eine große Menge an Serverspeicher erfordert. Wenn mehrere Server verwendet werden, werden problematische Sitzungsprobleme auf gemeinsame Sitzung beinhalten, was beim Zugriff auf mobile Terminals wie Mobiltelefone mehr ist.
JWT muss nicht auf dem Server gespeichert werden und belegen keine Serverressourcen (dh staatenlos). Nachdem sich der Benutzer angemeldet hat, fügt er beim Zugriff auf die Anforderung, die die Berechtigung erfordert (normalerweise im HTTP -Anforderungsheader festgelegt) an, an das Token hinzu. JWT hat nicht das Problem, mehrere Server zu teilen, und es hat auch keine mobilen Zugriffsprobleme auf Mobiltelefonen. Um die Sicherheit zu verbessern, kann das Token an die IP -Adresse des Benutzers gebunden werden
Front-End-Prozess
Der Benutzer hat sich über Ajax angemeldet, um ein Token zu bekommen
Danach muss beim Zugriff eine Erlaubnis ein Token an den Zugriff anfügen.
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script> <script type="application/javascript"> var header = ""; Funktion login () {$ .post ("http: // localhost: 8080/auth/login", {Benutzername: $ ("#userername"). Val (), Passwort: $ ("#password"). Val ()}, Funktion (Data) {console.log ($ data). "Get", URL: "http: // localhost: 8080/userpage", beforeSend: function (request) {request.setRequestheader ("Autorisierung", Header); } </script> </head> <body> <Fieldset> <Legend> Bitte login </legend> <label> Benutzername </Label> <Eingabe type = "text" id = "userername"> <label> Passwort </label> <input type = "text" id = "kennwort"> <Eingabe type = "buttht =" button = "login ()" value = ". id = "TouserpageBtn" Onclick = "TouserpageBtn ()"> Zugriff auf Benutzerpage </button> </body> </html>Backend -Prozess (Spring Boot + Spring Security + JJWT)
Ideen:
Schreiben Sie eine Benutzerentitätsklasse und fügen Sie ein Datenstück ein
Benutzer (Benutzer) Entitätsklasse
@Data @EntityPublic Class User {@id @generatedValue private int id; privater Zeichenfolge Name; privates Zeichenfolgenkennwort; @ManyToMany(cascade = {CascadeType.REFRESH}, fetch = FetchType.EAGER) @JoinTable(name = "user_role", joinColumns = {@JoinColumn(name = "uid", referencedColumnName = "id")}, inverseJoinColumns = {@JoinColumn(name = "rid", ReferenzColumnName = "id")}) private Liste <Rollen> Rollen;} Rolle (Erlaubnis) Entitätsklasse
@Data @EntityPublic Class Rolle {@ID @generatedValue private int id; privater Zeichenfolge Name; @Manytomany (mappedby = "rollen") private list <Benutzer> Benutzer;} Daten einfügen
Benutzertabelle
| Ausweis | Name | Passwort |
|---|---|---|
| 1 | Linyuan | 123 |
Rollentabelle
| Ausweis | Name |
|---|---|
| 1 | BENUTZER |
User_role table
| uid | loswerden |
|---|---|
| 1 | 1 |
DAO -Schichtschnittstelle, erhält Daten über den Benutzernamen und gibt ein optionales Objekt mit einem Wert von Java8 zurück
öffentliche Schnittstelle userRepository erweitert Repository <Benutzer, Integer> {Optional <Benutzer> findByName (String -Name);} Schreiben Sie Logindto für die Datenübertragung mit dem Frontend
@Datapublic class logindto implementiert serialisierbare {@notblank (message = "Der Benutzername kann nicht leer sein") privater String -Benutzername; @Notblank (Message = "Das Kennwort kann nicht leer sein") privates Zeichenfolgenkennwort;} Schreiben Sie ein Token -Tool -Tool und erstellen Sie es mit der JJWT -Bibliothek. Insgesamt gibt es drei Methoden: Generieren Sie ein Token (eine Zeichenfolge zurück), analysieren Sie das Token (senden Sie ein Authentifizierungs -Authentifizierungsobjekt) und überprüfen Sie das Token (senden Sie einen Booleschen Wert zurück)
@ComponentPublic Class JwtTokenUtils {private final logger log = loggerfactory.getLogger (jwtTokenutils.class); private statische endgültige String -Behörden_key = "Auth"; private String SecretKey; // Key Private Long TokenvalicityInmilliseconds für private Länge unterzeichnen; // Ablaufdatum private lange Tokenvaliditätsinmillisekondsforrememberme; // (erinnere mich an mich) Ablaufdatum @postconstruct public void init () {this.secretkey = "linyuanmima"; int Secondin1day = 1000 * 60 * 60 * 24; this.tokenValicityInmilliseconds = Secondin1day * 2L; this.tokenValicityInmillisecondsforrememberme = Secondin1day * 7L; } private endgültige statische Langzeitablaufzeit = 432_000_000; // Token public String createToken erstellen (Authentifizierungsauthentifizierung, boolean remmMe) {String Authentifizierungen = Authentifizierung.getAuthorities (). long jetzt = (neues Datum ()). GetTime (); // Erhalten Sie die aktuelle Gültigkeit des Zeitstempels; // Ablaufzeit der Speicherung von (rememberMe) {validity = neues Datum (jetzt + this.tokenValicityInmilliseconds); } else {validity = new Datum (jetzt + this.tokenValicityInmillisecondsforrememberMe); } return jwts.builder () // token token.setsubject (authentication.getName ()) // Benutzer-oriented.claim (Autorities_key, Behörden) setze // Berechtigungsattribute hinzufügen.setExpiration (Gültigkeit) // Ungültigkeitszeit festlegen. } // Benutzerberechtigungen öffentliche Authentifizierung getAuthentication (String Token) {System.out.println ("Token:"+Token); Ansprüche Ansprüche = jwts.parser () // tokens nutzlast. Sammlung <? erweitert GrantedAuthority> Autorities = arrays.stream (caells.get (Authorities_key) .ToString (). Split (",") // Benutzerberechtigte String.MAP (SimpleGrantedAuthority :: New) .Collect (Collectors.tolist ()); // Elemente in die gewährte Authority Interface Collection user Principal = New User (caells.getSubject (), "", Behörden) konvertieren; Neue usernamepasswordAuthenticationToken zurückgeben (Schulleiter, ", Behörden); } // Überprüfen Sie, ob das Token das korrekte public boolean validatEtoken (String Token) {try {jwts.parser (). // Token nach Schlüsselrückgabe true prüfen; } catch (SignatureException e) {// Signature -Ausnahmeprotokoll.info ("Ungültige JWT -Signatur."); log.trace ("Ungültige JWT -Signaturverfolgung: {}", e); } catch (malmaleformEdjwTexception e) {// JWT -Format -Fehler log.info ("Ungültiges JWT -Token."); log.trace ("Ungültiges JWT -Token Trace: {}", e); } catch (abgelaufenJwTexception e) {// jwt abgelaufen log.info ("abgelaufenes JWT -Token"); log.trace ("abgelaufener JWT -Token Trace: {}", e); } catch (unportedjwTexception e) {// das jwt log.info ("nicht unterstütztes JWT -Token"); log.trace ("nicht unterstütztes JWT -Token Trace: {}", e); } catch (illegalArgumentException e) {// Das Parameterfehler -Ausnahme -log.info ("JWT Token Compact of Handler sind ungültig."); log.trace ("JWT Token Compact of Handler sind ungültige Trace: {}", e); } return false; }} Implementieren Sie die Benutzerdetail -Schnittstelle, die die Benutzerentitätsklasse darstellt, in unserem Benutzerobjekt umwickelt, enthält Berechtigungen und andere Eigenschaften und kann von Spring Security verwendet werden
öffentliche Klasse MyUSerDetails implementiert Benutzerdetails {privater Benutzer; public myUserDetails (Benutzer Benutzer) {this.user = user; } @Override Public Collection <? erweitert GrantedAuthority> getAuthorities () {list <rolle> rollen = user.getRoles (); Liste <StrainedAuthority> Autorities = New ArrayList <> (); StringBuilder sb = new StringBuilder (); if (roles.size ()> = 1) {für (rollenrolle: rollen) {Authorities.Add (new SimpleGrantedAuthority (rollenname ()); } Rückkehrbehörden; } Rückkehrbehörden; } return Authorityutils.CommaseParatedStringtoAuthorityList (""); } @Override public String getPassword () {return user.getPassword (); } @Override public String getUnername () {return user.getName (); } @Override public boolean isAccountNonexpired () {return true; } @Override public boolean isAccountnonLocked () {return true; } @Override public boolean is credentialsNonexpired () {return true; } @Override public boolean isenabled () {return true; }} Implementieren Sie die Benutzerdiener -Benutzeroberfläche, die nur eine Methode zum Abrufen von Benutzerdetails enthält. Wir können das Benutzerobjekt aus der Datenbank abrufen, es dann in Benutzerdetails einwickeln und zurückgeben
@ServicePublic Class MyUSerDetailsService implementiert UserDetailsService {@autowired userRepository userRepository; @Override public userDetails loadUserByUserName (String s) löst userernamenotFoundException {// Benutzerobjekt aus der Datenbank optional <user> user = userrepository.findByName (s) aus. // Für das Debuggen wird der Benutzername und das Kennwort ausgegeben, wenn der Wert vorhanden ist. IfPresent ((Wert)-> System.out.println ("Benutzername:"+value.getName ()+"Benutzerkennwort:"+value.getPassword ()); // Wenn der Wert nicht mehr ist, senden Sie NULL NULL zurück. RECHTEN SIE NEUE MYUSERDETAILS (user.orelse (null)); }} Schreiben Sie einen Filter. Wenn der Benutzer das Token trägt, erhält er das Token und generiert ein Authentifizierungsauthentifizierungsobjekt basierend auf dem Token und speichert es im SecurityContext, um die Berechtigungssteuerung durch Spring Security zu erhalten.
public class jwtauthenticationTokenFilter erweitert genericFilterbean {private endgültige logger log = loggerfactory.getLogger (jwtthenticationTokenFilter.class); @Autowired Private JwtTokenutils TokenProvider; @Override public void dofilter (servletRequest servletRequest, servletResponse servletresponse, filterchain filterchain) löst ioException, servletException {system.out.println ("jwtauthenticationTokenfilter") aus; try {httpServletRequest httpreq = (httpServletRequest) servletRequest; String jwt = ResolvEToken (httpreq); if (stringutils.hastext (jwt) && this.tokenProvider.validatEToken (jwt)) {// Überprüfen Sie, ob die JWT korrekte Authentifizierung Authentifizierung = this.tokenProvider.GetAuthentication (jwt) ist; // Benutzerauthentifizierung Information SecurityContextHolder.getContext (). SetAuthentication (Authentifizierung); // den Benutzer auf SecurityContext speichern} filterchain.dofilter (ServletRequest, ServletResponse); } catch (abgelaufenJwTexception e) {// jwt ungültiges log.info ("Sicherheitsausnahme für Benutzer {} - {}", e.getClaims (). getUbject (), e.getMessage ()); log.trace ("Sicherheitsausnahmeverfolgung: {}", e); ((HttpServletResponse) servletResponse) .setStatus (httpServletResponse.sc_unauthorized); }} private String resolvetoken (httpServletRequest -Anforderung) {String BearerToken = Request.Getheader (WebSecurityConfig.Authorization_Header); // Token aus dem http -Header if (Stringutils.hastext (BearerToken) && BearerToken.StartsWith ("Bearer")) {return BearerToken.substring (7, BearerToken.Length ()); // Die Token -Zeichenfolge zurückgeben und Bearer} String jwt = Request.getParameter (WebSecurityConfig.Authorization_Token) entfernen; // Token aus den Anforderungsparametern ab (stringutils.hastext (jwt)) {return jwt; } return null; }} Schreiben Sie einen Logincontroller. Der Benutzer zugreift /auth /meldet sich über den Benutzernamen und das Kennwort an, empfängt ihn über das Logindto -Objekt und erstellt ein Authentifizierungsobjekt. Der Code ist usernamePasswordAuthenticationToken, um festzustellen, ob das Objekt existiert. Überprüfen Sie das Authentifizierungsobjekt über die Authentifizierungsmethode des AuthenticationManagers. Die AuthenticationManager -Implementierungsklasse ProviderManager überprüft über die Authentifizierungsprovider (Authentifizierungsverarbeitung). Der Standard -Providermanager ruft DaoAuthenticationProvider zur Authentifizierungsverarbeitung auf. Der DaoAuthenticationProvider erhält Benutzerdetails über UserdetailsService (Authentifizierungsinformationsquelle). Wenn die Authentifizierung erfolgreich ist, wird eine Authention, die Berechtigungen enthält, zurückgegeben und dann auf die SecurityContext durch SecurityContexTHolder.getContext ().
@RestControllerPublic Class Logincontroller {@autowired private userRepository userrepository; @Autowired Private AuthenticationManager AuthenticationManager; @Autowired Private JwtTokenutils jwttokenutils; @RequestMapping (value = "/auth/login", method = requestMethod.post) public string login (@valid logindto logindto, httpServletResponse httPresponse) löst Ausnahme aus {// eine Authentifizierungsauthentifizierung erstellen. = new usernamePasswordAuthenticationToken (logindto.getUnername (), logindto.getPassword ()); // Wenn das Authentifizierungsobjekt nicht leer ist, wenn (Objects.nonnull (AuthenticationToken)) {userrepository.findByName (AuthenticationToken.getPrincipal (). ToString ()) .Orelsethrow (()-> Neue Ausnahme ("Benutzer existiert nicht")); } try {// Überprüfen Sie das Authentifizierungsobjekt über den AuthenticationManager (Standard als Providermanager) Authentifizierung = AuthenticationManager.Authenticate (AuthenticationToken); // Authentifizierung an SecurityContext SecurityContextHolder.getContext (). SetAuthentication (Authentifizierung); // token String token = jwttokenutils.createToken (Authentifizierung, Falsch); // Schreiben Sie das Token in den HTTP -Header httPesponse.addHeader (WebSecurityConfig.Authorization_Header, "Bearer"+Token); Rückkehr "Träger"+Token; } catch (badcredentialSexception -Authentifizierung) {neue Ausnahme ("Passwortfehler"); }}} Schreiben Sie die Sicherheitskonfigurationsklasse, erben Sie die WebSecurityConFigurerAdapter und überschreiben Sie die Konfigurationsmethode
@Configuration@enableWebecurity@enableGlobalMethodSecurity (prepostEnabled = true) öffentliche Klasse WebSecurityConfig erweitert WebSecurityConFigurerAdapter {public static Final String Authorization_Header = "Autorisierung"; public static Final String Authorization_Token = "access_token"; @Autowired Private UserDetailsService UserDetailsService; @Override Protected void configure (AuthenticationManagerBuilder Auth) löst Ausnahme aus {auth // anpassen, um Benutzerinformationen zu erhalten. } @Override Protected void configure (httpecurity http) löst Ausnahme aus {// Anforderungszugriffspolitik http // CSRF und CORS .Cors (). Deaktivieren () .csrf (). Deaktiviert () // Sekession ist nicht erforderlich, da die SessionPoly -SessionPoly -SessionPoly (Sessions -Sessions). .And () // Http request.AuthorizeRequests () // allen Benutzern erlauben, auf die Homepage zuzugreifen und sich anzumelden. .and () // logout (). erlaubtenAll (); // JWT -Filter unter http .addFilterBefore (genericFilterbean (), usernamepasswordAuthenticationFilter.class) hinzufügen; } @Bean public passwordEnCoder passwordEnCoder () {Neue bcryptPasswordEnCoder () zurückgeben; } @Bean public GenericFilterbean GenericFilterbean GenericFilterbean () {return New JwtauthenticationTokenFilter (); }} Schreiben Sie einen Controller zum Testen
@RestControllerPublic Class UserController {@postmapping ("/login") public String login () {return "login"; } @GetMapping ("/") public String index () {return "hello"; } @Getmapping ("/userPage") public String httpapi () {System.out.println (SecurityContextHolder.getContext (). GetAuthentication (). GetPrincipal ()); Rückgabe "UserPage"; } @GetMapping ("/adminPage") public String httpsuite () {return "userPage"; }}Case Source Code Download (lokaler Download)
Zusammenfassen
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass der Inhalt dieses Artikels einen gewissen Referenzwert für das Studium oder die Arbeit eines jeden hat. Wenn Sie Fragen haben, können Sie eine Nachricht zur Kommunikation überlassen. Vielen Dank für Ihre Unterstützung bei Wulin.com.