JWT实现基于token的鉴权

一.介绍

  1.  1.JSON Web Token,简称JWT,本质是一个token,是一种紧凑的URL安全方法,用于在网络通信的双方之间传递。
  2.  2.一般放在HTTP的headers 参数里面的authorization里面,值的前面加Bearer关键字和空格。
  3.  3.主要用于身份认证和信息交换
  4.  4.由三部分组成,用英文句点连接(.),例如:xxxxxx.yyyyyy.zzzzzz

二.JWT的结构:JWT是三段(header.payload.signature)由小数点组成的字符串

a)header:头部用于描述关于JWT的基本的信息(如:类型,签名算法):

{
  "alg": "HS256",
  "typ": "JWT"
}

 b)payload:包含claims(有三种:标准中注册的声明,公共声明,私有声明)的消息体:

 标准中注册的声明,建议但不强制使用:

  >iss: jwt的签发者
  >sub: jwt所面向的用户
  >aud: 接收该jwt的一方 
  > exp: jwt的过期时间
  > nbf: 在该时间之前,该jwt都是不可用的
  > iat:jwt签发时间
  > jti:jwt的ID

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}
 c)Signature:验证JWT有没有被篡改


 生成过程:

 第一部分:将header的json对象进行base64编码

 第二部分:将payload的json对象进行base64编码

  第三部分:将拼接好的前两部分使用签名算法加密

 更详细的介绍:

 https://jwt.io/introduction/

 https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32

 (2)验证流程:

  1.  1.首次登录:提交用户名密码 
  2.  2.密码验证:通过后根据用户信息生成JWT
  3.  3.返回JWT:把JWT返回客户端,设置cookie或者设置到http请求头的Authorization中(一般是在请求头里加入Authorization并加上Bearer标注)
  4.  4.带JWT请求:每次访问服务器的时候都携带JWT,服务器根据JWT进行验证是否被篡改,没有的话获取信息

二.简单使用(使用jwt-go:https://github.com/dgrijalva/jwt-go

//密匙
const (
	SecretKey = "welcome"
)
//错误处理
func fatal(err error) {
	if err != nil {
		log.Fatal(err)
	}
}
//用户凭证
type UserCredentials struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

type User struct {
	ID       int    `json:"id"`
	Name     string `json:"name"`
	Username string `json:"username"`
	Password string `json:"password"`
}

type Response struct {
	Data string `json:"data"`
}

type Token struct {
	Token string `json:"token"`
}

func StartServer() {

	http.HandleFunc("/login", LoginHandler)

	http.Handle("/resource", negroni.New(
		negroni.HandlerFunc(ValidateTokenMiddleware),
		negroni.Wrap(http.HandlerFunc(ProtectedHandler)),
	))

	log.Println("Now listening...")
	http.ListenAndServe(":8080", nil)
}

func main() {
	StartServer()
}
//业务处理
func ProtectedHandler(w http.ResponseWriter, r *http.Request) {

	response := Response{"Gained access to protected resource"}
	JsonResponse(response, w)

}
//登录获取token
func LoginHandler(w http.ResponseWriter, r *http.Request) {

	var user UserCredentials
	err := json.NewDecoder(r.Body).Decode(&user)

	if err != nil {
		w.WriteHeader(http.StatusForbidden)
		fmt.Fprint(w, "Error in request")
		return
	}

	if strings.ToLower(user.Username) != "someone" {
		if user.Password != "password" {
			w.WriteHeader(http.StatusForbidden)
			fmt.Println("Error logging in")
			fmt.Fprint(w, "Invalid credentials")
			return
		}
	}

	token := jwt.New(jwt.SigningMethodHS256)
	claims := make(jwt.MapClaims)
	claims["exp"] = time.Now().Add(time.Hour * time.Duration(1)).Unix()
	claims["iat"] = time.Now().Unix()
	token.Claims = claims

	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintln(w, "Error extracting the key")
		fatal(err)
	}

	tokenString, err := token.SignedString([]byte(SecretKey))
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintln(w, "Error while signing the token")
		fatal(err)
	}

	response := Token{tokenString}
	JsonResponse(response, w)

}
//验证token
func ValidateTokenMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {

	token, err := request.ParseFromRequest(r, request.AuthorizationHeaderExtractor,
		func(token *jwt.Token) (interface{}, error) {
			return []byte(SecretKey), nil
		})

	if err == nil {
		if token.Valid {
			next(w, r)
		} else {
			w.WriteHeader(http.StatusUnauthorized)
			fmt.Fprint(w, "Token is not valid")
		}
	} else {
		w.WriteHeader(http.StatusUnauthorized)
		fmt.Fprint(w, "Unauthorized access to this resource")
	}

}

func JsonResponse(response interface{}, w http.ResponseWriter) {

	json, err := json.Marshal(response)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.Header().Set("Content-Type", "application/json")
	w.Write(json)
}
 测试:

JWT实现基于token的鉴权_第1张图片


JWT实现基于token的鉴权_第2张图片

你可能感兴趣的:(Go)