В этой статье представлен метод Spring-Boot в сочетании с Shrio для реализации JWT, и делится им с вами следующим образом:
Что касается проверки, есть примерно два аспекта:
Основное решение: используйте пользовательский фильтр широ
Строительство проекта:
Это веб-проект Spring-Boot. Если вы не знаете о строительстве проекта Spring-Boot, пожалуйста, Google.
pom.mx представляет соответствующие пакеты JAR
<!-Управление разрешениями SHIRO-> <Dependency> <groupId> org.apache.shiro </GroupId> <artifactid> shiro-spring </artifactid> <sersion> $ {shiro.version} </version> </artifactid> <dehyed> <groupid> org.apache.shiro </GroupD> <sersive> $ {shiro.version} </version> </dependency> <!-jwt-> <dependency> <groupid> io.jsonwebtoken </groupid> <artifactid> jjwt </artifactid> <serse> 0.9.0 </version> </vehing> Связанная с Шрио Конфигурация
Сделайте дело! ! Настраивал фильтр
filtermap.put ("jwtfilter", new jwtfilter ()); @ConfigurationPublic Class ShiroConfig {@bean public shirofilterfactorybean getshirofilterfactorybean (SecurityManager SecurityManager) {ShiroFilterFactoryBean ShiroFilterFactorybean = new ShirofilterFactorybean (); shirofilterfactorybean.setsecuritymanager (SecurityManager); // Добавить свой собственный фильтр и назвать его jwtfilter map <string, filter> filtermap = new hashmap <> (); filtermap.put ("jwtfilter", new jwtfilter ()); shirofilterfactorybean.setfilters (filtermap); / * * Пользовательские правила URL * http://shiro.apache.org/web.html#urls- */map <string, string> filterchaindefinitionmap = shirofilterfactorybean.getfilterchaindefinitionmap (); FilterChainDefinitionMap.put ("/**", "jwtfilter"); ShirofilterFactoryBean.SetFilterChainDefinitionMap (FilterChainDefinitionMap); вернуть shirofilterfactorybean; }/** * SecurityManager не нужно напрямую вводить Shirodbrealm, что может вызвать сбой транзакции * для решения, см. Handlecontextrefresh * http://www.debugrun.com/a/nks9ejq.html */@bean ("securityManager") publicwebsecurit DefaultWebSecurityManager Manager = New DefaultWebsecurityManager (); Manager.setRealm (TokenRealm); / * * Закройте сеанс, который поставляется с Shiro, см. Документацию для деталей * http://shiro.apache.org/session-management.html#sessionmanagement-stateshlessapplications%28SessionBless%29 */defaultbjectDao subjectDao = new DefaultsUbjectDao! (); DefaultSessionStorageEvaluator DefaultsSessionStorageEvaluator = New DefaultSessionStorageEvaluator (); DefaultSessionStorageEvaluator.setSessionStorageEnabled (false); subjectDao.setsessionStorageEvaluator (DefaultSessionStorageEvaluator); Manager.setsubjectDao (субъектдао); ответный менеджер; } @Bean Public LifeCyclebeanpostProcessor LifeCyclebeanpostProcessor () {return new LifeCyclebeanpostProcessor (); } @Bean (name = "tokenRealm") @dependson ("LifeCyclebeanpostProcessor") public tokenRealm tokenRealm () {return new tokenRealm (); } @Bean @Dependson ("LifeCyclebeanpostprocessor") public DefaultAdvisorautoproxycreator defaultAdvisorautoproxycreator () {defaultadvisoroproxycreator defaultadvisorautoproxycreator = new defaultadvisorautoproxycreator (); // Force Cglib, чтобы предотвратить дублированный прокси и возможные ошибки прокси // https://zhuanlan.zhihu.com/p/29161098 defaultadvisoroproxycreator.setproxytargetclass (true); вернуть defaultAdvisorautoproxycreator; } @Bean Public AuthorizationAttributesourceadvisor getAuthorizationattributesourceadvisor (SecurityManager SecurityManager) {AuthorizationAttributesourceadvisor Authorizationattributesourceadvisor = new AuthorizationAttributesourceadvisor (); Authorizationattributesourceadvisor.setsecurityManager (SecurityManager); вернуть новый Authorizationattributesourceadvisor (); }} Настроить фильтр Шрио
Приказ о выполнении: prehandle -> dofilterinternal -> receelogin -> onloginsuccess
Основное суждение заключается в том, является ли запрос входа в систему дофильтеринтернал
открытый класс jwtfilter extends basichttpauthenticationfilter { / *** Настроить метод для выполнения логина* / @override защищенного логического исполнения (запрос ServletRequest, ответ Servletresponse). Usernamepasswordtoken usernamepasswordtoken = json.parseobject (httpservletrequest.getinputstream (), usernamepasswordtoken.class); // Отправить его в сферу для входа в систему. Если ошибка неверна, она бросит исключение и будет пойман за темой субъекта = this.getSubject (запрос, ответ); Subject.login (Usernamepasswordtoken); вернуть это. // Ошибка бросает исключение}/ *** Первый метод для выполнения*/ @Override Protected Boolean Prehandle (запрос ServletRequest, ответ ServletResponse) Throws Exception {return Super.prehandle (запрос, ответ); } / *** Операция входа после успешного входа* добавить заголовок jwt* / @override защищенное логическое значение OnloginSuccess (AuthenticationToken Token, субъект, запрос ServletRequest, ответ ServletResponse) {httpservletresponse httpservlectresponse = (httpserservessesponse) ответ; String jwttoken = jwts.builder () .setId (token.getPrincipal (). ToString ()) .setExpiration (dateTime.now (). Plusminates (30) .todate ()) .signwith (signaturealgorithm.hs256, jwtcost). httpservletresponse.addheader (Authorization_header, jwttoken); вернуть истину; } / *** Основной процесс входа в систему и проверки* Определите, является ли он входом в систему или обычный запрос после входа в систему* / @Override public void dofilterinternal (ServletRequest ServletRequest, Servletresponse Servletrespons (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 (аутентификация)) {претензий body = jwts.parser () .setsigningkey (jwtcost.signaturekey) .parseclaimsjws (AuthenticationHeader) .getBody (); if (body! = null) {// Обновление токенового body.setexpiration (datetime.now (). Plusminutes (30) .todate ()); String updateTetoken = jwts.builder (). SetClaims (body) .compact (); httpservletresponse.addheader (Authorization_header, UpdateTetoken); // Добавить пользовательские учетные данные Принципиальные принципы = new SimplePrincipalCollection (body.getId (), jwtcost.usernamepasswordRealm); // Соберите информацию пользователя Shiro Websubject.Builder = new WebSubject.Builder (ServletRequest, ServletResponse); Builder.Principals (принципы); Builder.Authenticated (True); Builder.SessionCreationEnabled (false); Websubject subject = builder.buildWebSubject (); // Поместите в контейнер и вызовы ThreadContext.Bind (субъект); FilterChain.dofilter (httpservletRequest, httpservletresponse); }} else {httpservletresponse.setStatus (httpstatus.forbidden.value ()); }}}} Вход в систему не выполняет обработку
Справиться с исключениями Шрио
@RestControllerAdvicePublic Class GlobalControlleRexceptionHandler {@ExceptionHandler (value = exception.class) public Object AllexceptionHandler (httpservlectrequest, httpservletresponse response, exection exection) {String message = exection.getCause (). GetMessage (); Logutil.error (сообщение); вернуть новый ResultInfo (exception.getClass (). getName (), message); } /*=========== Shiro Exception Intercept ============================================================= response.setStatus (httpstatus.forbidden.value ()); вернуть "inforctcredentialsexception"; } @ExceptionHandler (value = inknownAccountexception.class) public String inknownaccountexception (httpservletrequest, httpservletresponse ответ, исключение исключения) {response.setStatus (httpstatus.forbidden.value ()); вернуть "Unknownaccountexception"; } @ExceptionHandler (value = lockedAccountexception.class) public String lockedAccountexception (httpservletrequest, httpservletresponse response, исключение исключения) {response.setStatus (httpstatus.forbidden.value ()); вернуть "lockedAccountexception"; } @ExceptionHandler (value = ExcessIveatTemptSexception.class) открытая строка ExcessIveatTempleSexception (httpservletRequest, httpservletresponse response, исключение исключения) {response.setStatus (httpstatus.forbidden.value ()); вернуть "ExcessIveatTemptSexception"; } @ExceptionHandler (value = AuthenticationException.class) public String authenticationException (httpservletrequest, httpservletresponse response, исключение исключения) {response.setStatus (httpstatus.forbidden.value ()); вернуть "аутентификацию Exception"; } @ExceptionHandler (value = unauthorizedException.class) public String unauthorizedException (httpservletrequest, httpservletresponse response, исключение исключения) {response.setStatus (httpstatus.forbidden.value ()); вернуть "несанкционированное экспресс"; }}Обработка исключений JWT
Это ловушка, потому что это исключение, которое происходит в фильтре, и @ExceptionHandler не может перехватить его.
/*** Страница ошибки ошибки перехвата пружины*/ @ @restcontrollerpublic class globalexceptionHandler реализует errorController {@Override public String geterRorpath () {return "/error"; } @RequestMapping (value = "/error") Ошибка публичного объекта (httpservlectrequest, httpservletresponse response) throws Exception {// Обработка ошибок исключение исключения = (Exception) request.getAttribute ("javax.servlet.error.exception"); Бросая причина = exception.getCause (); if (причина экземпляра истечь срок действия) {response.setStatus (httpstatus.gateway_timeout.value ()); вернуть новый результат («истечь } if (причина экземпляра malformedjwtexception) {response.setStatus (httpstatus.forbidden.value ()); вернуть новый результат ("malformedjwtexception", canem.getMessage ()); } вернуть новый ResultInfo (cane.getCause (). getMessage (), cane.getMessage ()); }}Что касается информации о разрешении, такой как разрешения, вы можете напрямую поместить ее в Redis в кеш. Я думаю, что это тоже хорошо.
Исходный код представляет: Githup-Shiro Branch: Теплое напоминание: тестовый код может быть грязным в повседневной жизни.
Выше всего содержание этой статьи. Я надеюсь, что это будет полезно для каждого обучения, и я надеюсь, что все будут поддерживать Wulin.com больше.