Skip to content

Instantly share code, notes, and snippets.

@zhangxiang958
Last active February 18, 2024 03:38
Show Gist options
  • Select an option

  • Save zhangxiang958/cc576a4fe3e9528c8b0dc034915965a7 to your computer and use it in GitHub Desktop.

Select an option

Save zhangxiang958/cc576a4fe3e9528c8b0dc034915965a7 to your computer and use it in GitHub Desktop.
learn how jwt work
package main
import (
"encoding/json"
"errors"
"fmt"
"log"
"net/http"
"time"
"github.com/golang-jwt/jwt"
)
type Message struct {
Status string `json:"status"`
Info string `json:"info"`
}
// 这里需要 64 位的字符串,我自己乱写的,可以自己生成一个 64 长度的字符串
// var secretKey ed25519.PrivateKey = []byte("go-jwt1111111111111111111111111111111111111111111111111111111111")
var secretKey = []byte("go-jwt")
var jwtExpireMinute int64 = 10
var (
PrivateAuthHeaderName = "X-Private-Auth-Username"
)
func generateJWT() (string, error) {
token := jwt.New(jwt.SigningMethodHS256)
claims := token.Claims.(jwt.MapClaims)
// claims["exp"] = time.Now().Add(time.Duration(jwtExpireMinute) * time.Minute)
// 这里需要根据 mapClaims 和 普通的 StandardClaims 区分开,另外 exp 的值需要和不同的 xxxClaims 匹配,map 就是需要是 float64 或者 json.Number
/**
type Claims struct {
Username string `json:"username"`
Password string `json:"password"`
jwt.StandardClaims
}
*/
claims["exp"] = float64(time.Now().Add(time.Duration(jwtExpireMinute) * time.Minute).Unix())
claims["authorized"] = true
claims["user"] = "username"
tokenString, err := token.SignedString(secretKey)
if err != nil {
log.Printf("generateJWT SignedString err: %+v", err)
return "Sign Error", nil
}
return tokenString, nil
}
func handlePage(writer http.ResponseWriter, request *http.Request) {
writer.Header().Set("Content-Type", "application/json")
user := request.Header.Get(PrivateAuthHeaderName)
var message Message
if err := json.NewDecoder(request.Body).Decode(&message); err != nil {
log.Printf("handlePage message json decode err: %+v", err)
return
}
if err := json.NewEncoder(writer).Encode(message); err != nil {
log.Printf("handlePage message json encode err: %+v", err)
return
}
log.Println("success return message, ", user)
}
func verifyJWT(endpointHandler func(writer http.ResponseWriter, request *http.Request)) http.HandlerFunc {
return func(writer http.ResponseWriter, request *http.Request) {
if request.Header["Token"] != nil {
token, err := jwt.Parse(request.Header["Token"][0], func(t *jwt.Token) (interface{}, error) {
_, ok := t.Method.(*jwt.SigningMethodHMAC)
if !ok {
writer.WriteHeader(http.StatusUnauthorized)
_, err := writer.Write([]byte("You're Unauthorized!"))
if err != nil {
log.Printf("token parse keyFunc StatusUnauthorized err:%+v", err)
return nil, err
}
return "", nil
}
return secretKey, nil
})
if err != nil {
writer.WriteHeader(http.StatusUnauthorized)
_, writerErr := writer.Write([]byte("You're Unauthorized due to error parsing the JWT"))
if writerErr != nil {
return
}
return
}
if !token.Valid {
writer.WriteHeader(http.StatusUnauthorized)
_, err := writer.Write([]byte("You're Unauthorized due to No token in the header"))
if err != nil {
return
}
return
}
if err := extractClaims(token, request); err != nil {
writer.WriteHeader(http.StatusUnauthorized)
_, err := writer.Write([]byte("You're Unauthorized due to token parse error in the header"))
if err != nil {
return
}
return
}
endpointHandler(writer, request)
return
}
writer.WriteHeader(http.StatusUnauthorized)
_, err := writer.Write([]byte("You're Unauthorized due to No token in the header"))
if err != nil {
return
}
}
}
func extractClaims(token *jwt.Token, request *http.Request) error {
if token == nil {
return errors.New("extractClaims with empty token")
}
if !token.Valid {
return errors.New("extractClaims with invalid token")
}
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
return errors.New("extractClaims with invalid type token claims")
}
username := claims["user"].(string)
request.Header.Add(PrivateAuthHeaderName, username)
return nil
}
func auth(writer http.ResponseWriter, request *http.Request) {
token, err := generateJWT()
if err != nil {
return
}
// client := &http.Client{}
// request, _ := http.NewRequest("POST", "<http://localhost:8080/>", nil)
request.Header.Set("Token", token)
_, err = writer.Write([]byte(token))
if err != nil {
return
}
// _, _ = client.Do(request)
}
func main() {
http.HandleFunc("/home", verifyJWT(handlePage))
http.HandleFunc("/login", auth)
serverPort := 8099
if err := http.ListenAndServe(fmt.Sprintf(":%v", serverPort), nil); err != nil {
log.Println("There was an error listening on ", fmt.Sprintf(":%v", serverPort), err)
return
}
}
go-getJWT-Token:
curl --location '127.0.0.1:8099/login'
go-testReq:
curl --location '127.0.0.1:8099/home' \
--header 'Content-Type: application/json' \
--header 'Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdXRob3JpemVkIjp0cnVlLCJleHAiOjE3MDgyMjc0MDMsInVzZXIiOiJ1c2VybmFtZSJ9.aXMV7LxV7dEL_v8gtWqOl1gaesDkfIEQjfAJUZWFMdc' \
--data '{\
"status": "200",\
"info": "test"\
}'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment