Este artículo presenta el método de Boot Spring-Boot con Shrio para implementar JWT, y lo comparte con usted, de la siguiente manera:
Con respecto a la verificación, hay aproximadamente dos aspectos:
Solución principal: use un filtro shiro personalizado
Construcción del proyecto:
Este es un proyecto web de Boot Spring-Boot. Si no sabe sobre la construcción del proyecto Spring-Boot, por favor google.
POM.MX presenta paquetes de jarra relacionados
< <versión> $ {shiro.version} </versión> </pendency> <!-jwt-> <pendency> <grupoD> io.jsonwebtoken </groupid> <artifactid> jjwt </artifactid> <versión> 0.9.0 </versión> </pendency> Configuración relacionada con Shrio
¡Haz el punto! ! Personalizado un filtro
filtreMap.put ("JWTFilter", nuevo JWTFilter ()); @ConfigurationPublic Clase Shiroconfig {@Bean public shirofilterFactoryBean getShirofilterFactoryBean (SecurityManager SecurityManager) {shirofilterfactorybean shirofilterFactoryBean = new shirofilterFactoryBean (); shiroFilterFactoryBean.SetSecurityManager (SecurityManager); // Agregue su propio filtro y asígnele el nombre JWTFilter Map <String, Filter> FilterMap = new HashMap <> (); filtreMap.put ("JWTFilter", nuevo JWTFilter ()); shirofilterFactoryBean.setFilters (filtreMap); / * * Reglas de URL personalizadas * http://shiro.apache.org/web.html#urls- */map <string, string> filterChainDefinitionMap = shirofilterFactoryBean.getFilterChainDefinitionMap (); filterChainDefinitionMap.put ("/**", "jwtfilter"); shirofilterFactoryBean.setFilterChainDefinitionMap (filtreChainDefinitionMap); return shirofilterfactorybean; }/** * SecurityManager no necesita inyectar shirodbrealm directamente, lo que puede causar falla de transacción * Para la solución, consulte Handlecontextrefresh * http://www.debugrun.com/a/nks9eJq.html */@Bean ("SecurityManager") PublicwebsecebsecurityManager (TokenRealm) DefaultWebSecurityManager Manager = new DefaultWebSecurityManager (); gerente.setRealm (TokenRealm); / * * Cierre la sesión que viene con shiro, vea la documentación para obtener detalles * http://shiro.apache.org/session-management.html#sessionManagement-statlessApplications%28Sessionles%29 */DefaultSubjectDao SUMTDAO = new DefaultsubjectDao (); DefaultSessionStorageEvaluator DefaultsessionStorageEvaluator = new DefaultSessionStorageEvaluator (); defaultSessionStorageEvaluator.SetSessessionStorageEnabled (falso); Sujeto. gerente.setsubjectdao (sometdao); gerente de regreso; } @Bean public lifecycleBeanPostPossorsor LifeCycleBeanPostProcessor () {return New LifeCycleBeanPostProcessor (); } @Bean (name = "tokenRealm") @dependson ("lifecycleBeanPostProcessor") public tokenRealm tokenRealm () {return new tokenRealM (); } @Bean @dependson ("LifeCycleBeanPostProcessor") Public DefaultAdVisoraUtoProxyCreator DefaultAdVisoraUtOproxyCreator () {defaultAdVisoraUtoProxyCreator DefaultVisorautoProxyCreator = NewDVisoraUtoproxyCreator ();); // obligar a CGLIB a evitar un proxy duplicados y posibles errores de proxy // https://zhuanlan.zhihu.com/p/29161098 defaultadVisoraUtoproxyCreator.setProxyTargetClass (true); return defaultAdVisoraUtoProxyCreator; } @Bean Public AuthorizationAttributeSourCeAdVisor getAuthorizationAttributeSourCeAdVisor (SecurityManager SecurityManager) {AuthorizationAttributeSourCeadVisor AuthorizationAttributeScoadVisor = nueva autorizationTributesOurCeadVisor (); AutorationAtTributesOurCeadVisor.SetSecurityManager (SecurityManager); devolver nuevo autorizatizationAttributeUrceAdVisor (); }} Personalizar el filtro Shrio
Orden de ejecución: Prehandle -> dofilterInternal -> Executelogin -> OnloginSuccess
El juicio principal es si la solicitud de inicio de sesión es dofilterinternal
La clase pública JWTFilter extiende BASICHTTPAuthenticationFilter { / *** Personalizar el método para ejecutar Login* / @Override Protected boolean ExecuteLogin (ServletRequest, Solicitud, Respuesta ServletReSponse) lanza IOException {httpServletRequest httpServeRTrequest = (httpServeRrequest) Solicitud; UserNamePasswordToken usernamePassWordToken = json.parseObject (httpservletRequest.getInputStream (), usernamePasswordToken.class); // Envíelo al reino para iniciar sesión. Si el error es incorrecto, lanzará una excepción y será atrapado asunto de sujeto = this.getSubject (solicitud, respuesta); Sujeto.login (usernamePasswordToken); devuelve this.onloginSuccess (usernamePasswordToken, sujeto, solicitud, respuesta); // Error de lanza una excepción}/ *** Primer método para ejecutar*/ @Override protegido Boolean Prehandle (ServletRequest Solicitud, Respuesta ServletResponse) Lanza la excepción {return super.prehandle (solicitud, respuesta); } / *** Operación de inicio de sesión después de inicio de sesión exitoso* Agregar el encabezado de JWT* / @Override protegido boolean onloginSuccess (autenticación de token, sujeto sujeto, solicitud de servletrequest, respuesta servletResponse) {httpServletReSponse htttpServletResponse = (httpServletResponse) respuesta; String jwttoken = jwts.builder () .setId (token.getPrincipal (). ToString ()) .setExpiration (datTime.Now (). Plusminutes (30) .todate ()) .signwith (signaturealGorithm.hs256, jwtcost.signature) .Compact (); httpservletResponse.addHeader (Authorization_header, jwttoken); devolver verdadero; } / *** El principal proceso de inicio de sesión y verificación* determina si es inicio de sesión, o una solicitud ordinaria después de inicio de sesión* / @Override public void dofilterInternal (ServLetRequest ServLetRequest, ServletResponse ServletResponse, FilterChain FilterChain) lanza IoException, ServLetException {httpServequest httTserveRequest = (HttpservletRequest) ServLetRequest; HttpservletResponse httpServletResponse = (httpServletResponse) ServletResponse; Cadena servletpath = httpservletRequest.getServletPath (); if (stringUtils.equals (servletpath, "/login")) {// ExecienteLogin (ServLetRequest, ServLetResponse); } else {String AuthenticationHeader = httpservletRequest.getheader (autorization_header); if (StringUtils.ISNotEmpty (AuthenticationHeader)) {reclama cuerpo = jwts.parser () .setsigningkey (jwtcost.signaturekey) .parseclemlamsjws (autenticación) .getBody (); if (body! = null) {// actualizar token body.setExpiration (datetime.now (). Plusminutes (30) .todate ()); Cadena updateToken = jwts.builder (). SetClaims (cuerpo) .compact (); httpservletResponse.addHeader (autorization_header, updateToken); // Agregar credenciales de usuario PrincipalCollection Princips = new SimplePrincipalCollection (Body.getId (), jwtcost.usernamePassWordRealm); // ensamble la información de usuario de Shiro WebSubject.Builder Builder = new WebSubject.Builder (ServletRquest, ServletResponse); Builder.principals (directores); builder.authenticated (verdadero); builder.SessionCreationEnable (falso); WebSubject Sujem = Builder.BuildWebSubject (); // Poner en el contenedor y llamar a ThreadContext.bind (sujeto); FilterChain.dofilter (httpservletRequest, httpservletResponse); }} else {httpservletResponse.setStatus (httpStatus.Forbidden.Value ()); }}}} Iniciar sesión en el procesamiento fallido
Manejar excepciones de shrio
@RestControllerAdVicePublic Class GlobalControllerExceptionHandler {@ExceptionHandler (valor = excepción.class) Object public allexceptionHandler (httpservletRequest solicitud, respuesta httpServletResponse, excepción de excepción) {String Message = Exception.getCause (). GetMessage (); Logutil.error (mensaje); return nuevo resultadoinfo (excepcion.getClass (). getName (), mensaje); } /*) Respuesta.SetStatus (httpstatus.Forbidden.Value ()); devolver "incorrectoCredentialSexception"; } @ExceptionHandler (valor = desconocidoCountException.class) Cadena pública desconocida ACHOUCTEXCECECION (httpservletRequest, respuesta httpServletResponse, excepción de excepción) {Response.SetStatus (httpstatus.forbidden.value ()); regresar "desconocidoCountException"; } @ExceptionHandler (value = LockedAccountException.Class) Cadena pública LockedAccountException (httpservletRequest solicitud, httpServletResponse Respuesta, excepción de excepción) {Response.SetStatus (httpStatus.ForbidDden.Value ()); regresar "LockedAccountException"; } @ExceptionHandler (value = excessiveAtTemptSeXception.class) cadena pública excessiveAtTemptSeXception (httpservletRequest solicitud, httpServletResponse respuesta, excepción de excepción) {Response.setStatus (httpstatus.forbidden.value ()); devolver "excesivo deficiente de medición"; } @ExceptionHandler (value = AuthenticationException.Class) public String AuthenticationException (httpservletRequest solicitud, respuesta httpServletResponse, excepción de excepción) {Response.setStatus (httpstatus.forbidden.value ()); return "AuthenticationException"; } @ExceptionHandler (valor = unauthorizedException.class) cadena pública unutorizedException (httpservletRequest solicitud, httpServletResponse Response, excepción de excepción) {Respuesta.SetStatus (httpStatus.Forbidden.Value ()); regresar "UnauthorizedException"; }}Manejo de excepciones JWT
Esta es una trampa, porque es una excepción que ocurre en el filtro, y @ExceptionHandler no puede interceptarlo.
/*** Página de error de arranque de intercepción*/ @RestControllerPublic GlobalExceptionHandler implementa ErrorController {@Override public String getErrorPath () {return "/error"; } @RequestMapping (valor = "/error") Error de objeto público (httpservletRequest solicitud, respuesta httpservletreSponse) lanza la excepción {// Error de manejo de manejo lógico Exception = (Exception) request.getAttribute ("javax.servlet.error.exception"); Causa de lanzamiento = excepción.getCause (); if (causar instancia de expiredjwtException) {Response.SetStatus (httpstatus.gateway_timeout.value ()); devolver nuevo resultadoinfo ("expiredjwtexception", causa.getMessage ()); } if (causa instancia de malformedjwtException) {Response.setStatus (httpstatus.forceBidden.Value ()); return new dultInfo ("malformedJWTException", causa.getMessage ()); } return New resultinfo (causa.getCause (). getMessage (), causa.getMessage ()); }}Con respecto a la información de autorización, como los permisos, puede ponerla directamente en Redis a la memoria caché. Creo que también es bueno.
El código fuente presenta: Rama de Githup-Shiro: Recordatorio cálido: el código de prueba puede ser desordenado en la vida diaria.
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.