Alibaba cloud API gateway implements a set of mechanism for authorizing access to users' APIs based on user system on the basis of structured token such as Json Web Token (JWT), which meets the needs of users' personalized security settings.
Alibaba cloud API gateway implements a set of mechanism for authorizing access to users' APIs based on user system on the basis of structured token such as Json Web Token (JWT), which meets the needs of users' personalized security settings.
1, token based authentication
1.1 INTRODUCTION
Many open API s need to identify the identity of the requester and judge whether the requested resources can be returned to the requester. token is a mechanism for authentication. Based on this mechanism, the application does not need to retain the user's authentication information or session information at the server. It can realize stateless and distributed Web application authorization, which provides convenience for application expansion.
1.2 process description
The above figure is the sequence diagram of the whole business process of API gateway using JWT to realize authentication. Next, we will describe the steps marked in the diagram in detail with words:
-
The client sends an authentication request to the API gateway, which generally carries the user name and password of the end user;
-
The API gateway forwards the request directly to the back-end service;
-
The back-end service reads the authentication information (such as user name and password) in the request for authentication. After passing the authentication, it uses the private key to generate a standard token and return it to the API gateway;
-
The API gateway returns the response with the token to the client, and the client needs to cache the token locally;
-
The client sends a service request to the API gateway, and the request carries a token;
-
The API gateway uses the public key set by the user to verify the token in the request. After the verification is passed, the request is transmitted to the back-end service;
-
The back-end service responds after business processing;
-
The API gateway returns the service response to the client.
In the whole process, the API gateway uses the token authentication mechanism to realize the ability of users to authorize their APIs using their own user system. Next, we will introduce the structured token JSON web token (JWT) used by the API gateway to implement token authentication.
1.3 JWT
1.3.1 introduction
JSON web token (JWT) is a JSON based open standard implemented to transfer declarations between network application environments RFC7519 . JWT can generally be used as an independent authentication token, which can contain information such as user ID, user role and permission, so as to obtain resources from the resource server. It can also add some additional declaration information necessary for other business logic, especially suitable for the login scenario of distributed sites.
1.3.2 composition of JWT
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
As shown in the above example, JWT is a string composed of three parts:
-
Header
-
Payload (data)
-
Signature
Header
The header of the JWT carries two messages:
-
Declaration type, here is JWT
-
Algorithm for declaring encryption
The complete header is like the following JSON:
{ 'typ': 'JWT', 'alg': 'HS256' }
Then, the header is Base64 encoded (which can be decoded symmetrically) to form the first part.
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
Payload
Payload is the place where valid information is stored. The definition details are as follows:
iss: token issuer. Indicates who created the token. The declaration is a string sub: Subject Identifier. The end user id provided by iss is unique within the scope of iss. The maximum length is 255 ASCII characters. It is case sensitive. aud: Audience(s), token audience, case sensitive string array exp: Expiration time, and token expiration timestamp. Tokens that exceed this time will be invalidated. The declaration is an integer, which is the number of seconds since January 1, 1970. iat: the issuing time of the token. The declaration is an integer, which is the number of seconds since January 1, 1970. jti: the unique identification of the token. The value of the declaration is unique in each token created by the token issuer. In order to prevent conflicts, It is usually a cryptographic random value. This value is equivalent to adding a random entropy component to the structured token that cannot be obtained by the attacker, which is helpful to prevent token guessing attack and replay attack
You can also add custom fields that the user system needs to use. For example, the following example adds name User nickname:
{ "sub": "1234567890", "name": "John Doe" }
Then it is Base64 encoded to obtain the second part of Jwt:
JTdCJTBBJTIwJTIwJTIyc3ViJTIyJTNBJTIwJTIyMTIzNDU2Nzg5MCUyMiUyQyUwQSUyMCUyMCUyMm5hbWUlMjIlM0ElMjAlMjJKb2huJTIwRG9lJTIyJTBBJTdE
Signature
This part needs to be used by Base64 encoded Header and Base64 encoded Payload . The string formed by the connection is then encrypted through the encryption method declared in the Header ($secret) Represents the user's private key), which then forms the third part of jwt.
// javascript var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload); var signature = HMACSHA256(encodedString, '$secret');
Use these three parts . Concatenation into a complete string constitutes the JWT example at the beginning of section 1.3.2.
1.3.3 scope and limitation of authorization
The API gateway will think that the token issued by the user has the right to access all APIs bound to JWT plug-ins under the whole group. If more detailed permission management is required, the back-end service needs to unlock the token for permission authentication. The API gateway will verify the exp field in the token. Once the field expires, the API gateway will consider the token invalid and call back the request directly. The expiration time value must be set, and the expiration time must be less than 7 days.
1.3.4 several characteristics of JWT
-
JWT is not encrypted by default and cannot write secret data to JWT.
-
JWT can be used not only for authentication, but also for exchanging information. Using JWT effectively can reduce the number of times the server queries the database. JWT's security feature 3. The biggest disadvantage of JWT is that the server does not save the session state, so it is impossible to revoke a token or change the permission of the token during use. That is, once the JWT is issued, it will remain valid until it expires, unless the server deploys additional logic.
-
JWT itself contains authentication information. Once it is leaked, anyone can obtain all the permissions of the token. In order to reduce embezzlement, the validity period of JWT should be set relatively short. For some important permissions, users should be authenticated again.
-
In order to reduce embezzlement, JWT should not use HTTP protocol for explicit transmission, but HTTPS protocol for transmission.
2, How does the user system apply the JWT plug-in protection API
2.1 generate a pair of JWK (JSON Web key)
Method 1: Online generation:
Users can be on this site https://mkjwk.org Generate the private key and public key for token generation and verification. The private key is used to authorize the service to issue JWT. The public key is configured in the JWT plug-in for API gateway to request signature verification. At present, the encryption algorithm of the key pair supported by API gateway is RSA SHA256, and the number of bits of encryption of the key pair is 2048.
Method 2: local generation:
This article applies Java examples to illustrate that users of other languages can also find relevant tools to generate key pairs. Create a Maven project and add the following dependencies:
<dependency> <groupId>org.bitbucket.b_c</groupId> <artifactId>jose4j</artifactId> <version>0.7.0</version> </dependency>
Generate a pair of RSA keys using the following code:
RsaJsonWebKey rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048); rsaJsonWebKey.setKeyId("authServer"); final String publicKeyString = rsaJsonWebKey.toJson(JsonWebKey.OutputControlLevel.PUBLIC_ONLY); final String privateKeyString = rsaJsonWebKey.toJson(JsonWebKey.OutputControlLevel.INCLUDE_PRIVATE);
2.2 use the private key in JWK to realize the authentication service of issuing token
Online generated in Section 2.1 is required Keypair JSON string (the first of the three boxes) or locally generated privateKeyString The JSON string is used as the private key to issue the token, which is used to authorize trusted users to access the protected API. For the specific implementation, please refer to the example in Section 4 of this article. The form of issuing a token to a customer is determined by the user according to the specific business scenario. The function of issuing a token can be deployed to the production environment, configured as a common API, and obtained by the visitor through the user name and password. It can also be directly copied to the specified user after the token is generated in the local environment.
2.3 configure the public key in JWK into JWT plug-in
-
Sign in
.
-
On the left navigation bar, click plug in management.
-
On the plug-in management page, click in the upper right corner
Create plug-in
.
-
On the create plug-in page, select the plug-in type
JWT authentication
, the following is the configuration and description of a JWT authentication plug-in. Refer to the document for specific configuration instructions
.
--- parameter: X-Token # Obtain the JWT from the specified parameters, corresponding to the parameters of the API parameterLocation: header # Optional when the API is in mapping mode. The API is required in transparent mode. It is used to specify the reading location of JWT. Only 'query' and 'header' are supported` claimParameters: # When the claims parameter is converted, the gateway will map the jwt claims to the back-end parameters - claimName: aud # claim name, supporting public and private parameterName: X-Aud # Parameter name after mapping location: header # The mapped parameter position supports ` query, header, path and formdata` - claimName: userId # claim name, supporting public and private parameterName: userId # Parameter name after mapping location: query # The mapped parameter position supports ` query, header, path and formdata` preventJtiReplay: false # Enable anti replay check for 'jti'; default: false # # `The 'Public Key' of Json Web Key is the Public Key generated in Section 2.1 of this article jwk: kty: RSA e: AQAB use: sig alg: RS256 n: qSVxcknOm0uCq5vGsOmaorPDzHUubBmZZ4UXj-9do7w9X1uKFXAnqfto4TepSNuYU2bA_-tzSLAGBsR-BqvT6w9SjxakeiyQpVmexxnDw5WZwpWenUAcYrfSPEoNU-0hAQwFYgqZwJQMN8ptxkd0170PFauwACOx4Hfr-9FPGy8NCoIO4MfLXzJ3mJ7xqgIZp3NIOGXz-GIAbCf13ii7kSStpYqN3L_zzpvXUAos1FJ9IPXRV84tIZpFVh2lmRh0h8ImK-vI42dwlD_hOIzayL1Xno2R0T-d5AwTSdnep7g-Fwu8-sj4cCRWq3bd61Zs2QOJ8iustH0vSRMYdP5oYQ
2.4 JWT plug-in binding API
Find the JWT authentication plug-in just created on the plug-in list page, click bind API, add the API under the specified group and environment in the pop-up box to the API list on the right side of the pop-up box, and click OK to finish binding.
At present, the API debugging function of the console does not support JWT plug-ins. It is recommended that users test the API binding JWT plug-ins through Postman or directly apply curl command on the system command line.
3, API gateway error response list
Status | Code | Message | Description |
400 | I400JR | JWT required | JWT parameter not found |
403 | S403JI | Claim jti is required when preventJtiReplay:true | When the anti replay function is configured in the JWT authorization plug-in, the request does not provide a valid jti |
403 | S403JU | Claim jti in JWT is used | When the anti replay function is configured in the JWT authorization plug-in, the requested jti has been used |
403 | A403JT | Invalid JWT: ${Reason} | The JWT provided in the request is illegal |
400 | I400JD | JWT Deserialize Failed: ${Token} | The JWT provided in the request failed to resolve |
403 | A403JK | No matching JWK, kid:${kid} not found | The kid in the request JWT does not have a matching JWK |
403 | A403JE | JWT is expired at ${Date} | The JWT provided in the request has expired |
400 | I400JP | Invalid JWT plugin config: ${JWT} | JWT authorization plug-in configuration error |
In case of unexpected response code, please check the X-Ca-Error-Code header in the HTTP response to obtain the ErrorCode, and obtain the ErrorMessage from the X-Ca-Error-Message header. In case of A403JT or I400JD error code, you can visit the jwt.io website to check your Token legitimacy and format.
4, Example code of authentication service issuing token
import java.security.PrivateKey; import org.jose4j.json.JsonUtil; import org.jose4j.jwk.RsaJsonWebKey; import org.jose4j.jwk.RsaJwkGenerator; import org.jose4j.jws.AlgorithmIdentifiers; import org.jose4j.jws.JsonWebSignature; import org.jose4j.jwt.JwtClaims; import org.jose4j.jwt.NumericDate; import org.jose4j.lang.JoseException; public class GenerateJwtDemo { public static void main(String[] args) throws JoseException { //Use the keyId set in the API gateway String keyId = "uniq_key"; //Use the keyware generated in Section 3.2 of this article String privateKeyJson = "{\n" + " \"kty\": \"RSA\",\n" + " \"d\": " + "\"O9MJSOgcjjiVMNJ4jmBAh0mRHF_TlaVva70Imghtlgwxl8BLfcf1S8ueN1PD7xV6Cnq8YenSKsfiNOhC6yZ_fjW1syn5raWfj68eR7cjHWjLOvKjwVY33GBPNOvspNhVAFzeqfWneRTBbga53Agb6jjN0SUcZdJgnelzz5JNdOGaLzhacjH6YPJKpbuzCQYPkWtoZHDqWTzCSb4mJ3n0NRTsWy7Pm8LwG_Fd3pACl7JIY38IanPQDLoighFfo-Lriv5z3IdlhwbPnx0tk9sBwQBTRdZ8JkqqYkxUiB06phwr7mAnKEpQJ6HvhZBQ1cCnYZ_nIlrX9-I7qomrlE1UoQ\",\n" + " \"e\": \"AQAB\",\n" + " \"kid\": \"myJwtKey\",\n" + " \"alg\": \"RS256\",\n" + " \"n\": \"vCuB8MgwPZfziMSytEbBoOEwxsG7XI3MaVMoocziP4SjzU4IuWuE_DodbOHQwb_thUru57_Efe" + "--sfATHEa0Odv5ny3QbByqsvjyeHk6ZE4mSAV9BsHYa6GWAgEZtnDceeeDc0y76utXK2XHhC1Pysi2KG8KAzqDa099Yh7s31AyoueoMnrYTmWfEyDsQL_OAIiwgXakkS5U8QyXmWicCwXntDzkIMh8MjfPskesyli0XQD1AmCXVV3h2Opm1Amx0ggSOOiINUR5YRD6mKo49_cN-nrJWjtwSouqDdxHYP-4c7epuTcdS6kQHiQERBd1ejdpAxV4c0t0FHF7MOy9kw\"\n" + "}"; JwtClaims claims = new JwtClaims(); claims.setGeneratedJwtId(); claims.setIssuedAtToNow(); //The expiration time must be set and less than 7 days NumericDate date = NumericDate.now(); date.addSeconds(120*60); claims.setExpirationTime(date); claims.setNotBeforeMinutesInThePast(1); claims.setSubject("YOUR_SUBJECT"); claims.setAudience("YOUR_AUDIENCE"); //Add a custom parameter. Please use String type for all values claims.setClaim("userId", "1213234"); claims.setClaim("email", "userEmail@youapp.com"); JsonWebSignature jws = new JsonWebSignature(); jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256); //Must be set jws.setKeyIdHeaderValue(keyId); jws.setPayload(claims.toJson()); PrivateKey privateKey = new RsaJsonWebKey(JsonUtil.parseJson(privateKeyJson)).getPrivateKey(); jws.setKey(privateKey); String jwtResult = jws.getCompactSerialization(); System.out.println("Generate Json Web token , result is " + jwtResult); } }
In the above example, the following areas need to be focused:
-
The keyId needs to be consistent in all three phases and globally unique:
-
keyId filled in when using Section 2.1 to generate key;
-
keyId set in section 3.2.1 of this document;
-
The keyId in the code and the value of KeyIdHeaderValue of JsonWebSignature object. This property is required
-
Privatekeyjason uses the online generated in Section 2.1
Keypair
JSON string (the first of the three boxes) or locally generated
privateKeyString
JSON string;
-
The expiration time must be set and less than 7 days;
-
Add a custom parameter. Please use String type for all values.