Обзор
Как мы все знаем, используя JWT для проверки разрешения. По сравнению с сеансом преимущество сеанса заключается в том, что сеанс требует большого количества памяти сервера, и когда используются несколько серверов, он будет включать в себя общие проблемы сеанса, что более хлопотно при доступе к мобильным терминалам, таким как мобильные телефоны.
JWT не нужно хранить на сервере и не занимает ресурсы сервера (то есть без сохранения). После входа пользователя он прикрепляется к токену при доступе к запросу, который требует разрешения (обычно установленного в заголовке HTTP -запроса). У JWT нет проблемы с обменом несколькими серверами, а также не имеет проблем с мобильным доступом на мобильных телефонах. Если для повышения безопасности токен может быть связан с IP -адресом пользователя
Передний процесс
Пользователь вошел через Ajax, чтобы получить токен
После этого при доступе требуется разрешение, прикрепите токен для доступа.
<! Doctype html> <html lang = "en"> <head> <meta charset = "UTF-8"> <Title> title </title> <script src = "http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"> </script> <script = "/javecript ="/javecript = "/javecript ="/javercript = "/javercript"/" ""; function login () {$ .post ("http: // localhost: 8080/outr/login", {username: $ ("#username"). val (), пароль: $ ("#пароль"). val ()}, function (data) {console.log (data); «Получить», url: «http: // localhost: 8080/userpage», Beforesend: function (request) {request.setrequestheader ("Authorization", Header); } </script> </head> <body> <fieldset> <legend> Пожалуйста, войдите в систему </Legend> <babel> username </label> <input type = "text" id = "username"> <babel> Пароль </label> <input type = "text" id = "пароль"> кнопку «Вход» = кнопку onclick = " id = "touserpagebtn" onclick = "touserpagebtn ()"> Access userpage </button> </body> </html>Процесс бэкэнд (Spring Boot + Spring Security + JJWT)
Идеи:
Напишите класс объектов пользователя и вставьте кусок данных
Пользовательский (пользовательский) класс объектов
@Data @entityPublic Class User {@ID @GeneratedValue Private INT ID; Приватное название строки; Private String Password; @Manytomany (cascade = {cascadetype.refresh}, fetch = fetchtype.eage) @jointable (name = "user_role", joincolumns = {@joincolumn (name = "uid", ссылка на cholumnname = "id")}, inversjoincolumns = {@joincol = ",", ",")}, inversjoincolumns = {@joincol name ". ссылка на ColumnName = "id")}) частный список <Lele> Роли;} Роль (разрешение) класс сущности
@Data @entityPublic Class Role {@ID @GeneratedValue Private INT ID; Приватное название строки; @Manytomany (mapedby = "role") частный список <user> пользователи;} Вставить данные
Пользовательский стол
| идентификатор | имя | пароль |
|---|---|---|
| 1 | Linyuan | 123 |
Ролевая таблица
| идентификатор | имя |
|---|---|
| 1 | ПОЛЬЗОВАТЕЛЬ |
Таблица user_role
| uid | избавлять |
|---|---|
| 1 | 1 |
Интерфейс слоя DAO, получает данные через имя пользователя и возвращает дополнительный объект со значением Java8
Public Interface userRepository Extends Repository <user, Integer> {необязательный <user> findbyName (string name);} Напишите logindto для передачи данных с помощью передней части
@Datapublic class logindto реализует serializable {@notblank (message = "Имя пользователя не может быть пустым") private String username; @Notblank (message = "пароль не может быть пустым") Private String Password;} Напишите инструмент генерации токенов и создайте его с помощью библиотеки JJWT. Всего существует три метода: генерировать токен (вернуть строку), проанализировать токен (вернуть объект аутентификации аутентификации) и проверить токен (вернуть логическое значение)
@Componentpublic class jwttokenutils {private final logger log = loggerfactory.getlogger (jwttokenutils.class); Частная статическая финальная строка власти_key = "auth"; частный строковый секрет; // Подписание ключевой частной TokenValityInmilliseconds; // Дата истечения срока годности // (Помните меня) Дата истечения срока действия @postconstruct public void init () {this.secretkey = "linyuanmima"; int second1day = 1000 * 60 * 60 * 24; this.tokenvalityInmilliseconds = secondin1day * 2l; this.tokenvalityInmillisecondsForRememberMe = secondIn1day * 7L; } частное окончательное статическое длительное время истечения = 432_000_000; // Создать токен открытый строки createToken (аутентификация аутентификации, boolean momplyme) {String voritions = authentication.getauthorities (). Stream () // Получить строку разрешения пользователя, такую как пользователь, admin .map (wetredAuthority :: getAuthority) .collect (collectors.joining (",", ")); долго сейчас = (новая дата ()). getTime (); // Получить текущую достоверность даты временной метки; // Время истечения сбора хранения if (momplyme) {validity = новая дата (теперь + this.tokenvalityInmilliseconds); } else {validity = новая дата (теперь + this.tokenvalityInmillisecondsforrememberme); } return jwts.builder () // Создать token token.setsubject (authentication.getname ()) // Установить пользователь-ориентированное.claim (holities_key, власти) // Добавить атрибут разрешения.setexpiration (достоверность) // set invalidation time.signwith (signatureAlgorithh.shs512, secretkey) /withersature; } // Получить разрешения пользователя публичная аутентификация getAuthentication (string token) {system.out.println ("token:"+token); Претензии претензий = jwts.parser () // Parse Token полезной нагрузки .setsigningKey (SecretKey) .ParSecistsjws (token) .getBody (); Коллекция <? extends wreatedAuthority> worthes = arrays.stream (reatss.get (howores_key) .toString (). Split (",", ")) // Получить строку разрешения пользователя (simplegrantedAuthority :: new) .collect (collectors.tolist ()); // конвертируйте элементы в предоставление интерфейса rewedAuthority interface princiте = новый пользователь (retemss.getSubject (), ", власти); вернуть новый usernamepasswordAuthenticationToken (принципал »,« власти); } // Убедитесь, является ли токен правильным общедоступным логическим Validatetoken (String Token) {try {jwts.parser (). SetSigningKey (secretKey) .parSeclaimsjws (token); // Проверьте токен с помощью ключа вернуть true; } catch (signatureException e) {// log Excemnature log.info ("Invalid JWT."); log.trace ("Invalid jwt подписная трасса: {}", e); } catch (malformedjwtexception e) {// jwt формата ошибки log.info ("Invalid Jwt Token."); log.trace ("Invalid JWT Token Trace: {}", E); } catch (истечь jwtexception e) {// jwt истек log.info ("истек jwt token."); log.trace ("Срок действия jwt token trace: {}", e); } catch (unsupportedjwtexception e) {// jwt log.info ("unsopported jwt token."); log.trace ("Неподдерживаемый токен jwt token race: {}", e); } catch (allogalargumentException e) {// ошибка параметров исключения исключения. log.trace ("JWT Token Compact of Handler является недействительной трассировкой: {}", e); } вернуть false; }} Реализуйте интерфейс userdetails, представляющий класс объектов пользователя, обернут на наш объект пользователя, содержит разрешения и другие свойства, и может использоваться в Spring Security Security
открытый класс myuserdetails реализует userdetails {частный пользователь; public myuserdetails (пользователь пользователя) {this.user = user; } @Override Public Collection <? extends wreatedAuthority> getAuthorities () {list <Role> role = user.getRoles (); Список <welsedAuthority> worthes = new ArrayList <> (); StringBuilder SB = new StringBuilder (); if (roles.size ()> = 1) {for (роли роли: роли) {worites.add (new SimplegrantedAuthority (role.getName ())); } return Outhorations; } return Outhorations; } return AuthorityUtils.commaseParatedStringToAuthorityList (""); } @Override public String getPassword () {return user.getPassword (); } @Override public String getUsername () {return user.getName (); } @Override public boolean isAccountnonexpired () {return true; } @Override public boolean isAccountnonlocked () {return true; } @Override public boolean iscredentialsnonexpired () {return true; } @Override public boolean isenabled () {return true; }} Реализуйте интерфейс userdetailsservice, который имеет только один метод для получения пользовательских данных. Мы можем получить объект пользователя из базы данных, затем завернуть его в пользователи и вернуть его
@Servicepublic class myuserdetailsservice реализует userdetailsservice {@autowired userRepository userRepository; @Override public userDetails lokuserByusername (String S) выбрасывает usernamenotFoundexception {// загружать объект пользователя из базы данных необязательно <user> user = userRepository.findbyName (ы); // Для отладки, если значение существует, имя пользователя и пароль выводятся. Ifpresent ((value)-> system.out.println ("username:"+value.getName ()+"Пароль пользователя:"+value.getPassword ())); // Если значение больше не является, вернуть null return new myuserdetails (user.orelse (null)); }} Напишите фильтр. Если пользователь несет токен, он получит токен и генерирует объект аутентификации аутентификации на основе токена, и сохранит его в SecurityContext для управления разрешением с помощью Spring Security.
открытый класс jwtauthenticationtokenfilter extends genericfilterbean {private final Logger log = loggerFactory.getLogger (jwtauthenticationTokenfilter.class); @Autowired private jwttokenutils tokenprovider; @Override public void dofilter (ServletRequest ServletRequest, Servletresponse Servletresponse, FilterChain FilterChain), выбросы IOException, ServletException {System.out.println ("jwtauthenticationTokenfilter"); try {httpservletrequest httpreq = (httpservletrequest) servletrequest; String jwt = resolvetoken (httpreq); if (stringUtils.hastext (jwt) && this.tokenprovider.validateTetoken (jwt)) {// проверить, является ли JWT правильной аутентификацией аутентификации = this.tokenprovider.getAuthentication (jwt); // Получить информацию об аутентификации пользователей SecurityContextholder.getContext (). SetAuthentication (аутентификация); // Сохранить пользователя в SecurityContext} filterChain.dofilter (ServletRequest, Servletresponse); } catch (истек jwtexception e) {// jwt Invalid log.info ("Исключение безопасности для пользователя {} - {}", e.getClaims (). getSubject (), e.getMessage ()); log.trace ("Trace Exception Trace: {}", e); ((Httpservletresponse) servletresponse) .setStatus (httpservletresponse.sc_unauthorized); }} private String Resolvetoken (httpservletrequest) {string bearertoken = request.getheader (websecurityconfig.authorization_header); // Получить токен из заголовка http if (stringutils.hastext (bearertoken) && bearertoken.startswith ("носитель")) {return bearertoken.substring (7, bearertoken.length ()); // вернуть строку токена и удалить носитель} string jwt = request.getParameter (websecurityConfig.authorization_token); // Получить токен из параметров запроса if (stringutils.hastext (jwt)) {return jwt; } return null; }} Напишите LoginController. Пользователь обращается к /auth /rougin через имя пользователя и пароль, получает его через объект Logindto и создает объект аутентификации. Код является usernamepasswordauthenticationtoken, чтобы определить, существует ли объект. Проверьте объект аутентификации с помощью метода аутентификации Authentication Manager. Authentication Manager Class Class Mamanager проверит через AuthenticationProvider (обработка аутентификации). Провайдер по умолчанию вызывает DaoAuthenticationProvider для обработки аутентификации. DaoAuthenticationProvider получит userdetails через пользовательский интерфейс (источник информации о аутентификации), если аутентификация успешна, возвращается авториентация, содержащая разрешения, а затем установит ее в SecurityContext через SecurityContextholder.getContext (). SetAuthentication (), генерируйте токен в соответствии с аутентификацией и возвращает его для пользователя.
@Restcontrollerpublic class logincontroller {@autowired private userRepository userRepository; @Autowired Private Authentication Manager AuthenticationManager; @Autowired private jwttokenutils jwttokenutils; @RequestMapping (value = "/auth/login", method = requestMethod.post) открытый строка новый usernamepasswordAuthenticationToken (logindto.getusername (), logindto.getpassword ()); // Если объект аутентификации не является пустым if (objects.nonnull (AuthenticationToken)) {userRepository.findbyName (authenticationToken.getPrincipal (). ToString ()) .Orelsethrow (()-> Новое исключение («пользователь не существует»)); } try {// проверить объект аутентификации через аутентификацию Manager (по умолчанию реализован как ProviderManager) Authentication = AuthenticationManager.Authenticate (AuthenticationToken); // Привязанность аутентификации с SecurityContext SecurityContextholder.getContext (). SetAuthentication (аутентификация); // генерировать токен строки token = jwttokenutils.createtoken (аутентификация, false); // Напишите токен в заголовок http httpresponse.addheader (websecurityconfig.authorization_header, «носитель»+token); вернуть "носитель"+токен; } catch (badcredentialsexception authentication) {бросить новое исключение ("ошибка пароля"); }}} Напишите класс конфигурации безопасности, наследуйте WebseCurityConfigurerAdapter и переопределите метод настройки
@Configuration@enablewebsecurity@enableglobalmethodsecurity (prefostenabled = true) открытый класс WebseCurityConfig Extends WebseCerationConfigurerAdapter {public Static Final String Authorization_header = "Authorization"; public Static Final String Authorization_token = "access_token"; @Autowired private userdetailsservice userdetailsservice; @Override Protected void configure (AuthenticationManagerBuilder auth) Throws Exception {auth // настройка для получения пользовательской информации.userDetailsService (userDetailsService) // Установить пароль incryption.passwordencoder (passwordEncoder ()); } @Override Protected void configure (httpsecurity http) бросает исключение {// Настройка политики доступа к запросу http // close csrf и cors .cors (). Disable () .csrf (). Disable () // sessions не требуется, поскольку токен не требуется. SessionManagemanageManagement (). . и () // Проверьте http request.authorizeRequests () // позволить всем пользователям получить доступ к домашней странице и входить в систему. . и () // установить logout (). armitall (); // добавить фильтр jwt по адресу http .addfilterbefore (genericfilterbean (), usernamepasswordAuthenticationFilter.class); } @Bean public passwordEncoder passwordEncoder () {return new bcryptpasswordencoder (); } @Bean public genericfilterbean genericfilterbean genericfilterbean () {return new jwtauthenticationtokenfilter (); }} Напишите контроллер для тестирования
@Restcontrollerpublic class usercontroller {@postmapping ("/login") public String login () {return "login"; } @GetMapping ("/") public String Index () {return "hello"; } @Getmapping ("/userpage") public String httpapi () {System.out.println (SecurityContextholder.getContext (). GetAuthentication (). GetPrincipal ()); вернуть "UserPage"; } @GetMapping ("/adminpage") public String httpsuite () {return "userpage"; }}Скачать исходный код корпуса (локальная загрузка)
Суммировать
Вышеуказанное - все содержание этой статьи. Я надеюсь, что содержание этой статьи имеет определенную справочную ценность для каждого обучения или работы. Если у вас есть какие -либо вопросы, вы можете оставить сообщение для общения. Спасибо за поддержку Wulin.com.