Spring Boot集成Keycloak:获取已认证用户ID及令牌属性方法
获取Spring Security中已认证用户的完整信息
如果你只通过@AuthenticationPrincipal拿到用户名,说明默认的UserDetails只包含基础字段。要获取id、email等扩展属性,有以下几种实用方案:
1. 自定义UserDetails扩展属性
Spring Security的核心用户信息载体是UserDetails,默认的User类只提供username、password和权限。你需要自己实现这个接口,添加所需的自定义字段:
步骤1:创建自定义UserDetails类
public class CustomUserDetails implements UserDetails { private final Long id; private final String email; private final String username; private final String password; private final Collection<? extends GrantedAuthority> authorities; // 全参构造方法 public CustomUserDetails(Long id, String email, String username, String password, Collection<? extends GrantedAuthority> authorities) { this.id = id; this.email = email; this.username = username; this.password = password; this.authorities = authorities; } // 实现UserDetails的强制方法(按需返回布尔值,一般默认启用) @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } // 自定义字段的getter public Long getId() { return id; } public String getEmail() { return email; } // 重写父接口的getter @Override public String getUsername() { return username; } @Override public String getPassword() { return password; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } }
步骤2:在UserDetailsService中返回自定义实例
修改你的用户详情服务,从数据库查询完整用户信息,封装成CustomUserDetails:
@Service public class CustomUserDetailsService implements UserDetailsService { private final UserRepository userRepository; // 构造注入 public CustomUserDetailsService(UserRepository userRepository) { this.userRepository = userRepository; } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username) .orElseThrow(() -> new UsernameNotFoundException("用户不存在: " + username)); // 转换为自定义UserDetails,传入id、email等字段 return new CustomUserDetails( user.getId(), user.getEmail(), user.getUsername(), user.getPassword(), // 根据用户角色生成权限列表 AuthorityUtils.createAuthorityList("ROLE_" + user.getRole()) ); } }
2. 在代码中获取完整用户信息
方式1:使用@AuthenticationPrincipal直接注入
在控制器方法中,直接注入自定义的CustomUserDetails:
@GetMapping("/api/user/profile") public ResponseEntity<Map<String, Object>> getProfile(@AuthenticationPrincipal CustomUserDetails userDetails) { Map<String, Object> profile = new HashMap<>(); profile.put("id", userDetails.getId()); profile.put("username", userDetails.getUsername()); profile.put("email", userDetails.getEmail()); return ResponseEntity.ok(profile); }
方式2:从SecurityContextHolder获取
如果不在控制器中(比如服务类),可以通过上下文获取:
public void someBusinessLogic() { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null && auth.getPrincipal() instanceof CustomUserDetails) { CustomUserDetails userDetails = (CustomUserDetails) auth.getPrincipal(); Long userId = userDetails.getId(); String email = userDetails.getEmail(); // 业务逻辑处理 } }
3. 若使用JWT令牌:直接解析Claims
如果你的认证基于JWT,令牌本身包含id、email等自定义Claims,可以直接解析令牌获取:
// 从请求头提取JWT令牌(去除Bearer前缀) String token = request.getHeader("Authorization").replace("Bearer ", ""); // 解析令牌(替换为你的签名密钥) Jws<Claims> jws = Jwts.parserBuilder() .setSigningKey(Keys.hmacShaKeyFor("your-signing-secret-key".getBytes(StandardCharsets.UTF_8))) .build() .parseClaimsJws(token); Claims claims = jws.getBody(); Long userId = claims.get("id", Long.class); String email = claims.get("email", String.class); String username = claims.getSubject();
注意:确保签发JWT时已将id、email等字段写入Claims。
内容的提问来源于stack exchange,提问作者Luiz Cardoso
相关产品推荐
相关产品推荐

