对接Keycloak的Spring Boot后端配置为授权服务器支持Flutter登录咨询
前置依赖确认
确保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
相关产品推荐
相关产品推荐

