Java 6 EE中基于HttpUrlConnection实现Client Credentials Bearer令牌生成
Java 6 EE 实现 Client Credentials 模式获取 OAuth2 令牌
核心实现代码
Client Credentials 模式的令牌请求需向授权服务器的 token 端点发送 POST 表单请求,以下是基于HttpUrlConnection的完整实现,依赖兼容 Java 6 的org.json包解析响应:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; import org.json.JSONObject; public class OAuth2TokenFetcher { // 替换为授权服务器的token端点URL private static final String TOKEN_ENDPOINT = "https://your-auth-server/token"; // 替换为你的client_id和client_secret private static final String CLIENT_ID = "your-client-id"; private static final String CLIENT_SECRET = "your-client-secret"; // 缓存令牌与过期时间,避免重复请求 private static String cachedAccessToken; private static long tokenExpiryTimestamp; public static String getValidToken() throws IOException { // 检查缓存令牌是否有效(提前1分钟刷新,规避请求过程中令牌过期风险) if (cachedAccessToken != null && System.currentTimeMillis() < tokenExpiryTimestamp - 60000) { return cachedAccessToken; } // 构建表单请求参数 Map<String, String> formParams = new HashMap<String, String>(); formParams.put("grant_type", "client_credentials"); formParams.put("client_id", CLIENT_ID); formParams.put("client_secret", CLIENT_SECRET); // 编码表单数据 StringBuilder postData = new StringBuilder(); for (Map.Entry<String, String> entry : formParams.entrySet()) { if (postData.length() != 0) postData.append('&'); postData.append(URLEncoder.encode(entry.getKey(), "UTF-8")); postData.append('='); postData.append(URLEncoder.encode(entry.getValue(), "UTF-8")); } byte[] postDataBytes = postData.toString().getBytes("UTF-8"); // 建立连接并发送请求 URL url = new URL(TOKEN_ENDPOINT); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); conn.setDoOutput(true); OutputStream os = conn.getOutputStream(); os.write(postDataBytes); os.flush(); os.close(); // 读取并解析响应 BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8")); StringBuilder response = new StringBuilder(); String line; while ((line = br.readLine()) != null) { response.append(line); } br.close(); conn.disconnect(); JSONObject tokenResponse = new JSONObject(response.toString()); cachedAccessToken = tokenResponse.getString("access_token"); int expiresInSeconds = tokenResponse.getInt("expires_in"); // 计算令牌过期时间戳 tokenExpiryTimestamp = System.currentTimeMillis() + (expiresInSeconds * 1000L); return cachedAccessToken; } }
关键细节说明
- 令牌缓存:通过静态变量实现简单缓存,避免频繁调用授权服务器;提前1分钟触发刷新,防止请求过程中令牌刚好过期
- 多线程适配:如果是多线程环境,需在
getValidToken()方法添加synchronized修饰符,或使用并发安全的容器存储缓存数据 - 依赖处理:Java 6无内置JSON解析工具,需引入
org.json包(推荐版本20090211,完全兼容Java 6),Maven依赖如下:<dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>20090211</version> </dependency> - Basic认证适配:若授权服务器要求将
client_id和client_secret做Base64编码后放在Authorization头,需添加以下代码:// 需引入commons-codec 1.9(兼容Java 6)的Base64工具类 String authPair = CLIENT_ID + ":" + CLIENT_SECRET; String encodedAuth = Base64.encodeBase64String(authPair.getBytes("UTF-8")); conn.setRequestProperty("Authorization", "Basic " + encodedAuth); - HTTPS证书处理:若授权服务器使用自签名证书,需将证书导入Java 6的信任库,或添加自定义信任管理器绕过证书校验(仅测试环境使用)
异常处理建议
实际项目中需捕获IOException、JSONException等异常,根据业务场景实现重试逻辑或错误告警,避免因令牌获取失败导致业务中断
内容的提问来源于stack exchange,提问作者Dinu VA
相关产品推荐
相关产品推荐

