如何在Java REST端点通过Keycloak与Bearer令牌实现用户认证
Hey there! 我来一步步帮你理清在Java REST端点中用Keycloak和Bearer令牌实现用户认证的完整流程,咱们分阶段拆解,每个环节都给你具体的实现思路和代码示例。
在Java REST端点中用Keycloak + Bearer令牌实现用户认证的完整流程
一、客户端通过用户名密码获取Bearer令牌(JWT)
首先客户端要向Keycloak的令牌端点发起请求,用用户名密码换取JWT格式的Bearer令牌。这里给你两种实现方式:
1. 用curl快速测试
curl -X POST \ http://your-keycloak-domain/auth/realms/your-realm/protocol/openid-connect/token \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'username=your-username&password=your-password&grant_type=password&client_id=your-client-id&client_secret=your-client-secret'
返回响应里的access_token就是你要的Bearer令牌,它确实是JWT格式——你可以用JWT解析工具查看里面的用户ID、角色、过期时间等核心信息。
2. Java客户端代码示例(基于OkHttp)
OkHttpClient client = new OkHttpClient(); RequestBody formBody = new FormBody.Builder() .add("username", "your-username") .add("password", "your-password") .add("grant_type", "password") .add("client_id", "your-client-id") .add("client_secret", "your-client-secret") .build(); Request request = new Request.Builder() .url("http://your-keycloak-domain/auth/realms/your-realm/protocol/openid-connect/token") .post(formBody) .build(); try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); String responseBody = response.body().string(); // 用Jackson解析JSON获取access_token ObjectMapper mapper = new ObjectMapper(); JsonNode jsonNode = mapper.readTree(responseBody); String accessToken = jsonNode.get("access_token").asText(); System.out.println("Bearer Token: " + accessToken); }
二、JWT令牌的验证方式
拿到令牌后,REST端点需要验证它的有效性,主要有两种靠谱的方案:
1. 本地验证(推荐,性能更高)
Keycloak会公开一个公钥端点,你可以获取公钥来本地验证JWT的合法性:
- 公钥地址:
http://your-keycloak-domain/auth/realms/your-realm/protocol/openid-connect/certs - 核心验证逻辑:
- 解析JWT头部的
kid(密钥ID),匹配对应的公钥 - 验证签名是否合法(确保令牌未被篡改)
- 检查令牌是否过期(
exp字段) - 验证受众(
aud字段)是否匹配你的客户端ID - 确认发行者(
iss字段)是你的Keycloak Realm地址
- 解析JWT头部的
2. 远程调用Keycloak Introspect端点验证
如果不想本地管理公钥,可以调用Keycloak的 introspect 端点来验证令牌有效性:
curl -X POST \ http://your-keycloak-domain/auth/realms/your-realm/protocol/openid-connect/token/introspect \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'token=your-access-token&client_id=your-client-id&client_secret=your-client-secret'
返回响应里active字段为true则表示令牌有效,同时还会返回用户的相关信息。不过这种方式每次请求都要调用Keycloak,性能会差一些,适合小流量场景。
三、Java REST端点实现令牌校验与用户认证
下面给你两种主流框架的实现方式,都是基于Keycloak官方依赖,不用自己手写复杂的验证逻辑:
1. Spring Boot + Spring Security(最常用)
第一步:添加依赖(pom.xml)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-spring-boot-starter</artifactId> <version>22.0.5</version> <!-- 建议使用最新稳定版 --> </dependency>
第二步:配置application.yml
keycloak: realm: your-realm auth-server-url: http://your-keycloak-domain/auth resource: your-client-id credentials: secret: your-client-secret use-resource-role-mappings: true bearer-only: true spring: security: oauth2: resourceserver: jwt: issuer-uri: http://your-keycloak-domain/auth/realms/your-realm
第三步:编写REST端点
import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class UserController { @GetMapping("/api/user/me") public String getCurrentUser(@AuthenticationPrincipal Jwt jwt) { // 从JWT中提取用户核心信息 String username = jwt.getClaim("preferred_username"); String userId = jwt.getClaim("sub"); return String.format("当前认证用户:%s,用户ID:%s", username, userId); } }
Spring Security会自动帮你处理Bearer令牌的验证,@AuthenticationPrincipal可以直接注入已验证的JWT对象,轻松获取用户的Principal信息。
2. JAX-RS(Jersey) + Keycloak Adapter
第一步:添加依赖(pom.xml)
<dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-jaxrs-adapter</artifactId> <version>22.0.5</version> </dependency> <dependency> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-servlet</artifactId> <version>3.1.5</version> </dependency>
第二步:配置Keycloak(web.xml)
<context-param> <param-name>keycloak.config.file</param-name> <param-value>WEB-INF/keycloak.json</param-value> </context-param> <listener> <listener-class>org.keycloak.adapters.servlet.KeycloakServletContextListener</listener-class> </listener> <filter> <filter-name>Keycloak Authentication Filter</filter-name> <filter-class>org.keycloak.adapters.servlet.KeycloakOIDCFilter</filter-class> </filter> <filter-mapping> <filter-name>Keycloak Authentication Filter</filter-name> <url-pattern>/api/*</url-pattern> </filter-mapping>
keycloak.json配置示例:
{ "realm": "your-realm", "auth-server-url": "http://your-keycloak-domain/auth", "resource": "your-client-id", "credentials": { "secret": "your-client-secret" }, "bearer-only": true }
第三步:编写JAX-RS端点
import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.core.Context; import javax.ws.rs.core.SecurityContext; import java.security.Principal; @Path("/api/user") public class UserResource { @GET @Path("/me") public String getCurrentUser(@Context SecurityContext securityContext) { Principal principal = securityContext.getUserPrincipal(); return String.format("当前认证用户:%s", principal.getName()); } }
Keycloak适配器会自动完成Bearer令牌的验证,SecurityContext里就能直接拿到已认证的Principal对象。
内容的提问来源于stack exchange,提问作者XandruDavid
相关产品推荐
相关产品推荐

