1.RSA asymmetric encryption
RSA asymmetric encryption encrypts the signature, not the header and load of jwt. The header and load are encrypted with base64 jwt official website You can know
Tokens are put together by spelling strings.
It is concluded that:
1. User defined data can be placed in the load, but sensitive data cannot be placed.
As shown in the figure above, even if you take the token here, you can see the header and payload, but the Invalid Signature displayed in the lower left corner is invalid because there is no public key
Enter the corresponding public key, and you can see that the verification is completed. Thus, you can know the usage mode and scenario of public key and key.
2. Public key and key
Asymmetric encryption requires public key and key, which appear in pairs
The general key is used for signature and the public key is used for verification. This is generally the data stored in two files. The rsa Library of golang can be used to generate the key, and the public key can be obtained directly from the key.
Generating keys using golang's rsa Library
In fact, here, we can choose to regenerate a bunch of public keys every time a new token is generated, and then publish the public keys to the system that needs to update the public keys, or we can always use only one pair of public keys. This is very helpful in distributed systems. The system that generates the key pair can only publish the public key to each system. Because they only need to do the verification function.
func CreateKeys() (*rsa.PrivateKey, rsa.PublicKey) { privateKey, err := rsa.GenerateKey(rand.Reader, 4096) if err != nil { panic(err) } publicKey := privateKey.PublicKey return privateKey, publicKey }
Here, we save the generated key into a private.key file
Get the key according to the file path
func GetPrivateKey(privateKeyFilePath string) *rsa.PrivateKey { file, err := os.Open(filePath) if err != nil { fmt.Errorf("%v", err) } pkBytes, err := ioutil.ReadAll(file) if err != nil { fmt.Errorf("%v", err) } key, err := jwt.ParseRSAPrivateKeyFromPEM(pkBytes) if err != nil { fmt.Errorf("cannot parse private key>%v", err) } return key }
Get public key
func GetPublicKeyByPrivateKey(privateKeyFilePath string) *rsa.PublicKey { privateKey := GetPrivateKey(filePath) publicKey := privateKey.PublicKey return &publicKey }
Generate token
func (j *JWT) CreateToken(claims request.CustomClaims) (string, error) { //Select the signature algorithm and pass in the load token := jwt.NewWithClaims(jwt.SigningMethodRS512, claims) //Get key privateKey := GetPrivateKey("./source/keyFile/private.key") //autograph tokenStr, err := token.SignedString(privateKey) return tokenStr, err }
Parse token
Here, the public key is obtained from the key because it is parsed in the jwt signature system. It doesn't matter
// Parse token func (j *JWT) ParseToken(tokenString string) (*request.CustomClaims, error) { publicKey := GetPublicKeyByPrivateKey("Key data file path") token, err := jwt.ParseWithClaims(tokenString, &request.CustomClaims{}, func(token *jwt.Token) (i interface{}, e error) { return publicKey, nil }) if err != nil { if ve, ok := err.(*jwt.ValidationError); ok { if ve.Errors&jwt.ValidationErrorMalformed != 0 { return nil, TokenMalformed } else if ve.Errors&jwt.ValidationErrorExpired != 0 { // Token is expired return nil, TokenExpired } else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 { return nil, TokenNotValidYet } else { return nil, TokenInvalid } } } if token != nil { if claims, ok := token.Claims.(*request.CustomClaims); ok && token.Valid { return claims, nil } return nil, TokenInvalid } else { return nil, TokenInvalid } }