Cet article présente la méthode de Spring-Boot combinée avec Shrio pour implémenter JWT, et la partage avec vous, comme suit:
En ce qui concerne la vérification, il y a environ deux aspects:
Solution principale: utilisez un filtre Shiro personnalisé
Construction du projet:
Il s'agit d'un projet Web Spring-Boot. Si vous ne connaissez pas la construction du projet Spring-Boot, veuillez Google.
pom.mx présente des packages de pot connexes
<! - SHIRO Permission Management -> <Dedency> <GroupId> org.apache.shiro </proncId> <Artifactid> shiro-spring </refactive> <fri version> $ {shiro.version} </prewing> </dependency> <petifactid> <proupId> org.apache.shiro </prounid> <ArtifActid> Shiro-Core; <version> $ {shiro.version} </ version> </ dépendance> <! - JWT -> <dependency> <proupId> io.jsonwebtoken </romp grouped> <Artifactid> jjwt </retifactid> <version> 0.9.0 </-version> </pedency> Configuration liée à Shrio
Faites valoir le point! ! Personnalisé un filtre
filtermap.put ("jwtfilter", new JWTFilter ()); @Configurationpublic class shiroconfig {@bean public shirofilterfactorybean getshirofilterfactorybean (SecurityManager SecurityManager) {shirofilterfactorybean shirofilterfactorybean = new shirofilterfactorybean (); ShirofilterFactoryBean.SetSecurityManager (SecurityManager); // Ajoutez votre propre filtre et nommez-le jwtfilter map <string, filter> filTermap = new hashmap <> (); filtermap.put ("jwtfilter", new JWTFilter ()); ShirofilterFactoryBean.SetFilters (filTermap); / * * Règles URL personnalisées * http://shiro.apache.org/web.html#urls- * / map <String, String> FilterChainDefinitionMap = shirofilterFactoryBean.getFilterChainDefinitionMap (); FilterChainDefinitionMap.put ("/ **", "jwtfilter"); ShirofilterFactoryBean.SetFilterChainDefinitionMap (FilterChainDefinitionMap); retour shirofilterfactoryBean; } / ** * SecurityManager n'a pas besoin d'injecter directement Shirodbrealm, ce qui peut entraîner une défaillance des transactions * pour la solution, voir handlecontextrefresh * http://www.debugrun.com/a/nks9ejq.html * / @Bean ("SecurityManager") PublicweBeleucyManager Sécurité {DefaultWebSecurityManager Manager = new defaultWebSecurityManager (); Manager.SetRealm (TokenRealm); / * * Fermez la session livrée avec Shiro, voir la documentation pour plus de détails * http://shiro.apache.org/session-management.html#SessionManagement-SatelessAplications%28Sessionless%29 * / DefaultSubjectDao SubjectDao = new DefaultSubjectDao (); DefaultSessionStorageEvaluator DefaultSessionStorageEvaluator = new defaultSessionStorageEvaluator (); DefaultSessionStorageEvaluator.SetSessionStorageEnabled (false); SubsenceDao.SetSessionStorageEvaluator (DefaultSessionStorageEvaluator); Manager.SetSubjectDao (SubjectDao); Retour Manager; } @Bean public lifecycleBylePostProcessor LifecycleBylePostProcessor () {return new LifecycleBylePostProcessor (); } @Bean (name = "tokenRealm") @DependSon ("lifecycleBeanPostProcessor") public tokenrealm tokenrealm () {return new tokenRealm (); } @Bean @dependSon ("LifecycleBeanPostProcessor") Public DefaultAdvisorAutoproxyCreator DefaultAdvisorAutoproxycreator () {DefaultAdvisorAutoproxycreator DefaultAdvisorAutoproxyCreator = newfAftAdVisorAutoproxyCreator (); // Force CGLIB pour empêcher le proxy en double et les erreurs de proxy possibles // https://zhuanlan.zhihu.com/p/29161098 defaultAdvisorAutoproxycreator.SetProxyTargetClass (true); return defaultAdvisorAutOproxyCreator; } @Bean Public AuthorizationAttributesourceadvisor getAuthorizationAtTributesourceadVisor (SecurityManager SecurityManager) {AutorisationAttributesourceadVisor AutorizationAtriButesourceAdvisor = Nouvelle AutorisationAttributeSourceCeadVisor (); AutorisationAtTributesourceadVisor.SetSecurityManager (SecurityManager); Renvoie une nouvelle autorisationAtTributesourceadVisor (); }} Personnaliser le filtre Shrio
Ordre d'exécution: pré-main
Le jugement principal est de savoir si la demande de connexion est DOFILTERINTERNE
classe publique JWTFilter étend BasichTTPAuthenticationFilter {/ ** * Personnalisez la méthode pour exécuter la connexion * / @Override Protected boolean exécuteLogin (ServLetRequest Request, ServletResponse Response) lance IoException {httSservleRequest HttSservleRest = (httServletReter) requête; UsernamepasswordToken usernamepasswordToken = json.parseObject (httpServletRequest.getInputStream (), usernamepasswordtoken.class); // le soumettez-le au royaume pour la connexion. Si l'erreur est erronée, elle lancera une exception et sera capturée comme sujet = this.getSubject (demande, réponse); sujet.login (usernamepasswordToken); Renvoyez ceci.onloginsuccess (usernamepasswordToken, sujet, demande, réponse); // Erreur lance une exception} / ** * première méthode pour exécuter * / @Override Protected Boolean Prehandle (ServLetRequest Request, ServLetResponse Response) lève une exception {return super.prehandle (request, réponse); } / ** * Opération de connexion après une connexion réussie * Ajouter l'en-tête de JWT * / @Override Protected booléen onloginsuccess (AuthenticationToken Token, Subject Sujet, ServLetRequest Request, ServLetResponse Response) {httpservletResponse httpservletResponse = (httpservrersesponse) réponse; String jwttoken = jwts.builder () .setid (token.getPrincipal (). ToString ()) .SetExpiration (DateTime.Now (). PlusMinutes (30) .Todate ()) .signWith (signaturalgorithm.hs256, jwtCost.SignatureKey) .Compact (); httpservletResponse.addheader (Authorization_header, jwttoken); Retour Vrai; } /** * The main process of login and verification* Determine whether it is login, or an ordinary request after login*/ @Override public void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) ServLetRequest; HttpservletResponse httpServletResponse = (httpservletResponse) servletResponse; String servletPath = httpservletRequest.getServletPath (); if (stringUtils.equals (servletPath, "/ login")) {// exécutELOGIN (servLetRequest, servletResponse); } else {String AuthenticationHeader = httpServleRequest.GetHeader (Authorization_Header); if (stringUtils.isnotempty (authenticationHeader)) {revendications body = jwts.parser () .setSigningKey (jwtcost.signatkey) .parseclaidsjws (authenticationHeader) .getBody (); if (body! = null) {// mettre à jour le token body.setExpiration (dateTime.now (). PlusMinutes (30) .todate ()); String updateToken = jwts.builder (). SetClaims (body) .compact (); httpServletResponse.addheader (Authorization_Header, UpdateToken); // Ajouter des informations d'identification utilisateur PrincipalCollection Principals = new SimplePrincipalCollection (Body.getId (), jwtcost.UsernamepasswordRealm); // assemble Shiro User Information WebSubject.Builder Builder = new WebSubject.Builder (ServleTrequest, ServletResponse); Builder.Principals (directeurs); builder.authenticated (true); Builder.SessionCreationAnabled (false); WebSubject sujet = builder.buildWebSubject (); // mis dans le conteneur et appeler threadContext.bind (sujet); FilterChain.Dofilter (httpServletRequest, httpservletResponse); }} else {httpsservletResponse.setStatus (httpstatus.forbidden.value ()); }}}} Traitement défaillant de connexion
Gérer les exceptions Shrio
@RestControllerAdvicePublic classe globale GlobalControlleRexceptionHandler {@ExceptionHandler (Value = exception.class) Objet public AllexectceptionHandler (HttpservletRequest Request, httpservletResponse réponse, exception exception) {String Message = exception.getCause (). GetMessage (); Logutil.Error (message); return new resultInfo (exception.getClass (). getName (), message); } / * =========== SHIRO EXCEPTION Intercept ========================= * / @ExceptionHandler (Value = IncorrectCredentialSexception.class) Public String IncorrectCredentialSException (exception HttpservletRequest, HTTPERSERSPERSPERS réponse.setStatus (httpstatus.forbidden.value ()); retourner "IncorrectCredentialSexception"; } @ExceptionHandler (Value = UnknownActreXception.class) public String UnknownActreTexception (HttpServletRequest Request, HttpServletResponse Response, Exception Exception) {Response.SetStatus (httpstatus.forbidden.Value ()); retourner "Unknownactrexception"; } @ExceptionHandler (Value = LockedActreException.class) Public String LockedActreException (HttpServletRequest Request, HttpServletResponse Response, Exception Exception) {Response.SetStatus (httpstatus.forbidden.Value ()); retourner "LockedActrexception"; } @ExceptionHandler (Value = exsiveAttEmptSException.class) Public String exsiveAttEmpsexception (HttpServletRequest Request, HttpservletResponse Response, exception exception) {Response.SetStatus (httpstatus.forbidden.Value ()); retourner "excès de titre de timp-teexception"; } @ExceptionHandler (Value = AuthenticationException.Class) String public AuthenticationException (HttpServLetRequest Request, HttpServletResponse Response, exception exception) {réponse.setStatus (httpstatus.forbidden.value ()); retourner "AuthenticationException"; } @ExceptionHandler (Value = UnauthorizedException.class) Public String UnauthorizedException (HttpServletRequest Request, HttpServletResponse Response, exception exception) {réponse.SetStatus (httpstatus.forbidden.Value ()); retourner "UnauthorizedException"; }}Gestion des exceptions JWT
Il s'agit d'un piège, car c'est une exception qui se produit dans le filtre, et @ExceptionHandler ne peut pas l'intercepter.
/ ** * Interception Page d'erreur de démarrage Spring * / @ RESTControllerPublic Class GlobalexceptionHandler implémente ErrorController {@Override public String getErrorPath () {return "/ error"; } @RequestMapping (Value = "/ Error") Erreur d'objet public (HttpServLetRequest Request, HttpServletResponse Response) lève exception {// Gestion d'erreur Logic Exception Exception = (exception) request.getAttribute ("javax.servlet.errror.exception"); Cause thrimpable = exception.getCause (); if (cause instanceof expiredjwtexception) {réponse.setStatus (httpstatus.gateway_timeout.value ()); Renvoie un nouveau résultat ("expiredjwtexception", cause.getMessage ()); } if (cause instanceof malformedjwtexception) {réponse.setstatus (httpstatus.forbidden.value ()); return new ResultInfo ("Malformedjwtexception", cause.getMessage ()); } return new resultInfo (cause.getcause (). getMessage (), cause.getMessage ()); }}En ce qui concerne les informations d'autorisation telles que les autorisations, vous pouvez directement les placer dans Redis en cache. Je pense que c'est bien aussi.
Code source présente: Githup-Shiro Branch: Rappel chaud: Le code de test peut être désordonné dans la vie quotidienne.
Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.