你可以尝试做这样的事情-
第 1 步:加载证书
object CertUtil {
private val DIGEST_ALGORITHM = "SHA-1"
private val keyStore = KeyStore.getInstance("PKCS12")
def loadCertificate(certLocation: String, pwdLocation: String): Certificate = {
keyStore.load(new FileInputStream(new File(certLocation)), readPassword(pwdLocation).toCharArray)
keyStore.getCertificate(keyStore.aliases().nextElement())
}
第 2 步:创建 client_assertion
Client Assertion 是使用您证书的私钥签名的 jwt,由 AAD 服务器用于在颁发令牌之前对您的请求执行身份检查。
def createJWTToken(aadURL: String, clientId: String, scope: String, key: Key, certThumbPrint: String): String =
Jwts.builder()
.claim(Claims.AUDIENCE, aadURL)
.claim(Claims.ISSUER, clientId)
.claim(Claims.SUBJECT, clientId)
.claim(Claims.ID, UUID.randomUUID.toString)
.claim(Claims.EXPIRATION, NOW + ONE_HOUR)
.claim(Claims.NOT_BEFORE, NOW)
.setHeaderParam(X5THUMBPRINT, certThumbPrint)
.signWith(key)
.compact()
第 3 步:使用客户端断言令牌创建 Post Payload
包含要以 url 编码形式提交给 AAD 服务的 clientId、Scope、GrantType、Client Assertion 的 Payload。
def getPayload(request: AADRequest): String = {
val token = JWTCreator
.createJWTToken(
aadURL(request.tenentId),
request.clientId,
getScope(request.appId),
CertUtil.getPrivateKey,
CertUtil.getThumbPrint
)
Map(
(CLIENT_ID, request.clientId),
(SCOPE, getScope(request.appId)),
(GRANT_TYPE, GRANT_TYPE_VAL),
(CLIENT_ASSERTION_TYPE, CLIENT_ASSERTION_TYPE_VAL),
(CLIENT_ASSERTION, token))
.map(_.productIterator.mkString("="))
.mkString("&")
}
第 4 步:调用 Azure AD Post API
private def aadURL(tenentId: String) = s"${BASE_URL}${tenentId}${PATH}"
private def getScope(appId: String) = s"api://${appId}/.default"
def getAADToken(request: AADRequest): Future[String] = {
CertUtil.loadCertificate(request.certPath, request.pwdPath)
doPost(toPostRequest(aadURL(request.tenentId),
getHttpEntity(request)))
.flatMap(response => Unmarshal(response.entity).to[String])
.map(s => mapper.readValue(s, classOf[AADResponse]).accessToken)
}
编辑
Maven 依赖项 -
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.7.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-scala_${scala.version.major}</artifactId>
<version>2.6.7.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.typesafe.akka/akka-actor -->
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-actor_2.12</artifactId>
<version>2.6.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.typesafe.akka/akka-stream -->
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-stream_2.12</artifactId>
<version>2.6.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.typesafe.akka/akka-http -->
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-http_2.12</artifactId>
<version>10.2.3</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.1</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.1</version>
<scope>runtime</scope>
</dependency>