调用Microsoft Graph API返回400错误,Graph Explorer可正常运行求助
调用Microsoft Graph /v1.0/me接口返回400 Bad Request问题
使用Azure Active Directory认证调用Microsoft Graph API的/v1.0/me接口时,返回HTTP 400 Bad Request错误。同一个客户端ID在Graph Explorer中能够成功调用,但本地Java代码始终报错。以下是相关代码及错误信息:
获取令牌代码
IClientCredential credential = ClientCredentialFactory.createFromSecret(CLIENT_SECRET); ConfidentialClientApplication cca = ConfidentialClientApplication.builder(CLIENT_ID, credential).authority(AUTHORITY).build(); IAuthenticationResult result; try { SilentParameters silentParameters = SilentParameters.builder(Collections.singleton(SCOPE)).build(); // 尝试静默获取令牌,这里会失败因为缓存中没有对应令牌 result = cca.acquireTokenSilently(silentParameters).join(); } catch (Exception ex) { if (ex.getCause() instanceof MsalException) { ClientCredentialParameters parameters = ClientCredentialParameters.builder(Collections.singleton(SCOPE)).build(); // 获取令牌,成功后会在控制台打印令牌信息 result = cca.acquireToken(parameters).join(); } else { // 处理其他异常 throw ex; } } System.out.println(result.accessToken());
调用Graph API代码
URL url = new URL("https://graph.microsoft.com/v1.0/me"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setRequestProperty("Authorization", "Bearer " + accessToken); conn.setRequestProperty("Accept","application/json"); int httpResponseCode = conn.getResponseCode(); if(httpResponseCode == HTTPResponse.SC_OK) { StringBuilder response; try(BufferedReader in = new BufferedReader( new InputStreamReader(conn.getInputStream())){ String inputLine; response = new StringBuilder(); while (( inputLine = in.readLine()) != null) { response.append(inputLine); } } return response.toString(); } else { return String.format("Connection returned HTTP code: %s with message: %s", httpResponseCode, conn.getResponseMessage()); }
错误信息:Connection returned HTTP code: 400 with message: Bad Request
问题原因
你当前使用的是客户端凭证流(Client Credential Flow)获取令牌,但/v1.0/me接口的设计是获取当前登录用户的信息,要求令牌必须关联具体用户。而客户端凭证流是服务对服务的认证方式,获取的令牌无用户关联,因此调用/me接口会返回400错误。
Graph Explorer能成功调用,是因为它采用的是授权码流(Authorization Code Flow),会先引导用户登录,获取的令牌绑定了具体用户身份,符合/me接口的调用要求。
解决方案
方案一:切换为授权码流获取用户令牌
如果业务需要访问当前用户的信息,需将认证方式改为授权码流:
- 在Azure AD应用注册页面,添加重定向URI(如
http://localhost:8080/redirect),并启用"授权码流"。 - 修改令牌获取代码示例(Web应用场景):
ConfidentialClientApplication cca = ConfidentialClientApplication.builder(CLIENT_ID, credential) .authority(AUTHORITY) .build(); Set<String> scopes = new HashSet<>(Arrays.asList("User.Read")); // authorizationCode是用户登录后回调返回的授权码 AuthorizationCodeParameters parameters = AuthorizationCodeParameters.builder(authorizationCode, new URI(REDIRECT_URI)) .scopes(scopes) .build(); IAuthenticationResult result = cca.acquireToken(parameters).join();
方案二:改用/users/{user-id}接口
如果业务无需关联当前登录用户,仅需获取特定用户信息,可在客户端凭证流基础上,调用/v1.0/users/{user-id}接口,同时确保Azure AD应用已添加对应的应用权限(如User.Read.All)。
修改API调用代码:
// 替换为目标用户的ID或用户主体名称(UPN) String userId = "target-user@your-domain.com"; URL url = new URL("https://graph.microsoft.com/v1.0/users/" + userId);
内容的提问来源于stack exchange,提问作者elvaone
相关产品推荐
相关产品推荐

