如何在Vaadin+Spring项目中获取Keycloak的Access Token调用FastAPI?
Vaadin + Keycloak 获取Access Token调用FastAPI解决方案
问题背景
已基于Spring Security实现Vaadin应用通过Keycloak登录,能获取OidcUser对象,但仅能访问ID Token,需要获取Access Token调用后端FastAPI,同时确认现有认证流程是否正确。
现有认证流程理解:
- 用户尝试登录Vaadin UI
- 重定向至Keycloak指定Realm完成认证
- 认证成功后用户登录Vaadin应用
- 应用使用用户的Access Token调用FastAPI加载数据
- FastAPI验证Token有效性后返回用户对应租户的数据
流程正确性确认
你的流程完全正确,符合OAuth2授权码流的标准逻辑。需要明确的是:OidcUser本身不直接存储Access Token,但Spring Security会将Access Token与当前用户的认证信息绑定,可通过Spring提供的工具类获取。
获取Access Token的实现方法
1. 注入OAuth2AuthorizedClientService获取Token
Spring Security的OAuth2AuthorizedClientService可加载当前用户的授权客户端信息,其中包含有效的Access Token。
示例服务类:
import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService; import org.springframework.security.oauth2.core.oidc.user.OidcUser; import org.springframework.stereotype.Service; import org.springframework.web.reactive.function.client.WebClient; @Service public class FastApiClient { private final OAuth2AuthorizedClientService authorizedClientService; private final WebClient webClient; public FastApiClient(OAuth2AuthorizedClientService authorizedClientService) { this.authorizedClientService = authorizedClientService; this.webClient = WebClient.create("http://your-fastapi-base-url"); } public String fetchUserData(@AuthenticationPrincipal OidcUser currentUser) { // 加载Keycloak授权客户端,clientId需与配置文件中的一致 OAuth2AuthorizedClient authorizedClient = authorizedClientService.loadAuthorizedClient( "keycloak", currentUser.getName()); // 获取Access Token字符串 String accessToken = authorizedClient.getAccessToken().getTokenValue(); // 调用FastAPI,携带Bearer Token请求头 return webClient.get() .uri("/api/user/data") .headers(headers -> headers.setBearerAuth(accessToken)) .retrieve() .bodyToMono(String.class) .block(); } }
2. 配置OAuth2客户端参数
确保application.properties中配置正确的Keycloak客户端信息,尤其是scope需包含FastAPI所需的权限范围:
# Keycloak客户端配置 spring.security.oauth2.client.registration.keycloak.client-id=vaadin-app-client spring.security.oauth2.client.registration.keycloak.client-secret=your-client-secret spring.security.oauth2.client.registration.keycloak.scope=openid,profile,api-access # api-access为FastAPI对应的scope spring.security.oauth2.client.provider.keycloak.issuer-uri=http://your-keycloak-domain/realms/your-realm-name
3. 在Vaadin View中调用API
在Vaadin视图中注入服务类,获取当前用户并调用FastAPI:
import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.textfield.TextArea; import com.vaadin.flow.router.Route; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.oauth2.core.oidc.user.OidcUser; @Route("user-dashboard") public class UserDashboardView extends VerticalLayout { private final FastApiClient fastApiClient; public UserDashboardView(FastApiClient fastApiClient) { this.fastApiClient = fastApiClient; TextArea resultArea = new TextArea("API返回数据"); Button fetchButton = new Button("获取我的数据", event -> { OidcUser currentUser = getCurrentUser(); String apiResult = fastApiClient.fetchUserData(currentUser); resultArea.setValue(apiResult); }); add(fetchButton, resultArea); } private OidcUser getCurrentUser() { return (OidcUser) getUI().get().getSession().getAttribute("SPRING_SECURITY_CONTEXT") .getAuthentication().getPrincipal(); } }
关键注意事项
- Token自动刷新:Spring Security会自动处理Access Token的过期刷新(前提是Keycloak颁发了Refresh Token),
OAuth2AuthorizedClientService返回的始终是有效Token。 - FastAPI Token验证:FastAPI需配置Keycloak的JWKS端点(
{keycloak-issuer-uri}/protocol/openid-connect/certs)来验证Token的签名和有效性,同时解析Token中的角色/scope声明实现权限控制。 - Scope权限匹配:确保Keycloak客户端配置的scope与FastAPI要求的一致,否则Access Token会缺少必要的权限声明,导致API调用被拒绝。
内容的提问来源于stack exchange,提问作者Loahrs
相关产品推荐
相关产品推荐

