Автор оригинала: Koffi KOMLAN.
Привет,
Мы добавили некоторые функции безопасности в наш REST API в предыдущем посте благодаря Spring Security и JWT . В этом уроке мы проверим токен и защитим конечные точки API.
Обзор
Вот что мы будем делать в этом посте:
- Проверка токена JWT
- Как предоставить/запретить доступ к методу хранилища данных Spring для отдыха
Проверка токена JWT
Чтобы перехватить и проверить токен, поступающий от клиента, мы должны создать класс фильтра запросов, расширяющий веб-фильтр Spring OncePerRequestFilter класс. Для любого входящего запроса этот класс фильтра будет выполнен. Он проверяет, имеет ли запрос действительный токен JWT. Если у него есть действительный токен JWT, он устанавливает аутентификацию в контексте, чтобы указать, что текущий пользователь аутентифицирован.
Создайте класс, AuthRequestFilter.java в безопасность.фильтр пакет.
package com.codeurinfo.easytransapi.security.filter; import com.codeurinfo.easytransapi.security.UserDetailsImpl; import com.codeurinfo.easytransapi.security.UserDetailsServiceImpl; import com.codeurinfo.easytransapi.security.util.JwtUtil; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; @Component public class AuthRequestFilter extends OncePerRequestFilter { @Autowired private UserDetailsServiceImpl userDetailsService; @Autowired private JwtUtil jwtUtil; @Override protected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain chain ) throws ServletException, IOException { final String authorizationHeader = request.getHeader("Authorization"); String username = null; String jwt = null; if ( authorizationHeader != null && authorizationHeader.startsWith("Bearer ") ) { // get the jwt token jwt = authorizationHeader.substring(7);// authorizationHeader is like "Bearer jwttoken", so 7 caracters before jwttoken username = jwtUtil.extractUsername(jwt);// get username for the given token } if ( username != null && SecurityContextHolder.getContext().getAuthentication() == null ) { UserDetailsImpl userDetails = (UserDetailsImpl) this.userDetailsService.loadUserByUsername(username); if (jwtUtil.validateToken(jwt, userDetails)) { UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities() ); usernamePasswordAuthenticationToken.setDetails( new WebAuthenticationDetailsSource().buildDetails(request) ); SecurityContextHolder .getContext() .setAuthentication(usernamePasswordAuthenticationToken); } } chain.doFilter(request, response); } }
Затем давайте добавим этот фильтр в SecurityConfig.java класс в сконфигурируйте метод, подобный этому:
@Override protected void configure(HttpSecurity http) throws Exception { http .csrf() .disable() .authorizeRequests() .antMatchers("/api/auth/**").permitAll() // Grant access to every /api/auth based url .anyRequest().authenticated() // All other based url wil be allowed if authenticated .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS);//Force server not to never create an HttpSession http.addFilterBefore( authRequestFilter, UsernamePasswordAuthenticationFilter.class ); }
Напоминание: Вы должны сначала объявить Фильтр запроса аутентификации в качестве переменной в SecurityConfig.java класс
@Autowired private AuthRequestFilter authRequestFilter;
На данный момент наш REST API почти защищен. Давайте запустим и протестируем его в Postman.
1 . Сделайте простой запрос на получение
http:
Как вы можете видеть, у нас ошибка отказа в доступе.
2 . Сделайте запрос на запись для входа в систему
http:
Не забудьте использовать те же учетные данные, которые вы настроили для пользователей при предварительной загрузке DatabaseLoader.java Если указано действительное имя пользователя/пароль, возвращается токен JWT.
3 . Попробуйте еще раз выполнить простой запрос на получение
http:
- Перед выполнением запроса GET в Postman скопируйте токен JWT, возвращенный на шаге 2
- Откройте вкладку “Заголовок”, добавьте ключ : Авторизация , введите значение :
- :
С этого момента вы должны добавить ключ авторизации и значение на вкладке Заголовок перед выполнением любого другого запроса, кроме входа в систему
4 . Сделайте запрос на публикацию, чтобы сохранить маршрут
http:
- Откройте вкладку Заголовок и ключ авторизации и значение, как описано в шаге 3
- Откройте вкладку Тело, чтобы добавить свои данные полезной нагрузки
{ "name": "Rex-Adidogome", "start": "Grand marche - Rex", "terminus": "Adidogome" }
- Затем выполните, чтобы получить результат, как показано ниже:
Поздравляю! Вы настроили Spring Security и JWT для защиты API REST, чтобы только прошедшие проверку пользователи могли получать доступ к конечным точкам для запросов.
Но… в реальном мире каждый вошедший в систему пользователь должен иметь возможность доступа к некоторым конечным точкам, в то время как другие-нет. Давайте укрепим нашу безопасность API.
Безопасность пружины: безопасность на уровне метода
Помните, мы добавили @Enableglobalmethod безопасность y(защищено,) аннотация к SecurityConfig.java класс. Эта аннотация обеспечивает безопасность на уровне метода.
В RouteRepository.java класс, предположим, мы хотим, чтобы только пользователи ROLE_ADMIN имели возможность доступа к методу findRoutesByName .
Добавить @Предварительная авторизация (“hasRole(‘ROLE_ADMIN’)”) аннотация к этому методу для предоставления доступа пользователям ROLE_ADMIN. Обновленный код RouteRepository.java:
package com.codeurinfo.easytransapi.repository; import com.codeurinfo.easytransapi.model.Route; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.repository.query.Param; import org.springframework.data.rest.core.annotation.RepositoryRestResource; import org.springframework.data.rest.core.annotation.RestResource; import org.springframework.security.access.prepost.PreAuthorize; @RepositoryRestResource public interface RouteRepository extends JpaRepository{ @PreAuthorize("hasRole('ROLE_ADMIN')") @RestResource(path = "routesByName") Optional findRoutesByName(@Param("name") String name); }
Давайте еще раз протестируем API.
1 . Убедитесь, что вы предварительно загрузили двух разных пользователей, одного с именем ROLE_ADMIN, а другого нет.
2 . Сделайте запрос POST для входа в систему с учетными данными администратора, затем скопируйте маркер
3 . Попробуйте отправить запрос на сохранение маршрута, получить запрос на поиск маршрута и т. Д. Используя маркер авторизации на вкладке Заголовок, вы должны получить успешные ответы.
4 . Теперь войдите в систему с помощью учетных данных простого пользователя (у которого не было роли ROLE_ADMIN) и скопируйте токен
5 . Используя маркер авторизации на вкладке Заголовок, все методы POST и GET должны быть успешными, за исключением запроса GET для маршрута поиска!
http://localhost:9000/api/routes/search/routesByName?name=Rex-Adidogome
Мы получили запрещенную ошибку, в которой говорится, что вошедшему в систему пользователю не разрешается запрашивать этот метод.
В следующем посте мы добавим новые функции в наше приложение Easy Trans. Надеюсь, вы узнали что-то новое. Если это так, не забудьте нажать кнопку “Мне нравится” и подписаться на этот блог, чтобы быть в курсе новых сообщений.
Оригинал: “https://www.codementor.io/@koffikomlan/let-s-build-java-full-stack-spring-boot-react-app-backend-rest-api-3-securing-the-rest-api-with-spring-security-jwt-b-1k448kc13g”