You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

对接Keycloak的Spring Boot后端配置为授权服务器支持Flutter登录咨询

Spring Authorization Server 授权码模式配置方案

前置依赖确认

确保pom.xml或build.gradle中已引入所需依赖:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-authorization-server</artifactId>
    <version>匹配Spring Boot版本</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>

核心配置步骤

1. 配置授权服务器专属过滤链

授权服务器过滤链优先级需高于普通业务过滤链,适配现有Keycloak登录逻辑:

@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
    OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
    http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
        // 不需要用户手动同意授权的话关闭同意页面
        .authorizationEndpoint(auth -> auth
            .authorizationConsentService((authorizationConsent) -> {})
        )
        .oidc(Customizer.withDefaults());
    
    // 未登录时自动跳转到Keycloak登录入口,无需自定义登录页
    http.exceptionHandling(e -> e
        .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/oauth2/authorization/keycloak"))
    );
    http.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
    return http.build();
}

2. 配置授权服务器基础参数

指定后端作为授权服务器的 issuer 地址:

@Bean
public ProviderSettings providerSettings() {
    return ProviderSettings.builder()
        // 替换为后端实际访问域名/IP端口
        .issuer("https://your-backend-domain.com")
        .build();
}

3. 注册Flutter客户端

配置允许Flutter端调用的客户端信息,适配自定义scheme回调:

@Bean
public RegisteredClientRepository registeredClientRepository() {
    RegisteredClient flutterClient = RegisteredClient.withId(UUID.randomUUID().toString())
        // 自定义客户端ID,Flutter端发起请求时需携带
        .clientId("flutter-app")
        // 移动端公开客户端无需密钥,配置为NONE
        .clientAuthenticationMethod(ClientAuthenticationMethod.NONE)
        // 开启授权码模式和刷新令牌模式
        .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
        .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
        // 替换为Flutter自定义scheme回调地址,多个可重复调用redirectUri方法添加
        .redirectUri("myflutter://login/callback")
        // 配置允许的scope
        .scope("openid")
        .scope("profile")
        // 关闭手动授权确认
        .clientSettings(ClientSettings.builder().requireAuthorizationConsent(false).build())
        // 配置令牌有效期
        .tokenSettings(TokenSettings.builder()
            .accessTokenTimeToLive(Duration.ofHours(2))
            .refreshTokenTimeToLive(Duration.ofDays(7))
            .build())
        .build();
    // 生产环境建议替换为数据库存储实现
    return new InMemoryRegisteredClientRepository(flutterClient);
}

4. 配置JWK密钥对

用于签名授权服务器签发的JWT令牌:

@Bean
public JWKSource<SecurityContext> jwkSource() {
    // 生产环境建议从配置中心/密钥服务读取固定密钥,不要每次启动生成新密钥
    KeyPair rsaKeyPair = generateRsaKeyPair();
    RSAKey rsaKey = new RSAKey.Builder((RSAPublicKey) rsaKeyPair.getPublic())
        .privateKey(rsaKeyPair.getPrivate())
        .keyID(UUID.randomUUID().toString())
        .build();
    return new ImmutableJWKSet<>(new JWKSet(rsaKey));
}

private KeyPair generateRsaKeyPair() {
    try {
        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
        generator.initialize(2048);
        return generator.generateKeyPair();
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException("生成RSA密钥失败", e);
    }
}

5. 调整原有通用过滤链

新增资源服务器配置,校验自身签发的令牌:

@Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            // 公开接口可在此处放行
            .anyRequest().authenticated()
        )
        // 原有Keycloak登录配置保留
        .oauth2Login(Customizer.withDefaults())
        // 新增资源服务器配置,校验自身签发的JWT
        .oauth2ResourceServer(oauth2 -> oauth2
            .jwt(jwt -> jwt.jwkSetUri("https://your-backend-domain.com/oauth2/jwks"))
        );
    return http.build();
}

流程验证

配置完成后完全符合你预期的登录流程:

  • Flutter端发起授权请求地址为 https://your-backend-domain.com/oauth2/authorize?response_type=code&client_id=flutter-app&redirect_uri=myflutter://login/callback&scope=openid profile&state=随机防CSRF值
  • 后端自动跳转Keycloak登录,登录完成后生成授权码回调到Flutter自定义scheme地址
  • Flutter携带授权码调用/oauth2/token接口即可获取访问令牌和刷新令牌

注意事项

  • 重定向地址必须和RegisteredClient中配置的完全一致,Spring Authorization Server默认严格匹配
  • 生产环境不要使用内存存储客户端信息和动态生成密钥,避免重启后旧令牌失效
  • 公开客户端不要配置密钥,否则令牌请求会校验失败

内容的提问来源于stack exchange,提问作者Selast Lambou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 22:57:03