이 기사는 Shrio와 결합 된 Spring-Boot 방법을 소개하여 JWT를 구현하고 다음과 같이 공유합니다.
검증과 관련하여 대략 두 가지 측면이 있습니다.
주요 솔루션 : 사용자 정의 Shiro 필터를 사용하십시오
프로젝트 구성 :
이것은 스프링 부팅 웹 프로젝트입니다. Spring-Boot Project Construction에 대해 모른다면 Google을 알려주십시오.
pom.mx는 관련 JAR 패키지를 소개합니다
<!-Shiro 권한 관리-> <pectionency> <groupid> org.apache.shiro </groupid> <artifactid> shiro-spring </artifactid> <버전> $ {shiro.version} </version> </fectionency> <pection> <groupid> org.apache.shiro <artifactid> Shiro-Cocore <버전> $ {shiro.version} </version} </version> </fectionency> <!-jwt-> <prection> <groupid> io.jsonwebtoken </groupid> <artifactid> jjwt </artifactid> <버전> 0.9.0 </version> </dependency> Shrio 관련 구성
요점을 만드십시오! ! 필터를 사용자 정의했습니다
filtermap.put ( "jwtfilter", New Jwtfilter ());
@ConfigurationPublic Class ShiroConfig {@bean public shirofilterfactorybean getShirofilterfactoryBean (SecurityManager SecurityManager) {shirofilterfactoryBean ShirofilterfactoryBean = new ShirofilterfactoryBean (); shirofilterFactoryBean.SetSecurityManager (SecurityManager); // 자신의 필터를 추가하고 이름을 지정하고 jwtfilter map <string, 필터> Filtermap = new Hashmap <> (); filtermap.put ( "jwtfilter", New Jwtfilter ()); shirofilterfactorybean.setfilters (filtermap); / * * Custom URL 규칙 * http://shiro.apache.org/web.html#urls- */map <String, String> FilterChainDefinitionMap = shirofilterFactoryBean.getFilterChainDefinitionMap (); FilterChainDefinitionMap.put ( "/**", "jwtfilter"); shirofilterFactoryBean.SetFilterChainDefinitionMap (FilterChainDefinitionMap); 반환 shirofilterfactorybean; }/** * SecurityManager는 ShirodBrealm을 직접 주입 할 필요가 없습니다. 이는 솔루션의 경우 트랜잭션 실패를 일으킬 수 있습니다. http://www.debugrun.com/a/nks9ejq.html */@bean ( "SecurityManager") SecurityManager (Tokenrealmmokengreal Manager)를 참조하십시오. DefaultWebSecurityManager Manager = 새 DefaultWebsecurityManager (); Manager.SetRealm (TokenRealm); / * * Shiro와 함께 제공되는 세션을 닫으십시오. 자세한 내용은 설명서를 참조하십시오. defaultsessionStorageEvaluator defaultsessionStorageEvaluator = new defaultsessionStorageEvaluator (); defaultsessionStorageEvaluator.SetSessionStorageEnabled (False); griessDao.SetSessionStorageEvaluator (defaultsessionStorageEvaluator); Manager.SetSubjectDao (SubjectDao); 반품 관리자; } @bean public lifecyclebeanpostprocessor lifecyclebeanpostprocessor () {return new lifecyclebeanpostprocessor (); } @Bean (이름 = "TokenRealm") @dependson ( "LifeCycleBeanPostProcessor") public tokenrealm tokenrealm () {return new TokenRealm (); } @bean @dependson ( "LifeCycleBeanPostProcessor") public defaultAdvisorAutoProxyCreator defaultAdvisorAutoProxycreator () {defaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = 새로운 DefaultAdvisorOutoProxycreator (); // 중복 프록시 및 가능한 프록시 오류를 방지하도록 cglib을 강제로 강제 // https://zhuanlan.zhihu.com/p/29161098 DefaultAdvisorAutoProxyCreator.setProxyTargetClass (true); DefaultAdvisorAutoProxyCreator를 반환합니다. } @Bean Public AuthorizationAttributSourCeadvisor getAuthorizationAttributesourceAdvisor (SecurityManager SecurityManager) {authorizationAttributeSourceAdvisor AuthorizationAttributesOURCeadvisor = new AuthorizationAttributesOUrceAdvisor (); AuthorizationAttributesourceadvisor.SetSecurityManager (SecurityManager); 새로운 권한 AuthorizationAttributesourceadvisor ()를 반환합니다. }} Shrio 필터를 사용자 정의합니다
실행 순서 : 사전 처리 -> dofilterinternal-> executeLogin-> onloginsuccess
주요 판단은 로그인 요청이 Dofilterinternal인지 여부입니다.
Public Class Jwtfilter는 BasichttPauthenticationFilter { / *** 로그인을 실행하는 메소드를 사용자 정의합니다* / @override Protected Boolean executeLogin (ServletRequest 요청, ServletResponse 응답) IoException {httpservletrequest httpervletrequest = (httpservletrequest); usernamepasswordtoken usernamepasswordtoken = json.parseobject (httpservletrequest.getinputstream (), usernamepasswordtoken.class); // 로그인을 위해 영역에 제출하십시오. 오류가 잘못되면 예외가 발생하고 피사체 주제 = this.getSubject (요청, 응답); 대상 (usernamepasswordtoken); reture this.onloginsuccess (usernamepasswordtoken, 주제, 요청, 응답); // ERROR DRAT } / *** 성공적인 로그인 후 로그인 작업* JWT의 헤더 추가* / @override Protected Boolean onloginsuccess (AuthenticationToken Token, 주제 주제, ServletRequest 요청, ServletResponse 응답) {httpservletResponse = (httpservletResponse) 응답; String jwttoken = jwts.builder () .setId (token.getPrincipal (). toString ()) .setexpiration (datetime.now (). plusminutes (30) .todate ()) .signwith (signaturealgorithm.hs256, jwtcost.signature Khey). httpservletresponse.addheader (Authorization_header, jwttoken); 진실을 반환하십시오. } / *** 로그인 및 검증의 주요 프로세스* 로그인인지 또는 로그인 한 후 일반 요청 여부를 결정하십시오* / @override public void dofilterinternal (servletrequest servletrequest, servletreponse servletrepsonse, filterchain)이 ioexception, servletexception httrequest httperperverequest (httpservletrequest) servletrequest; httpservletresponse httpservletresponse = (httpservletresponse) servletresponse; 문자열 servletpath = httpservletrequest.getServletPath (); if (stringUtils.equals (servletpath, "/login")) {// executeLogin (servletRequest, servletResponse); } else {string authenticationHeader = httpservletRequest.getheader (upportization_header); if (stringUtils.isNotEmpty (AuthenticaticHeader)) {CLEARTHS BODY = jwts.parser () .SetSigningKey (jwtCost.SignatureKey) .parseClaimsjws (AuthenticationHeader) .getBody (); if (body! = null) {// Token body.setexpiration을 업데이트합니다 (datetime.now (). plusminutes (30) .todate ()); String updateToken = jwts.builder (). setCleaims (body) .compact (); httpservletresponse.addheader (upportization_header, updateToken); // 사용자 자격 증명 추가 PrincipalCollection Principals = New SimplePrinciPalCollection (body.getId (), jwtcost.usernamepasswordRealm); // shiro 사용자 정보 webSubject.builder builder = new WebSubject.Builder (servletRequest, servletResponse); 빌더. 프린시 퍼 (Principals); 빌더. builder.sessioncreationEnabled (false); webSubject subject = builder.buildwebsubject (); // 컨테이너에 넣고 CALL ThreadContext.Bind (주제); filterchain.dofilter (httpservletrequest, httpservletresponse); }} else {httpservletresponse.setstatus (httpstatus.forbidden.value ()); }}}} 로그인 처리 실패
Shrio 예외를 처리합니다
@RestControllerAdVicePublic 클래스 GlobalControllerExceptionHandler {@ExceptionHandler (value = exception.class) public Object AllexceptionHandler (httpservletrequest request, httpservletrepsonge 응답, 예외 예외) {string message = except.getCause (); getMessage (); logutil.error (메시지); 새로운 결과를 반환합니다 (Exception.getClass (). getName (), message); } /*=========== Shiro Exception Intercept=========================*/ @ExceptionHandler(value = IncorrectCredentialsException.class) public String IncorrectCredentialsException(HttpServletRequest request, HttpServletResponse response, Exception exception) { Response.setStatus (httpstatus.forbidden.value ()); "잘못된 실질적인 섹션"을 반환합니다. } @ExceptionHandler (value = unknownaccountexception.class) public String unknownAccountexception (httpservletRequest 요청, httpservletResponse 응답, 예외 예외) {response.setstatus (httpstatus.forbidden.value ()); "알 수없는 Accountexception"을 반환합니다. } @ExceptionHandler (value = lockedAccountexception.class) public String levedAccountexception (httpservletrequest request, httpservletResponse 응답, 예외 예외) {response.setstatus (httpstatus.forbidden.value ()); "lockedaccountexception"을 반환합니다. } @ExceptionHandler (value = accessiveAttEmptSexception.class) public String excessiveAttempsexception (httpservletrequest request, httpservletreponse 응답, 예외 예외) {response.setstatus (httpstatus.forbidden.value ()); "excessiveattempsexception"을 반환합니다. } @ExceptionHandler (value = authenticationException.class) public string augenticationException (httpservletrequest request, httpservletresponse 응답, 예외 예외) {response.setstatus (httpstatus.forbidden.value ()); "AuthenticationException"을 반환합니다. } @ExceptionHandler (value = unauthorizedException.class) 공개 문자열 무단 exception (httpservletRequest 요청, httpservletResponse 응답, 예외 예외) {response.setstatus (httpstatus.forbidden.value ()); "무단 exception"을 반환합니다. }}JWT 예외 처리
필터에서 발생하는 예외이며 @ExceptionAndler는이를 가로 채울 수 없기 때문에 이것은 함정입니다.
/*** 스프링 부팅 오류 페이지*/ @restControllerPublic Class GlobalExceptionHandler는 ErrorController {@override public string getErrorPath () {return "/error"; } @requestmapping (value = "/error") 공개 오브젝트 오류 (httpservletrequest 요청, httpservletrepsonse 응답) 예외 {// 오류 처리 로직 예외 예외 = (예외) request.getAttribute ( "javax.servlet.error.exception"); 던질 가능한 원인 = Exception.getCause (); if (원인 alfiredjwtexception) {response.setstatus (httpstatus.gateway_timeout.value ()); 새로운 resultinfo를 반환합니다 ( "expreiredjwtexception", ass.getMessage ()); } if (mause instance의 instance) {response.setstatus (httpstatus.forbidden.value ()); 새로운 resultinfo ( "mullformedjwtexception", ass.getMessage ()); } return new resultInfo (as }}권한과 같은 권한 정보와 관련하여 Redis에 직접 넣을 수 있습니다. 나도 좋다고 생각합니다.
소스 코드 선물 : Githup-Shiro Branch : 따뜻한 알림 : 시험 코드는 일상 생활에서 지저분해질 수 있습니다.
위는이 기사의 모든 내용입니다. 모든 사람의 학습에 도움이되기를 바랍니다. 모든 사람이 wulin.com을 더 지원하기를 바랍니다.