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

Spring Boot集成Keycloak仅获匿名令牌,如何获取登录用户名?

解决Keycloak保护Spring Boot REST API时获取当前用户名为anonymousUser的问题

问题描述

此前使用标准用户详情服务完成用户认证,切换到Keycloak后,调用以下代码始终返回anonymousUser,且Spring Boot仅识别[ANONYMOUS_USER]角色:

public static String getCurrentUsername() { 
    return (String) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 
}

核心原因

Spring Security未正确拦截并解析Keycloak的认证令牌,导致请求被当作匿名请求处理。

正确配置步骤

1. 依赖配置(Maven)

确保引入匹配Spring Boot版本的Keycloak Starter依赖:

<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-spring-boot-starter</artifactId>
    <version>${keycloak.version}</version>
</dependency>

2. 应用配置(application.yml)

配置与Keycloak后台一致的客户端信息:

keycloak:
  auth-server-url: http://localhost:8080/auth
  realm: 你的领域名称
  resource: 你的客户端ID
  credentials:
    secret: 你的客户端密钥
  use-resource-role-mappings: true
  bearer-only: true
  ssl-required: external
  • bearer-only: true:服务端仅接受Bearer令牌,不做重定向认证
  • use-resource-role-mappings: true:启用客户端角色映射

3. Spring Security配置类

创建配置类确保请求被Keycloak认证过滤器拦截:

import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;

@KeycloakConfiguration
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        KeycloakAuthenticationProvider authProvider = keycloakAuthenticationProvider();
        // 可选:统一角色前缀,按需调整
        authProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
        auth.authenticationProvider(authProvider);
    }

    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        // REST API无需会话,使用空会话策略
        return new NullAuthenticatedSessionStrategy();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http.csrf().disable()
            .authorizeRequests()
            // 配置需要认证的接口路径,替换为实际业务路径
            .antMatchers("/api/**").authenticated()
            .anyRequest().permitAll();
    }
}

4. 调整用户名获取代码

原代码中getPrincipal()返回的是KeycloakAuthenticationToken对象,需调整逻辑提取用户名:

import org.keycloak.KeycloakPrincipal;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;

public static String getCurrentUsername() {
    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    if (principal instanceof KeycloakAuthenticationToken) {
        KeycloakPrincipal<?> keycloakPrincipal = (KeycloakPrincipal<?>) ((KeycloakAuthenticationToken) principal).getPrincipal();
        // 获取Keycloak用户的首选用户名
        return keycloakPrincipal.getKeycloakSecurityContext().getToken().getPreferredUsername();
    }
    // 兼容匿名或其他认证场景
    return principal.toString();
}

关键检查项

  • 确认请求头携带有效Authorization: Bearer <token>令牌
  • 用JWT工具解码令牌,验证包含preferred_username字段
  • 检查Keycloak客户端Access Type是否设为confidential(使用客户端密钥时)
  • 确保Keycloak客户端已启用,且用户已分配对应客户端角色

内容的提问来源于stack exchange,提问作者jonathan-lee-devel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 22:15:36