The authentication
After the first login, a token with a certain validity period is generated and stored in the Cookie or LocalStorage of the browser. Subsequent requests carry the token. After the request arrives at the server, the server uses the token to authenticate the request.
A simpler approach is to symmetrically encrypt user information and time stamps directly with the key, which saves extra storage and reduces the query pressure on the database with each request. In this way, there is a standard implementation in the industry, which is called JSON Web Token
JWT
In JWT, the Token consists of three parts, separated by a., and encoded in Base64:
-
header
-
payload
-
signature
header
The JWT Token header contains two parts of information:
- The type of the Token
- Encryption algorithm used by the Token
For example,
{
"typ": "JWT"."alg": "HS256"
}
Copy the code
payload
To place the token content, you can put some standard fields and some additional fields. Standard fields include:
- Iss: issuer of JWT Token
- Sub: theme
- Exp: indicates the expiration time of the JWT Token
- Aud: the party receiving the JWT Token
- Iat: JWT Token issue time
- NBF: JWT Token validity time
- Jti: indicates the JWT Token ID
Signature
Generate through the previous two parts. Generation method:
- Encode header.payload in Base64
- Use Secret (Secret is a password stored on the server) to encrypt the encoded content, and the encrypted content is called Signature
Tokens are generated based on ID and user name
func Sign(ctx *gin.Context, c Context, secret string) (tokenString string, err error) {
// Load the jwt secret from the Gin config if the secret isn't specified.
if secret == "" {
secret = viper.GetString("jwt_secret")
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"id": c.ID,
"username": c.Username,
"nbf": time.Now().Unix(),
"iat": time.Now().Unix(),
})
tokenString, err = token.SignedString([]byte(secret))
return
}
Copy the code
Extract the token from the header of the request
func ParseRequest(c *gin.Context) (*Context, error) {
header := c.Request.Header.Get("Authorization")
secret := viper.GetString("jwt_secret")
if len(header) == 0 {
return &Context{}, ErrMissingHeader
}
var t string
fmt.Sscanf(header, "Bearer %s", &t)
return Parse(t, secret)
}
Copy the code
Check the format of secret
func secretFunc(secret string) jwt.Keyfunc {
return func(token *jwt.Token) (interface{}, error) {
// Make sure the `alg` is what we except.
if_, ok := token.Method.(*jwt.SigningMethodHMAC); ! ok {return nil, jwt.ErrSignatureInvalid
}
return []byte(secret), nil}}Copy the code
Parsing the token
func Parse(tokenString string, secret string) (*Context, error) {
ctx := &Context{}
token, err := jwt.Parse(tokenString, secretFunc(secret))
iferr ! =nil {
return ctx, err
} else if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
ctx.ID = uint64(claims["id"]. (float64))
ctx.Username = claims["username"]. (string)
return ctx, nil
} else {
return ctx, err
}
}
Copy the code