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:
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