java从azure中读取用户信息
以下是用 Java 从 Azure AD 获取用户信息的完整实现方案,使用 Spring Boot 框架和 Microsoft 身份验证库 (MSAL):
1. 添加 Maven 依赖
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Azure AD MSAL -->
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>msal4j</artifactId>
<version>1.13.3</version>
</dependency>
<!-- JWT 处理 -->
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>9.25</version>
</dependency>
<!-- HTTP 客户端 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
</dependencies>
2. 配置 Azure AD 参数
在 application.properties 中:
# Azure AD 配置
azure.client-id=your_client_id
azure.client-secret=your_client_secret
azure.tenant-id=your_tenant_id
azure.redirect-uri=https://your-app.com/auth/redirect
azure.scope=openid profile User.Read
3. 控制器实现
import com.microsoft.aad.msal4j.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.net.MalformedURLException;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
@RestController
public class AuthController {
@Value("${azure.client-id}")
private String clientId;
@Value("${azure.client-secret}")
private String clientSecret;
@Value("${azure.tenant-id}")
private String tenantId;
@Value("${azure.redirect-uri}")
private String redirectUri;
@Value("${azure.scope}")
private String scope;
// 第一步:生成登录URL
@GetMapping("/login")
public Map<String, String> login() throws MalformedURLException {
String authUrl = getAuthUrl();
return Collections.singletonMap("loginUrl", authUrl);
}
// 第二步:处理回调
@GetMapping("/auth/redirect")
public Map<String, Object> handleRedirect(
@RequestParam("code") String authCode,
@RequestParam("state") String state
) throws Exception {
// 使用授权码获取令牌
IAuthenticationResult result = acquireToken(authCode);
// 获取用户信息
Map<String, Object> userInfo = getUserInfo(result.accessToken());
// 返回用户信息
Map<String, Object> response = new HashMap<>();
response.put("id_token_claims", result.idToken());
response.put("user_info", userInfo);
return response;
}
// 生成认证URL
private String getAuthUrl() throws MalformedURLException {
ConfidentialClientApplication app = ConfidentialClientApplication.builder(
clientId, ClientCredentialFactory.createFromSecret(clientSecret))
.authority("https://login.microsoftonline.com/" + tenantId)
.build();
AuthorizationCodeParameters parameters = AuthorizationCodeParameters.builder(
authCode,
new URI(redirectUri)
).scopes(Collections.singleton(scope))
.build();
String authorizationUrl = app.getAuthorizationRequestUrl(
AuthorizationRequestUrlParameters
.builder(redirectUri, Collections.singleton(scope))
.build()
).toString();
return authorizationUrl;
}
// 使用授权码获取令牌
private IAuthenticationResult acquireToken(String authCode)
throws MalformedURLException, ExecutionException, InterruptedException {
ConfidentialClientApplication app = ConfidentialClientApplication.builder(
clientId, ClientCredentialFactory.createFromSecret(clientSecret))
.authority("https://login.microsoftonline.com/" + tenantId)
.build();
AuthorizationCodeParameters parameters = AuthorizationCodeParameters.builder(
authCode,
new URI(redirectUri)
).scopes(Collections.singleton(scope))
.build();
return app.acquireToken(parameters).get();
}
// 使用访问令牌获取用户信息
private Map<String, Object> getUserInfo(String accessToken) {
String graphEndpoint = "https://graph.microsoft.com/v1.0/me";
// 使用HttpClient调用Graph API
// 实际实现需要添加错误处理和JSON解析
return fetchUserDataFromGraph(graphEndpoint, accessToken);
}
// 调用Microsoft Graph API的实现
private Map<String, Object> fetchUserDataFromGraph(String endpoint, String accessToken) {
// 这里使用HttpClient简化实现
// 实际项目使用RestTemplate或WebClient
HttpGet request = new HttpGet(endpoint);
request.setHeader("Authorization", "Bearer " + accessToken);
try (CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(request)) {
String json = EntityUtils.toString(response.getEntity());
return new Gson().fromJson(json, new TypeToken<Map<String, Object>>(){}.getType());
} catch (Exception e) {
throw new RuntimeException("Failed to fetch user info", e);
}
}
}
4. 安全配置类 (可选)
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.jwk.source.RemoteJWKSet;
import com.nimbusds.jose.proc.JWSVerificationKeySelector;
import com.nimbusds.jose.proc.SecurityContext;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.proc.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.net.MalformedURLException;
import java.net.URL;
@Configuration
public class SecurityConfig {
@Value("${azure.tenant-id}")
private String tenantId;
// 配置JWT验证器
@Bean
public ConfigurableJWTProcessor<SecurityContext> jwtProcessor()
throws MalformedURLException {
// Azure AD JWKS端点
String jwksUrl = String.format(
"https://login.microsoftonline.com/%s/discovery/v2.0/keys",
tenantId
);
// 设置JWT处理器
DefaultJWTProcessor<SecurityContext> jwtProcessor =
new DefaultJWTProcessor<>();
// 配置JWK来源
JWKSource<SecurityContext> keySource =
new RemoteJWKSet<>(new URL(jwksUrl));
// 配置签名验证
JWSAlgorithm expectedJWSAlg = JWSAlgorithm.RS256;
JWSVerificationKeySelector<SecurityContext> keySelector =
new JWSVerificationKeySelector<>(expectedJWSAlg, keySource);
jwtProcessor.setJWSKeySelector(keySelector);
// 设置JWT声明验证器
jwtProcessor.setJWTClaimsSetVerifier(new DefaultJWTClaimsVerifier<>(
new JWTClaimsSet.Builder().build(),
new HashSet<>(Arrays.asList("sub", "aud", "exp", "iat"))));
return jwtProcessor;
}
}