golang JWT implementation of the sample code

  • 2020-10-23 20:08:48
  • OfStack

What is JSON Web Token?

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transferring information between parties in JSON fashion. Because this information is digitally signed, it can be validated and trusted. JWT can be signed using the secret (using the HMAC algorithm) or using the public/private key pair of RSA or ECDSA.

To put it bluntly, jwt is a solution for user authentication (different from session and cookie).

Background of appearance

As we all know, before jwt came along, we had session and cookie to solve authentication problems such as user login, so why jwt?

So let's look at 1 session, cookie.

session

Students familiar with session operation mechanism know that session data of users is stored in the server side in file or cache (redis, memcached), and only sessionid is stored in the client browser cookie. The server side session belongs to the centralized storage. In the case of small quantity, there is no problem. When the user data gradually increases to the level of 1, it will bring great burden to the server side management and maintenance.

session has two disadvantages:

1. Cross-domain implementation is not possible.

2. As session data belongs to centralized management, server performance is a problem when there is a large amount of data.

Advantages:

1. session has a server side, and the data is relatively safe.

2. Centralized management of session also has the advantage that users' login and logout of the service side can be controlled.

cookie

cookie also is one kind of solution to the realization of the website user authentication, user login, contains login credentials Cookie server will be sent to the user's browser client, the browser will Cookie key/value save users (memory or hard disk), local users to visit the web site, the browser will send cookie information to the server, the server receives the cookie and to maintain the user login state.

cookie avoids the problem of centralized management of session, but it also has disadvantages:

1. Cross-domain problems.

2. As the data is stored in the browser, it is easy to be stolen and attacked by csrf, with poor security.

Advantages:

1. Simpler than session, the server does not need to maintain user authentication information.

2. Data persistence.

jwt

jwt is transmitted through json, supported by many languages such as php, java, golang, etc., with good versatility, there is no cross-domain problem. The transmitted data is relatively secure through data signature. The client interacts with the server through jwt, and the server decrypts token information to achieve user authentication. There is no need for servers to centrally maintain token information, making it easy to scale. The jwt has its drawbacks, of course.

Disadvantages:

1. The user cannot log out voluntarily, as long as token is valid within the validity period. Consider redis setting a blacklist that is directly valid for token to solve this problem.

2. token has expired and cannot be renewed. Consider determining when the old token expires and refreshing the token renewal interface when it expires to generate a new token to replace the old token.

jwt set expiry date

The validity period can be set. The validity period is added to increase security, that is, token is intercepted by hackers and can only attack for a short time. If the validity period is set, the renewal problem of token will be faced. The solution is as follows

Typically, the server sets up two token

Access Token: Adds to header requested by HTTP, authenticates the user, and requests interface resources. refresh token: Used when Access Token expires, the client passes refresh token to refresh the Access Token renewal interface to get a new Access Token and refresh token. Its validity period is longer than Access Token.

jwt composition:

Header: The type of TOKEN is JWT, the signature algorithm, such as HMAC SHA256, HS384 Payload: The payload, also known as Claim, carries information such as user name, expiration time, etc. 1 is commonly called Claim Signature: Signature, encrypted by header, payload and one secret maintained by yourself

jwt use

Here recommend using more open source projects [github. com/dgrijalva/jwt - go] (), more documentation.

Example:


package main

import (
  "fmt"
  "github.com/dgrijalva/jwt-go"
  "time"
)
const (
  SECRETKEY = "243223ffslsfsldfl412fdsfsdf"// The private key 
)
// The custom Claims
type CustomClaims struct {
  UserId int64
  jwt.StandardClaims
}
func main() {
  // generate token
  maxAge:=60*60*24
  customClaims :=&CustomClaims{
    UserId: 11,// The user id
    StandardClaims: jwt.StandardClaims{
      ExpiresAt: time.Now().Add(time.Duration(maxAge)*time.Second).Unix(), //  Expiration time must be set 
      Issuer:"jerry",  //  You don't have to fill in the user name, 
    },
  }
  // using HMAC SHA256 The encryption algorithm 
  token:=jwt.NewWithClaims(jwt.SigningMethodHS256, customClaims)
  tokenString,err:= token.SignedString([]byte(SECRETKEY))
  if err!=nil {
    fmt.Println(err)
  }
  fmt.Printf("token: %v\n", tokenString)

  // parsing token
  ret,err :=ParseToken(tokenString)
  if err!=nil {
    fmt.Println(err)
  }
  fmt.Printf("userinfo: %v\n", ret)
}

// parsing token
func ParseToken(tokenString string)(*CustomClaims,error) {
  token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
    if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
      return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
    }
    return []byte(SECRETKEY), nil
  })
  if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
    return claims,nil
  } else {
    return nil,err
  }
}

Operation results:

[

token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOjExLCJleHAiOjE1OTA5MTk1NDAsImlzcyI6ImplcnJ5In0.FppmbbHRrS4wd5wen73vYPOvtzycOrn2JZlK6JRjEGk
userinfo: & {11 { 1590919540 0 jerry 0 }}

]

This is CustomClaims, but you can also use the simple method

The sample


package main

import (
  "fmt"
  "github.com/dgrijalva/jwt-go"
  "time"
)
const (
  SECRETKEY = "243223ffslsfsldfl412fdsfsdf"// The private key 
)
// The custom Claims
type CustomClaims struct {
  UserId int64
  jwt.StandardClaims
}
func main() {
  // generate token
  maxAge:=60*60*24
  // Create the Claims
  //claims := &jwt.StandardClaims{
  //  //  ExpiresAt: time.Now().Add(time.Duration(maxAge)*time.Second).Unix(), //  Expiration time must be set ,
  //  //  Issuer:  "jerry",//  You don't have to fill in the user name, 
  //  //}

  // Or customize it with the following claim
  claims := jwt.MapClaims{
    "id":    11,
    "name":    "jerry",
    "exp": time.Now().Add(time.Duration(maxAge)*time.Second).Unix(), //  Expiration time must be set ,
  }

  token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
  tokenString, err := token.SignedString([]byte(SECRETKEY))
  if err!=nil {
    fmt.Println(err)
  }
  fmt.Printf("token: %v\n", tokenString)

  // parsing token
  ret,err :=ParseToken(tokenString)
  if err!=nil {
    fmt.Println(err)
  }
  fmt.Printf("userinfo: %v\n", ret)
}

// parsing token
func ParseToken(tokenString string)(jwt.MapClaims,error) {
  token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
    // Don't forget to validate the alg is what you expect:
    if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
      return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
    }

    // hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
    return []byte(SECRETKEY), nil
  })
  if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
    return claims,nil
  } else {
    return nil,err
  }
}

Running results are similar

[

token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTA5MzUzMDUsImlkIjoxMSwibmFtZSI6ImplcnJ5In0.fapE0IiOEe_TqoMCThbNTHUvgWiHPEk0rm-9uPIcvPU
userinfo: map[exp:1.590935305e+09 id:11 name:jerry]

]

Summary:

The jwt generated by the server can be saved to cookie or localStorage (larger capacity than cookie). The token of HttpOnly should be added in cookie to prevent XSS attack. Use https with certificates whenever possible. session and jwt are not absolutely good or bad, each has its own application environment, please choose according to the actual situation.

The resources

https://github.com/guyan0319/golang_development_notes

https://godoc.org/github.com/dgrijalva/jwt-go

https://blog.csdn.net/weixin_43613053/article/details/84642140

https://www.cnblogs.com/flipped/p/12973557.html


Related articles: