В настоящее время я работаю над проектом, в котором мы хотим, чтобы пользователь входил в систему через Facebook и других поставщиков OAuth2. Кроме того, REST API должен быть без гражданства. Поэтому не следует создавать/использовать файлы cookie/jsessionid. Для авторизации через API API выдает JWT после успешного входа через Facebook. Веб-приложение, использующее остальные API, построено с использованием AgularJS и сателлайзера. Я сократил свой код до минимального примера, доступного на github.
Идея рабочего процесса:
- Пользователь заходит на сайт, выбирает "войти через facebook"
- Веб-приложение открывает всплывающее окно со страницей входа в facebook.
- Пользователь входит в систему, принимает и перенаправляет facebook на веб-приложение
- Веб-приложение получает токен от Facebook и использует его для входа в остальные API (GET /login/facebook?code=XXXXXXXXXXXXXXXXXXX).
- Остальные API возвращают JWT.
- Веб-приложение использует JWT для авторизации остальных API для любых дальнейших запросов.
Пока работает
- Веб-приложение может обрабатывать шаги с 1 по 4
- Остальные API могут обрабатывать шаги 5 и 6, если вы используете перенаправление, которое вы получаете от OAuth2ClientContextFilter, выполняя GET на «/login/facebook» без параметра кода. (Это перенаправление идет на facebook, вы входите в систему, вы снова перенаправляетесь на API.)
- Остальные API не имеют состояния, jsessionid/cookies не создаются/не требуются (отключен csrf и используется SessionCreationPolicy.STATELESS). За исключением вызова «login/facebook», здесь все еще создается jsessionid.
Проблема
Комбинация веб-приложения и остального API-вызова «login/facebook?code=XXX» не работает. Я узнал, что когда вы выполняете GET «логин/facebook», вы будете перенаправлены на facebook с дополнительным параметром состояния, прикрепленным к URL-адресу. Кроме того, этот параметр состояния также добавляется, когда facebook перенаправляет обратно на API. Судя по тому, что я нашел в Интернете, это похоже на защиту от CSRF, верно? И я предполагаю, что этот материал также создает файл cookie jsessionid?
Вопросы
- Является ли рабочий процесс, представленный выше, разумной идеей?
- Нужна ли мне эта защита CSRF в моем случае использования?
- Как я могу отключить это поведение? Я имею в виду, что я использовал SessionCreationPolicy.STATELESS, но Spring по-прежнему создает сеанс с jsessionid. Как я могу создать API для отдыха без сохранения состояния? (По крайней мере, в отношении файлов cookie...)
- Это правильный способ сделать это? Или я что-то упускаю?
Пример кода
Как уже было сказано, полный рабочий минимальный пример я выложил на GitHub. Здесь я опубликую только (надеюсь) самую важную часть WebSecurityConfigurerAdapter. полный файл здесь.
@EnableOAuth2Client
@Configuration
public class OAuth2ClientConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
private OAuth2ClientContext oAuth2ClientContext;
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).enableSessionUrlRewriting(false).and()
.antMatcher("/**").authorizeRequests()
.antMatchers("/login/**").permitAll()
.anyRequest().authenticated().and()
.exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint()).and()
.addFilterBefore(statelessJwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(createSsoFilter(facebook(), facebookSuccessHandler(), "/login/facebook"), BasicAuthenticationFilter.class);
}
private OAuth2ClientAuthenticationProcessingFilter createSsoFilter(ClientResourceDetails clientDetails, AuthenticationSuccessHandler successHandler, String path) {
OAuth2ClientAuthenticationProcessingFilter ssoFilter = new OAuth2ClientAuthenticationProcessingFilter(path);
ssoFilter.setAllowSessionCreation(false);
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(clientDetails.getClient(), oAuth2ClientContext);
ssoFilter.setRestTemplate(restTemplate);
ssoFilter.setTokenServices(new UserInfoTokenServices(clientDetails.getResource().getUserInfoUri(), clientDetails.getClient().getClientId()));
ssoFilter.setAuthenticationSuccessHandler(successHandler);
return ssoFilter;
}
@Bean // handles the redirect to facebook
public FilterRegistrationBean oAuth2ClientFilterRegistration(OAuth2ClientContextFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(filter);
registration.setOrder(-100);
return registration;
}
Большое спасибо за вашу помощь!