In diesem Artikel wird die Methode des Frühlingsboots in Kombination mit Shrio eingeführt, um JWT zu implementieren, und teilt sie wie folgt mit Ihnen mit:
In Bezug auf die Überprüfung gibt es ungefähr zwei Aspekte:
Hauptlösung: Verwenden Sie einen benutzerdefinierten Shiro -Filter
Projektkonstruktion:
Dies ist ein Spring-Boot-Webprojekt. Wenn Sie nichts über das Spring-Boot-Projektkonstruktion wissen, bitte Google.
Pom.mx führt verwandte Glaspakete ein
<!-- shiro permission management--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version> $ {shiro.version} </Version> </abhängig> <!-jwt-> <abhängigkeit> <gruppe> io.jsonWebtoken </Groupid> <artifactid> jjwt </artifactid> <version> 0.9.0 </Version> </abhängig> </abhängig> </abhängig> Shrio -bezogene Konfiguration
Auf den Punkt bringen! ! Angepasst einen Filter
filtermap.put ("jwtfilter", new jwtfilter ()); @ConfigurationPublic Class Shiroconfig {@Bean public shirofilterFactoryBean getShiroFilterFactoryBean (SecurityManager SecurityManager) {shirofilterFactoryBean shirofilterFactoryBean = New ShiroFilterFactoryBean (); shirofilterFactoryBean.SetSecurityManager (SecurityManager); // Fügen Sie Ihren eigenen Filter hinzu und nennen Sie es jwtfilter map <string, filter> filterterap = new Hashmap <> (); filtermap.put ("jwtfilter", new jwtfilter ()); shirofilterFactoryBean.SetFilters (Filterterap); / * * Benutzerdefinierte URL-Regeln * http://shiro.apache.org/web.html#urls- */map <String, String> filterchaindeFinitionmap = shirofilterFactoryBean.getFilterchaNdeFinitionMap (); filterchainedefinitionmap.put ("/**", "jwtfilter"); shirofilterFactoryBean.SetFilterChaindeFinitionMap (filterchainedefinitionMap); Return ShirofilterFactoryBean; }/** * SecurityManager muss Shirodbrealm nicht direkt injizieren, was zu Transaktionsfehlern * für die Lösung führen kann, siehe HandlecontexTrefresh * http://www.debugrun.com/a/nks9ejq.html */@Bean ("SecurityManitrealm) öffentlich")). {DefaultWebSecurityManager Manager = new DefaultWebSecurityManager (); Manager.SetRealm (Tokenrealm); / * * Schließen Sie die mit Shiro gelieferte Sitzung. Weitere Informationen finden Sie in der Dokumentation. DefaultSessionStorageValuator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator (); DefaultSessionStorageEvaluator.SetSessionStorageEnabled (false); Subjektdao.SetSessionStorageEvaluator (DefaultSessionStorageValuator); Manager.SetsubjectDao (Subjektdao); Rückkehrmanager; } @Bean public LifecycleBeanPostProcessor LifecycleBeanPostProcessor () {Return New LifecycleBeanPostProcessor (); } @Bean (name = "tokenrealm") @Dependson ("LifeCycleBeanPostProcessor") public tokenrealm tokenrealm () {return New Tokenrealm (); } @Bean @Dependson ("LifeCycleBeanPostProcessor") public defaultAdvroutoproxyCreator defaultAdvisorautoproxycreator () {DefaultAdSorautoproxyCreator DefaultAdvisorAutoproxycreatur = New DefaultAdSoraUtorAutorauToraToraToraToraToraToraToraToraToraToraToraUtoraToraToraToraUtoraToraToraUtoraToraToraToraToraToraToraToraToraToraToraTor (); // CGLIB zwingen, doppelte Proxy und mögliche Proxy -Fehler zu verhindern // https://zhuanlan.zhihu.com/p/29161098 defaultAdvisorautoproxycreator.setproxytargetClass (True); Return defaultAdvisorautoproxyCreator; } @Bean Public AuthorizationAttributesourceAvvisor getAuthorizationAttributesourceadvisor (SecurityManager SecurityManager) {AuthorizationAttributesourceadvisor AuthorizationAttributesourceadvisor = new AuthorizationAttributesourceadvisor (); AuthorizationAttributesourceadvisor.SetSecurityManager (SecurityManager); Rückgabe neuer AuthorizationAttributesourceadvisor (); }} Passen Sie den Shriofilter an
Ausführungsreihenfolge: Vorhand -> Dofilterinternal -> Executelogin -> OnLoginSuccess
Das Haupturteil ist, ob die Anmeldeanforderung dofilterinternal ist
public class JWTFilter erweitert BasisichTtpAuthenticationFilter { / *** Die Methode anpassen, um die Anmeldung auszuführen UserernamepasswordToken usernamePassWordToken = json.ParseObject (httpServletRequest.getInputStream (), usernamePasswordToken.class); // Senden Sie es für die Login an Reich. Wenn der Fehler falsch ist, wird eine Ausnahme ausgelöst und erwischt Subjekt = this.getSubject (Anfrage, Antwort); Betreff.login (userernamepasswordToken); Gibt dies zurück. // Fehler mit einer Ausnahme ausführen}/ *** Erste Methode zur Ausführung*/ @Override Protected Boolean Prehandle (ServletRequest Request, ServletResponse -Antwort) löst eine Ausnahme aus {return Super.prehandle (Anfrage, Antwort); } / *** Anmeldeoperation nach erfolgreichem Login* Fügen Sie JWTs Header hinzu* / @Override Protected Boolean OnLoginSuccess (AuthenticationToken Token, Subjekt, ServletRequest Request, ServletResponse -Antwort) {httpServletResponse httpServletResponse = (httpServletresponse) Reaktion; String jwttoken = jwts.builder () .setId (token.getPrincipal (). ToString ()) .setExpiration (DateTime.Now (). Plusminutes (30) .todate ()) .SignWith (SignatureAlithm.hs256, jwtcost.ssignature). httpServletResponse.addHeader (Authorization_Header, jwtToken); zurückkehren; } / *** Der Hauptprozess von Anmeldung und Überprüfung* Bestimmen Sie, ob es sich um Anmeldung oder eine gewöhnliche Anfrage nach Anmeldung handelt* / @Override Public Void DofilterInternal (ServletRequest ServletRequest, ServletResponse ServletResponse, Filterchain Filterchain) ioexception, servletException {httplevletrequest {httplevletrequest {httplevletrequest {httplevletrequest {httplevletrequest {httpevletreews {httplevel (HttpServletRequest) ServletRequest; HttpServletResponse httpServletResponse = (httpServletResponse) servletResponse; String servletPath = httpServletRequest.getServletPath (); if (Stringutils.equals (ServletPath, "/login") {// executelogin (ServletRequest, ServletResponse); } else {String authenticationHeader = httpServletRequest.Getheader (Authorization_Header); if (Stringutils.isnotEmpty (AuthenticationHeader)) {Angaben body = jwts.parser () .setsigningKey (jwtcost.SignatureKey) .ParSeclaimsjws (AuthenticationHeader) .getBody (); if (body! String updateToken = jwts.builder (). SetClaims (Körper) .Compact (); httpServletResponse.addHeader (Authorization_Header, UpdateToken); // Benutzeranmeldeinformationen PrincipalCollection Principals = new SimplePrincipalCollection (body.getId (), jwtcost.usernamePasswordRealm); // shiro -Benutzerinformationen Websubject.builder Builder = new Websubject.builder (servletRequest, servletResponse); Builder.Principals (Schulleiter); Builder.Authenticated (wahr); Builder.SessioncreationEnabled (falsch); WebSubject Subjekt = builder.buildwebSubject (); // in den Container eingeben und threadcontext.bind (Betreff) aufrufen; filterchain.dofilter (httpServletRequest, httpServletResponse); }} else {httpServletResponse.setStatus (httpstatus.forbidden.Value ()); }}}} Anmeldung fehlgeschlagene Verarbeitung
Gehen Sie mit Shrio -Ausnahmen
@RestControllerAdvicePublic Class GlobalControllerexceptionHandler {@ExceptionHandler (value = exception.class) public Object AllexceptionHandler (httpServletRequest -Anforderung, httpServletRespectRect, Ausnahme) {String Message = Exception.getCause (). GetMessage (); Logutil.Error (Nachricht); Neue ergebene zurückgeben (exception.getClass (). getName (), meldung); } /*=========== Shiro Exception Intercept=========================*/ @ExceptionHandler(value = IncorrectCredentialsException.class) public String IncorrectCredentialsException(HttpServletRequest request, HttpServletResponse response, Exception exception) { response.setStatus (httpstatus.forbidden.Value ()); Rückgabe "Falschkredischsexception"; } @ExceptionHandler (value = unbekannteAccountException.class) public String UnbekannteAccountException (httpServletRequest -Anforderung, httpServletResponse -Antwort, Ausnahme) {response.setStatus (httpstatus.forbidden.Value ()); zurück "unBocusAccountException"; } @ExceptionHandler (value = lockedAccountException.class) public String lockedAccountException (httpServletRequest -Anforderung, httpServletResponse -Antwort, Ausnahme) {response.setStatus (httpstatus.forbidden.Value ()); return "lockedAccountException"; } @ExceptionHandler (value = expereIneTTemptSexception.class) public String expereTePemptSexception (httpServletRequest Request, httpServletResponse -Antwort, Ausnahme) {response.setStatus (httpstatus.forbidden.value (); Rückkehr "übermäßiges Temperaturexception"; } @ExceptionHandler (value = authenticationException.class) öffentliche String -AuthentifizierungException (httpServletRequest -Anforderung, httpServletResponse -Antwort, Ausnahme) {response.setStatus (httpstatus.forbidden.Value ()); Rückgabe "Authentifizierungxception"; } @ExceptionHandler (value = unauthorizedException.class) public String unauthorizedException (httpServletRequest Request, httpServletResponse -Antwort, Ausnahme) {response.setStatus (httpstatus.forbidden.value ()); zurück "unbefugtesException"; }}Umgang mit JWT -Ausnahmen
Dies ist eine Fallstrick, da es sich um eine Ausnahme handelt, die im Filter auftritt, und @ExceptionHandler kann es nicht abfangen.
/*** Intercept Spring Startfehler Seite*/ @rastControllerPublic class globalExceptionHandler implementiert Fehlercontroller {@Override public String getErrorPath () {return "/error"; } @RequestMapping (value = "/error") öffentlicher Objektfehler (httpServletRequest -Anforderung, httpServletResponse -Antwort) löst eine Ausnahme aus {// Fehlerbehandlungslogik -Ausnahme = (Ausnahme) request.getAttribute ("javax.Servlet.Error.Exception"); Throwable cause = exception.getCause (); if (Ursache Instanz von abgelaufenem jwTexception) {response.setStatus (httpstatus.gateway_timeout.Value ()); Neue ergebene zurückgeben ("abgelaufene Jwtexception", cause.getMessage ()); } if (Ursacheninstanz von malmaledjwTexception) {response.setStatus (httpstatus.forbidden.Value ()); Neue ergebene returnfo ("MalmalFormedJwTexception", cause.getMessage ()); } Neue ergebene returnfo zurückgeben (cause.getCause (). getMessage (), cause.getMessage ()); }}In Bezug auf Autorisierungsinformationen wie Berechtigungen können Sie sie direkt in Redis auf den Cache einfügen. Ich finde es auch gut.
Quellcode präsentiert: Githup-Shiro-Zweig: Warm Erinnerung: Der Testcode kann im täglichen Leben chaotisch sein.
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.