TL; DR - Как использовать специально созданный JWT для защиты моего API БЕЗ с помощью oauth2?
Я прочитал этот вопрос но я все еще не уверен, как распутать OAuth2 из аутентификации JWT в Spring Security 5. У меня странный случай, я попытаюсь объяснить
- мой SPA будет аутентифицироваться с Okta, чтобы получить токен доступа
- мой SPA отправит GET в мой загрузочный API (который я контролирую) в / token / exchange, который вернет настроенный JWT. Мой маршрут / токен / обмен проецируется через oauth2 с использованием стартера загрузки okta spring. У меня эта часть работает.
- мой SPA будет отправлять пользовательский JWT в качестве заголовка авторизации для всех последующих запросов к моему API. Мне нужно защитить все маршруты, начинающиеся с
/api
, чтобы принимались только запросы с моим пользовательским токеном.
Я избавлю вас от почему, если кому-то действительно не нужны подробности ... но, пожалуйста, поверьте мне, когда я говорю, что застрял между камнем и наковальней, и именно так мы решили решить проблему.
Я понимаю, что мне понадобятся два WebSecurityConfigurerAdapter
, чтобы я мог защитить свой /token/exchange
маршрут с помощью Okta, а все остальные маршруты - с помощью пользовательского JWT.
Я запутался в деталях фильтра безопасности. Должен ли я отменить один? Который из? Стоит ли делать новый фильтр? Куда его вставить? Я видел в Интернете пример, в котором используются GenericFilter, OncePerRequestFilter, UsernameAndPasswordFilter, BasicAuthFilter. Я немного завален вариантами ...
Для меня отметки +1 указали бы на возможность служить сообществу и продемонстрировали бы потребность, которую весенняя команда могла бы помочь удовлетворить.
------ кровавые подробности ------
у моего SPA в настоящее время есть настраиваемая страница входа в систему, которая отправляет кредиты моему API. Мой API выполняет вызов REST в Ping Federate, чтобы получить JWT с использованием типа предоставления password
. Этот JWT возвращается в SPA, который SPA использует для всех последующих запросов.
Меня попросили преобразовать приложение для использования экземпляра Okta родительской компании. Я не контролирую его, и я не могу заставить его вернуть мне токен, который будет точно соответствовать токену Ping Federate, который в настоящее время ожидает мое приложение.
мой СПА - угловое приложение 1.5. прежде чем он будет загружен вручную, я планирую выполнить аутентификацию okta через перенаправление и обменять токен Okta на пользовательский токен. По сути, вместо того, чтобы передавать свои кредиты пользователей, я могу передать свой токен как своего рода ваучер ... потому что я больше никогда не увижу кредиты пользователей ... они будут вводиться только в Okta ... вроде все дело.
В моем API, просто используя тему токена okta, я могу найти все необходимые данные и построить токен, который по форме идентичен токену, предоставленному Ping Federate (который не возвращает типичный токен oauth2). Получив токен, который соответствует тому, что я получаю в настоящее время, большая часть логики API может продолжать работать «как есть».
-------- На данный момент неудачные попытки
Я вижу это в своих журналах
o.s.security.web.FilterChainProxy : /api/entities at position 6 of 12 in additional filter chain; firing Filter: 'BearerTokenAuthenticationFilter'
o.s.s.authentication.ProviderManager : Authentication attempt using org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider
.s.a.DefaultAuthenticationEventPublisher : No event was found for the exception org.springframework.security.oauth2.core.OAuth2AuthenticationException
.o.s.r.w.BearerTokenAuthenticationFilter : Authentication request for failed: org.springframework.security.oauth2.core.OAuth2AuthenticationException: An error occurred while attempting to decode the Jwt: Signed JWT rejected: Another algorithm expected, or no matching key(s) found
o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@3ec543f6
s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
похоже, что Spring Security пытается аутентифицировать запросы, сделанные к /api/entities
, с моей конфигурацией Okta oauth, а не с моим "ApiConfig", который сейчас я просто делаю весь свой /api/**
общедоступным
@Configuration
@Order(1)
public class OktaWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/token/exchange")
.authorizeRequests()
.antMatchers("/token/exchange").authenticated()
.and()
.oauth2ResourceServer().jwt();
http.cors();
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// https://github.com/okta/okta-spring-boot/blob/master/oauth2/src/main/java/com/okta/spring/boot/oauth/Okta.java
Okta.configureResourceServer401ResponseBody(http);
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
}
}
а также
@Configuration
@Order(200)
public class ApiWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/**")
.authorizeRequests()
.antMatchers("/public/**","/api/**").permitAll()
.and()
.authorizeRequests()
.anyRequest()
.authenticated();
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.cors();
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
}
}
любой запрос к /token/exchange
должен иметь токен, предоставленный Okta. похоже, это работает так, как я ожидал. любой запрос к /api/**
должен иметь мой собственный JWT. мой SPA отправляет настраиваемый JWT, но, пытаясь лучше понять ситуацию, я решил, что могу просто установить все /api
вызовы на allowAll и доказать, что мой фильтр Okta не мешает.
при дополнительной отладке кажется, что BearerTokenAuthenticationFilter
вызывается как вызовом /token/exchange
, так и вызовом /api/entities
. Оба раза он проверяет токен на провайдера Okta Oauth. Таким образом, он не работает с вызовом /api/entities
, который имеет мой собственный токен .... НЕ токен okta
Я так запутался