Хранение токенов JWT в веб-клиенте OAuth2 с использованием Spring Security - PullRequest
0 голосов
/ 15 мая 2019

Я реализую клиент веб-приложения OAuth2 с использованием Spring Boot 2.1.3 и Spring Security 5.1.3, который получает токены JWT с сервера авторизации через тип предоставления кода авторизации и вызывает защищенный сервер ресурсов.

Вот как выглядит реализация до сих пор:

Конфигурация безопасности и bean-компонент restTemplate, используемый для вызова защищенного ресурса:

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/").permitAll()
            .anyRequest().authenticated()
            .and()
            .oauth2Login()
            .and()
            .oauth2Client()
            .and().logout().logoutSuccessUrl("/");
    }

    @Bean
    public RestTemplate restTemplate(OAuth2AuthorizedClientService clientService) {
        RestTemplate restTemplate = new RestTemplate();
        List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
        if (CollectionUtils.isEmpty(interceptors)) {
            interceptors = new ArrayList<>();
        }
        interceptors.add(new AuthorizationHeaderInterceptor(clientService));
        restTemplate.setInterceptors(interceptors);
        return restTemplate;
    }
}

Перехватчик, который добавляет заголовок авторизации (из InMemoryOAuth2AuthorizedClientService платформы) в шаблон restTemplate:

public class AuthorizationHeaderInterceptor implements ClientHttpRequestInterceptor {

    private OAuth2AuthorizedClientService clientService;

    public AuthorizationHeaderInterceptor(OAuth2AuthorizedClientService clientService) {
        this.clientService = clientService;
    }

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] bytes, ClientHttpRequestExecution execution) throws IOException {
         Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String accessToken = null;
        if (authentication != null && authentication.getClass().isAssignableFrom(OAuth2AuthenticationToken.class)) {
            OAuth2AuthenticationToken auth = (OAuth2AuthenticationToken) authentication;
            String clientRegistrationId = auth.getAuthorizedClientRegistrationId();
            OAuth2AuthorizedClient client = clientService.loadAuthorizedClient(clientRegistrationId, auth.getName());
            accessToken = client.getAccessToken().getTokenValue();
            request.getHeaders().add("Authorization", "Bearer " + accessToken);
        }
        return execution.execute(request, bytes);
    }
}

И контроллер, который вызывает защищенный сервер ресурсов:

@Controller
@RequestMapping("/profile")
public class ProfileController {

    @Autowired
    private RestTemplate restTemplate;

    @Value("${oauth.resourceServerBase}")
    private String resourceServerBase;

    @GetMapping
    public String getProfile(Model model) {
        Profile profile = restTemplate.getForEntity(resourceServerBase + "/api/profile/", Profile.class).getBody();
        model.addAttribute("profile", profile);
        return "profile";
    }
}

Конфигурация клиента OAuth2 находится непосредственно в application.yml:

spring:
  security:
    oauth2:
      client:
        registration:
          auth-server:
            client-id: webClient
            client-secret: clientSecret
            scope: read,write
            authorization-grant-type: authorization_code
            redirect-uri: http://localhost:8081/client/login/oauth2/code/auth-server
        provider:
          auth-server:
            authorization-uri: http://localhost:8080/auth-server/oauth/authorize
            token-uri: http://localhost:8080/auth-server/oauth/token
            user-info-uri: http://localhost:8082/resource-server/users/info
            user-name-attribute: user_name

После некоторой отладки я заметил, что в конце успешного потока аутентификации через OAuth2LoginAuthtenticationFilter платформа сохраняет полученные маркеры доступа и обновления JWT в модели OAuth2AuthorizedClient в памяти через предоставленный InMemoryOAuth2AuthorizedClientService.

Я пытаюсь выяснить, как переопределить это поведение, чтобы токены могли оставаться доступными после перезапуска сервера. И также держите пользователя вошедшим в систему на основе этого.

Должен ли я просто предоставить собственную реализацию OAuth2AuthorizedClientService? Как я могу настроить Spring Security для его использования? И должна ли эта пользовательская реализация хранить токены в куки?

1 Ответ

0 голосов
/ 15 мая 2019

Должен ли я просто предоставить пользовательский OAuth2AuthorizedClientService осуществление

Я думаю, да, для решения вашего варианта использования

Как настроить Spring Security для его использования?

С Spring Doc :

Если вы хотите предоставить пользовательскую реализацию AuthorizationRequestRepository, в котором хранятся атрибуты OAuth2AuthorizationRequest в Cookie, вы можете настроить его, как показано в следующем примере:

@EnableWebSecurity
public class OAuth2ClientSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .oauth2Client()
                .authorizationCodeGrant()
                    .authorizationRequestRepository(this.cookieAuthorizationRequestRepository())
                    ...
    }

    private AuthorizationRequestRepository<OAuth2AuthorizationRequest> cookieAuthorizationRequestRepository() {
        return new HttpCookieOAuth2AuthorizationRequestRepository();
    }
}
...