Spring Security 如何配置RestTemplate使用浏览器的session进行API调用?

bsxbgnwa  于 2023-08-05  发布在  Spring
关注(0)|答案(1)|浏览(192)

我有一个用Sping Boot RestControllers编写的API,用keycloak保护。我正在一个单独的Sping Boot 应用程序中编写一个Thymeleaf客户端来使用这个API。客户端的浏览器成功登录到keycloak,并且在控制器上,我能够通过@AuthenticationPrincipal访问OAuth2 AuthenticatedPrincipal。
如何配置RestTemplate以使用这个已经建立的信任关系,而不是为每个RestTemplate建立一个新的信任关系?
下面的代码是使用在浏览器中经过身份验证的用户成功地通过API进行身份验证的代码。
控制器

  1. @Controller
  2. @RequestMapping("/product")
  3. public class ProductController {
  4. private final RestTemplate restTemplate;
  5. private final ProductService productService;
  6. private final ClientRegistrationRepository clientRegistrationRepository;
  7. // only needed to validate registration during debug
  8. private final InMemoryClientRegistrationRepository clientRegistrationRepository;
  9. public ProductController(RestTemplate restTemplate, ProductService productService,
  10. ClientRegistrationRepository clientRegistrationRepository,
  11. InMemoryClientRegistrationRepository clientRegistrationRepository) {
  12. this.restTemplate = restTemplate;
  13. this.productService = productService;
  14. this.clientRegistrationRepository = clientRegistrationRepository;
  15. this.clientRegistrationRepository = clientRegistrationRepository;
  16. }
  17. @GetMapping("")
  18. @PreAuthorize("isAuthenticated()")
  19. public String index(@AuthenticationPrincipal OAuth2AuthenticatedPrincipal principal,
  20. Authentication auth,
  21. HttpServletRequest servletRequest,
  22. Model model) {
  23. OAuth2AuthorizedClient accessToken = clientRepository.loadAuthorizedClient("keycloak-confidential-user",
  24. auth, servletRequest);
  25. log.debug("accessToken is null [{}]", accessToken == null);
  26. model.addAttribute("products",
  27. productService.getProductWithDetailsForUser(UUID.fromString(principal.getName()), accessToken));
  28. return "product/list";
  29. }

字符串
服务方式

  1. public List<ProductListInfo> getProductWithDetailsForUser(UUID userId, String token) {
  2. List<ProductListInfo> products = productRepository.findByUser_UniqueUserOrderByNameAsc(userId,
  3. Pageable.ofSize(10));
  4. if(token != null) {
  5. header.setBearerAuth(token);
  6. for (ProductListInfo product : products) {
  7. ProductPublicDto publicData = restTemplate.exchange(
  8. "https://localhost:8043/product/%s/public".formatted(product.getProductId()),
  9. HttpMethod.GET, new HttpEntity<>(header), ProductPublicDto.class).getBody();
  10. productMapper.partialUpdateDetails(publicData product);
  11. }
  12. }
  13. return products;
  14. }


pom.xml片段

  1. ...
  2. <dependencies>
  3. <dependency>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-starter-oauth2-client</artifactId>
  6. </dependency>
  7. ...

krcsximq

krcsximq1#

如果您的应用程序使用Thymeleaf控制器配置为OAuth2客户端,则其他使用REST API的应用程序应配置为OAuth2资源服务器,并且可能是无状态的(无会话)。
对资源服务器的请求使用承载访问令牌而不是会话进行授权。在客户端中,配置REST客户端(RestTemplate并不是很流行,您可能会看一下WebClient@FeignClient)来设置一个Authorization头,其中包含一个Bearer字符串,其中包含从OAuth2AuthorizedClient获得的访问令牌。(您可以在OAuth2客户端控制器中自动连接OAuth2AuthorizedClientRepository,并查询它以检索所需的OAuth2AuthorizedClient)。
我有一个完整的工作示例WebClient(不是RestTemplate,对不起)there。在本教程中,客户端和资源服务器部分合并在单个应用程序中,但这两个部分具有不同的SecurityFilterChain bean,并与REST客户端通信。内部请求使用Bearer访问令牌进行授权,这可能是您所需要的。

相关问题