本文檔提供阿里雲IDaaS(EIAM)中M2M用戶端令牌調用樣本,詳細說明如何通過OAuth 2.0用戶端模式擷取存取權杖,並調用API實現系統間安全認證。
調用樣本
認證方式:client_secret_basic
要求方法:POST
header頭參數:
參數名
類型
說明
樣本
Authorization
String
該參數值格式為 clientId 和 clientSecret 合并後的 base64 編碼格式,合并格式為:clientId:clientSecret。
YXBwX201ZG9vemVzbm81Mmtxxxxxxxxx
Content-Type
String
固定值:application/x-www-form-urlencoded
application/x-www-form-urlencoded
請求參數:
參數名
類型
說明
樣本
grant_type
String
固定值:client_credentials。
client_credentials
scope
String
可以根據scope來進行許可權申請,String類型空格拼接。格式為:resourceServerIdentifier+"|"+scope,如:
resourceServerIdentifier是:api://api.xxxxx.com,scope是:read:file
最終返回結果為:api://api.xxxxx.com|read:file
擷取當前client已經授權的所有scopes,使用:{resourceServerIdentifier}|.all
api://api.xxxxx.com|read:file
client_id
string
應用ID。
請求樣本:
curl --location --request POST 'https://XXXX.aliyunidaas.com/api/v2/iauths_system/oauth2/token' \ --header 'Authorization: Basic YXBwX201ZG9vemVxxxxxx' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'api://api.xxxxx.com|read:file'返回參數:
參數名
類型
是否可為空白
描述
access_token
String
否
token值。
expires_in
Long
否
到期時間長度,單位秒。
expires_at
Long
否
到期時間,unix時間戳記,單位秒。
token_type
String
否
token類型。
返回樣本:
{ "token_type": "Bearer", "access_token": "AT8csE2se******xxHUG", "expires_in": 3600, "expires_at": 1733710213 }
認證方式:client_secret_post
要求方法:POST
header頭參數:
參數名
類型
說明
樣本
Content-Type
String
固定值:application/x-www-form-urlencoded
application/x-www-form-urlencoded
請求參數:
參數名
類型
說明
樣本
grant_type
String
固定值:client_credentials。
client_credentials
client_id
String
應用id。
client_secret
String
應用密鑰。
scope
String
可以根據scope來進行許可權申請,String類型空格拼接。格式為:resourceServerIdentifier+"|"+scope,如:
resourceServerIdentifier是:api://api.xxxxx.com,scope是:read:file
最終返回結果為:api://api.xxxxx.com|read:file
擷取當前client已經授權的所有scopes,使用:{resourceServerIdentifier}|.all
api://api.xxxxx.com|read:file
請求樣本:
curl --location --request POST 'https://XXXX.aliyunidaas.com/api/v2/iauths_system/oauth2/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'client_id=app_m5doozesno52kbqrqpw3XXXX' \ --data-urlencode 'client_secret=CS5v3F4Cy8hyDmFPJtAuyHDTUdR8i88GcgcXXXXX' \ --data-urlencode 'scope=api://api.xxxxx.com|read:file'返回樣本:
{ "token_type": "Bearer", "access_token": "AT8csE2se******7NHBkxxHUG", "expires_in": 3600, "expires_at": 1733710213 }
認證方式:client_secret_jwt
要求方法:POST
header頭參數:
參數名
類型
說明
樣本
Content-Type
String
固定值:application/x-www-form-urlencoded
application/x-www-form-urlencoded
請求參數:
參數名
類型
說明
樣本
grant_type
String
固定值:client_credentials。
client_credentials
client_id
String
應用id。
client_assertion_type
String
用戶端assertion類型。固定值:urn:ietf:params:oauth:client-assertion-type:jwt-bearer。
client_assertion
String
用戶端使用client_secret簽發的簽名,jwt格式,簽名演算法使用HS256。請參考:附錄二。
scope
String
可以根據scope來進行許可權申請,String類型空格拼接。格式為:resourceServerIdentifier+"|"+scope,如:
resourceServerIdentifier是:api://api.xxxxx.com,scope是:read:file
最終返回結果為:api://api.xxxxx.com|read:file
擷取當前client已經授權的所有scopes,使用:{resourceServerIdentifier}|.all
api://api.xxxxx.com|read:file
請求樣本:
curl --request POST \ --url 'https://XXXX.aliyunidaas.com/api/v2/iauths_system/oauth2/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'client_id={{clientId}}' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \ --data-urlencode 'client_assertion={{JwtToken}}' \ --data-urlencode 'scope=api://api.xxxxx.com|read:file'返回樣本:
{ "token_type": "Bearer", "access_token": "AT8csE2sep******7NHBkxxHUG", "expires_in": 3600, "expires_at": 1733710213 }
認證方式:private_key_jwt
要求方法:POST
header頭參數:
參數名
類型
說明
樣本
Content-Type
String
固定值:application/x-www-form-urlencoded
application/x-www-form-urlencoded
請求參數:
參數名
類型
說明
樣本
grant_type
String
固定值:client_credentials。
client_credentials
client_id
String
應用id。
client_assertion_type
String
用戶端assertion類型。固定值:urn:ietf:params:oauth:client-assertion-type:jwt-bearer。
client_assertion
String
用戶端使用私密金鑰簽發的簽名,jwt格式,簽名演算法使用RS256。請參考:附錄一。
scope
String
可以根據scope來進行許可權申請,String類型空格拼接。格式為:resourceServerIdentifier+"|"+scope,如:
resourceServerIdentifier是:api://api.xxxxx.com,scope是:read:file
最終返回結果為:api://api.xxxxx.com|read:file
擷取當前client已經授權的所有scopes,使用:{resourceServerIdentifier}|.all
api://api.xxxxx.com|read:file
請求樣本:
curl --request POST \ --url 'https://XXXX.aliyunidaas.com/api/v2/iauths_system/oauth2/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'client_id={{clientId}}' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \ --data-urlencode 'client_assertion={{JwtToken}}' \ --data-urlencode 'scope=api://api.xxxxx.com|read:file'返回樣本:
{ "token_type": "Bearer", "access_token": "AT8csE2se******HBkxxHUG", "expires_in": 3600, "expires_at": 1733710213 }
認證方式:OIDC 聯邦認證
要求方法:POST
header頭參數:
參數名
類型
說明
樣本
Content-Type
String
固定值:application/x-www-form-urlencoded
application/x-www-form-urlencoded
請求參數:
參數名
類型
說明
樣本
grant_type
String
固定值:client_credentials。
client_credentials
client_id
String
應用id。
client_assertion_type
String
用戶端assertion類型。固定值:urn:cloud:idaas:params:oauth:client-assertion-type:id-token-bearer。
client_assertion
String
用戶端使用的OIDC Token,JWT格式。
scope
String
可以根據scope來進行許可權申請,String類型空格拼接。格式為:resourceServerIdentifier+"|"+scope,如:
resourceServerIdentifier是:api://api.xxxxx.com,scope是:read:file
最終返回結果為:api://api.xxxxx.com|read:file
擷取當前client已經授權的所有scopes,使用:{resourceServerIdentifier}|.all
api://api.xxxxx.com|read:file
application_federated_credential_name
String
應用聯邦憑證名稱。
aliyun_ack
請求樣本:
curl --request POST \ --url 'https://xxxxx.aliyunidaas.com/api/v2/iauths_system/oauth2/token' \ --header 'content-type: application/x-www-form-urlencoded' \ --data-urlencode 'client_id=app_xxxxxx' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'scope=api://api.xxxxx.com|.all' \ --data-urlencode 'application_federated_credential_name=xxxxxx' \ --data-urlencode 'client_assertion=xxxxx.xxxxx.xxxxx' \ --data-urlencode 'client_assertion_type=urn:cloud:idaas:params:oauth:client-assertion-type:id-token-bearer'返回參數:
參數名
類型
是否可為空白
描述
access_token
String
否
access token值。
expires_in
Long
否
到期時間長度,unix時間戳記,單位秒。
expires_at
Long
否
到期時間,unix時間戳記,單位秒。
token_type
String
否
access token類型。
返回樣本:
{ "token_type": "Bearer", "access_token": "AT8csE2se******NHBkxxHUG", "expires_in": 3600, "expires_at": 1733710213 }
認證方式:PKCS#7 簽名認證
要求方法:POST
header頭參數:
參數名
類型
說明
樣本
Content-Type
String
固定值:application/x-www-form-urlencoded
application/x-www-form-urlencoded
請求參數:
參數名
類型
說明
樣本
grant_type
String
固定值:client_credentials。
client_credentials
client_id
String
應用id。
client_assertion_type
String
用戶端assertion類型。固定值:urn:cloud:idaas:params:oauth:client-assertion-type:pkcs7-bearer。
client_assertion
String
PKCS#7簽名值。
scope
String
可以根據scope來進行許可權申請,String類型空格拼接。格式為:resourceServerIdentifier+"|"+scope,如:
resourceServerIdentifier是:api://api.xxxxx.com,scope是:read:file
最終返回結果為:api://api.xxxxx.com|read:file
擷取當前client已經授權的所有scopes,使用:{resourceServerIdentifier}|.all
api://api.xxxxx.com|read:file
application_federated_credential_name
String
應用聯邦憑證名稱。
aliyun_ecs
請求樣本:
curl --request POST \ --url 'https://xxxxx.aliyunidaas.com/api/v2/iauths_system/oauth2/token' \ --header 'content-type: application/x-www-form-urlencoded' \ --data-urlencode 'client_id=app_xxxxx' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'scope=api://api.xxxxx.com|.all' \ --data-urlencode 'application_federated_credential_name=xxxxxx' \ --data-urlencode 'client_assertion=xxxxx' \ --data-urlencode 'client_assertion_type=urn:cloud:idaas:params:oauth:client-assertion-type:pkcs7-bearer'返回參數:
參數名
類型
是否可為空白
描述
access_token
String
否
access token值。
expires_in
Long
否
到期時間長度,unix時間戳記,單位秒。
expires_at
Long
否
到期時間,unix時間戳記,單位秒。
token_type
String
否
access token類型。
返回樣本:
{ "token_type": "Bearer", "access_token": "AT8csE2sep******7NHBkxxHUG", "expires_in": 3600, "expires_at": 1733710213 }
認證方式:PrivateCA 憑證認證
要求方法:POST
header頭參數:
參數名
類型
說明
樣本
Content-Type
String
固定值:application/x-www-form-urlencoded。
application/x-www-form-urlencoded
請求參數:
參數名
類型
說明
樣本
grant_type
String
固定值:client_credentials。
client_credentials
client_id
String
應用id。
client_assertion_type
String
用戶端assertion類型。固定值:urn:cloud:idaas:params:oauth:client-assertion-type:x509-jwt-bearer。
client_assertion
String
用戶端使用private_key簽發的JWT Token。
scope
String
可以根據scope來進行許可權申請,String類型空格拼接。格式為:resourceServerIdentifier+"|"+scope,如:
resourceServerIdentifier是:api://api.xxxxx.com,scope是:read:file
最終返回結果為:api://api.xxxxx.com|read:file
擷取當前client已經授權的所有scopes,使用:
api://api.xxxxx.com|read:file
client_x509
String
終端認證(葉子認證),即Client Certificate。
base64-encoded Distinguished Encoding Rules
-----BEGIN CERTIFICATE-----
xxxxxx
-----END CERTIFICATE-----
client_x509_chain
String
中間認證列表,Intermediate CA。
base64-encoded Distinguished Encoding Rules
多張認證使用換行拼接。每張認證必須為以下格式:
-----BEGIN CERTIFICATE-----開始 -----END CERTIFICATE-----結尾-----BEGIN CERTIFICATE-----
xxxxxx1
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
xxxxxx1
-----END CERTIFICATE-----
application_federated_credential_name
String
應用聯邦憑證名稱。
private_ca
請求樣本:
curl --request POST \ --url 'https://xxxxx.aliyunidaas.com/api/v2/iauths_system/oauth2/token' \ --header 'content-type: application/x-www-form-urlencoded' \ --data-urlencode 'client_id=app_xxxxx' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'scope=api://api.xxxxx.com|.all' \ --data-urlencode 'application_federated_credential_name=xxxxx' \ --data-urlencode 'client_assertion=xxxxx' \ --data-urlencode 'client_assertion_type=urn:cloud:idaas:params:oauth:client-assertion-type:pkcs7-bearer'返回參數:
參數名
類型
是否可為空白
描述
access_token
String
否
access token值。
expires_in
Long
否
到期時間長度,unix時間戳記,單位秒。
expires_at
Long
否
到期時間,unix時間戳記,單位秒。
token_type
String
否
access token類型。
返回樣本:
{ "token_type": "Bearer", "access_token": "AT8csE2se******NHBkxxHUG", "expires_in": 3600, "expires_at": 1733710213 }
錯誤碼
HttpCode | error | 錯誤資訊 | 說明 |
400 | invalid_request | Require parameter variable: grant_type | 請求缺少必需參數、包含無效參數值、包含多個參數或格式錯誤。 |
400 | authentication_required | Authentication required, allowed authentication methods: [client_secret_basic, client_secret_post, client_secret_jwt, private_key_jwt] | 認證方式不正確,支援的認證方式為: client_secret_basic, client_secret_post, client_secret_jwt, private_key_jwt。 |
400 | invalid_client_credential | Invalid client_assertion, reasons(s): [expired] | 無效的client_assertion,token到期。 |
400 | invalid_grant | Invalid or not supported grant_type: authorization_code | 不支援的grant_type類型。 |
400 | invalid_scope | Invalid scope: http://www.example.com|read:file | 請求的範圍無效、未知或格式錯誤。 |
500 | internal_error | Unexpected internal error | 伺服器內部錯誤。 |
附錄一:使用Java產生JWT(RS256演算法)簽名
本附錄提供了使用Java語言產生JWT(JSON Web Token)簽名的完整樣本,採用RS256非對稱式加密演算法。內容包含:
Maven依賴配置:
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency>Java程式碼範例:
import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import java.security.Key; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.UUID; /** * @author fei.chen * @date 2025-02-24 16:17 */ public class JwtGenerator { private static final String PRIVATE_KEY = "your-private-key"; // 替換為你的密鑰 // 填入應用的client_id private static final String ISSUER = "your_client_id"; // 填入應用的client_id private static final String SUBJECT = "your_client_id"; // 填入應用的令牌端點 private static final String AUDIENCE = "your_token_endpoint"; public static void main(String[] args) throws Exception { // 密鑰 Key securityKey = RsaKeyConverter.getPrivateKeyFromString(PRIVATE_KEY); Map<String, Object> claims = new HashMap<>(); claims.put("jti", UUID.randomUUID().toString()); // 防重放jti // 設定到期時間,不能超過30分鐘 long expirationTime = 1000 * 60 * 30; Date expirationDate = new Date(System.currentTimeMillis() + expirationTime); // 產生 JWT String jwt = Jwts.builder() .setClaims(claims) .setIssuedAt(new Date()) .setExpiration(expirationDate) .setSubject(SUBJECT) .setIssuer(ISSUER) .setAudience(AUDIENCE) .signWith(securityKey, SignatureAlgorithm.RS256) .compact(); System.out.println("產生的 JWT 令牌:"); System.out.println(jwt); } }import java.security.KeyFactory; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; /** * @author fei.chen * @date 2025-02-24 16:51 */ public class RsaKeyConverter { public static PrivateKey getPrivateKeyFromString(String privateKeyStr) throws Exception { // 去掉PEM格式的頭尾標記 String privateKeyPEM = privateKeyStr .replace("-----BEGIN PRIVATE KEY-----", "") .replace("-----END PRIVATE KEY-----", "") .replaceAll("\\s+", ""); // 去除所有空白字元 // Base64解碼 byte[] encoded = Base64.getDecoder().decode(privateKeyPEM); // 使用PKCS8EncodedKeySpec產生私密金鑰 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); return keyFactory.generatePrivate(keySpec); } public static PublicKey getPublicKeyFromString(String publicKeyStr) throws Exception { // 去掉PEM格式的頭尾標記 String publicKeyPEM = publicKeyStr .replace("-----BEGIN PUBLIC KEY-----", "") .replace("-----END PUBLIC KEY-----", "") .replaceAll("\\s+", ""); // 去除所有空白字元 // Base64解碼 byte[] encoded = Base64.getDecoder().decode(publicKeyPEM); // 使用X509EncodedKeySpec產生公開金鑰 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); return keyFactory.generatePublic(keySpec); } }
附錄二:使用Java產生JWT(HS256演算法)簽名
本附錄提供使用Java語言產生JWT(JSON Web Token)格式簽名的完整樣本,採用HS256簽名演算法。樣本包含以下內容:
Maven依賴配置:
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency>Java程式碼範例:
public class JwtGenerator { private static final String SECRET_KEY = "your_secret_key"; // 替換為你的密鑰 // 填入應用的client_id private static final String ISSUER = "your_client_id"; // 填入應用的client_id private static final String SUBJECT = "your_client_id"; // 填入應用的令牌端點 private static final String AUDIENCE = "your_token_endpoint"; public static String generateJwt() throws Exception { SecretKey secretKey = Keys.hmacShaKeyFor(SECRET_KEY.getBytes()); Map<String, Object> claims = new HashMap<>(); claims.put("jti", UUID.randomUUID().toString()); // 防重放jti // 設定到期時間,不能超過30分鐘 long expirationTime = 1000 * 60 * 30; Date expirationDate = new Date(System.currentTimeMillis() + expirationTime); // 產生 JWT String jwt = Jwts.builder() .setClaims(claims) .setIssuedAt(new Date()) .setExpiration(expirationDate) .setSubject(SUBJECT) .setIssuer(ISSUER) .setAudience(AUDIENCE) .signWith(secretKey, SignatureAlgorithm.HS256) .compact(); return jwt; } public static void main(String[] args) throws Exception{ // 產生JWT String jwt = generateJwt(); System.out.println("Generated JWT: " + jwt); } }