mitaichik
@mitaichik

Spring: Как сделать аутентификацию на основе bearer токена?

Добрый день! Есть Spring MVC приложение. На него приходят запросы c заголовком Authorization : Bearer ... Авторизация, выдача токенов идет вне этого приложения.

Что мне нужно: нужно получить данные пользователя по этому токену (токен и данные храняться в БД) и сделать иньекцию объекта юзера в контроллер.

Какие средства из коробки обычно используются для этого? Я так понял что spring security, но не совсем понял как сделать такое...
  • Вопрос задан
  • 1291 просмотр
Решения вопроса 1
jaxtr
@jaxtr
JavaEE/Spring-разработчик
  1. Класс, реализующий Authentication.
    TokenAuthentication.java
    public class TokenAuthentication extends AbstractAuthenticationToken {
        private final Object principal;
        private final Object credentials;
        public TokenAuthentication(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
            super(authorities);
            this.principal = principal;
            this.credentials = credentials;
            this.setAuthenticated(true);
        }
        public TokenAuthentication(Object principal, Object credentials) {
            this(principal, credentials, null);
        }
        @Override
        public Object getPrincipal() {
            return principal;
        }
        @Override
        public Object getCredentials() {
            return credentials;
        }
    }

  2. Фильтр, с которого начнётся процесс аутентификации пользователя. Фильтр должен создать объект типа Authentication и попробовать аутентифицировать его при помощи AuthenticationManager.
    TokenHeaderAuthenticationFilter.java
    public class TokenHeaderAuthenticationFilter extends OncePerRequestFilter {
    
        private final AuthenticationManager authenticationManager;
    
        public TokenHeaderAuthenticationFilter(AuthenticationManager authenticationManager) {
            this.authenticationManager = authenticationManager;
        }
    
        @Override
        protected void doFilterInternal(HttpServletRequest servletRequest, HttpServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {
            if (SecurityContextHolder.getContext().getAuthentication() != null && SecurityContextHolder.getContext().getAuthentication().isAuthenticated()) {
                filterChain.doFilter(servletRequest, servletResponse);
                return;
            }
            String headerValue = servletRequest.getHeader("X-Authorization");
            if (StringUtils.isEmpty(headerValue)) {
                filterChain.doFilter(servletRequest, servletResponse);
                return;
            }
            String token = headerValue.split("\\s")[1];// ну или headerValue.replace("Bearer ")
            TokenAuthentication authenticationToken = new TokenAuthentication(null, token);
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(servletRequest));
    
            Authentication authenticationResult = authenticationManager.authenticate(authenticationToken);
            SecurityContextHolder.getContext().setAuthentication(authenticationResult);
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }

  3. Класс, реализующий AuthenticationProvider. Этот класс и будет производить аутентификацию полученных данных.
    TokenAuthenticationProvider.java
    public class TokenAuthenticationProvider implements AuthenticationProvider {
        @Override
        public boolean supports(Class<?> authentication) {
            return TokenAuthentication.class.isAssignableFrom(authentication);
        }
        @Override
        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
            // здесь должна быть реализована логика аутентификации полученных данных
        }
    }

  4. Последний штрих - конфигурация.
    SecurityConfig.java
    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Bean
        public AuthenticationProvider tokenAuthenticationProvider() {
            return new TokenAuthenticationProvider();
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.addFilterAfter(new TokenHeaderAuthenticationFilter(authenticationManagerBean()), BasicAuthenticationFilter.class)
                    .authenticationProvider(tokenAuthenticationProvider())
                    .authorizeRequests()
                    .anyRequest().authenticated();
        }
    }

Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы