JWT achieve certification authority


1. What is the JWT

Web Token JSON (the JWT) is the most popular cross-domain authentication solutions. Simply put, OAuth is a kind of authorization mechanisms. Tell the owner of the data system, agreed to authorize third-party applications into the system, access to these data. System to produce a short-term order entry (token), is used instead of the password for using third party applications. .

Traditional authorization and authentication, for the persistent session data into the database or file persistence layer or the like, dependent on the data and the authorization verification persistence layer . In this way, the structure 维护成本大, implement 单点登录较为复杂, and not distributed architecture 无法支持横向扩展, 风险较大(if persistence layer fails, the entire certification system will hang up).

JWT is no need to persist session data is encrypted signature way to achieve the user identity authentication and authorization, a good solution 跨域身份验证, 分布式session共享, 单点登录and 横向扩展other issues.


Two. JWT standards

JWT consists of three parts, i.e. 头部, 负载the 签名. Token format token=头部+'.'+载荷+'.'+签名.

{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Nzg0MDQ5OTUsImlhdCI6MTU3ODQwMTM5NX0.waG8rvOZLM2pKDeKg7frMKlV8lAty1Og5LDjrVMJRsI"}

1. Header: for explaining cryptographically signed and the like, of the following types json obtained after base64 encoded JWT head.

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

2. Payload: standard defines seven fields, load json obtained after base64 encoded JWT load.

{
  iss (issuer):签发人
  exp (expiration time):过期时间
  sub (subject):主题
  aud (audience):受众
  nbf (Not Before):生效时间
  iat (Issued At):签发时间
  jti (JWT ID):编号
}

Example:

{
    "sub": "1",
    "iss": "http://localhost:8000/user/sign_up",
    "iat": 1451888119,
    "exp": 1454516119,
    "nbf": 1451888119,
    "jti": "37c107e4609ddbcc9c096ea5ee76c667"
}

3.Signature: a header and a payload with the connection number, together with a string key, an encryption algorithm obtained through the head declaration encrypted signature '.'.

HMACSHA256(
    base64UrlEncode(header) + "." +
    base64UrlEncode(payload),
    secret
)


III. Analysis of the core code

1. Data Structure

// A JWT Token.  Different fields will be used depending on whether you're
// creating or parsing/verifying a token.
type Token struct {
   Raw       string                 // The raw token.  Populated when you Parse a token
   Method    SigningMethod          // The signing method used or to be used
   Header    map[string]interface{} // (头部)The first segment of the token
   Claims    Claims                 // (负载)The second segment of the token
   Signature string                 // (签名)The third segment of the token.  Populated when you Parse a token
   Valid     bool                   // Is the token valid?  Populated when you Parse/Verify a token
}
// Structured version of Claims Section, as referenced at
// https://tools.ietf.org/html/rfc7519#section-4.1
// See examples for how to use this with your own claim types
type StandardClaims struct {
   Id        string `json:"jti,omitempty"`  //编号
   Subject   string `json:"sub,omitempty"`  //主题
   Issuer    string `json:"iss,omitempty"`  //签发人
   Audience  string `json:"aud,omitempty"`  //受众
   ExpiresAt int64  `json:"exp,omitempty"`  //过期时间
   IssuedAt  int64  `json:"iat,omitempty"` //签发时间
   NotBefore int64  `json:"nbf,omitempty"`  //生效时间
}

2. Generate Token

var(
   key []byte = []byte("This is secret!")
)
// 产生json web token
func GenToken() string {
   claims := &jwt.StandardClaims{
      NotBefore: int64(time.Now().Unix()),
      ExpiresAt: int64(time.Now().Unix() + 1000),
      Issuer:    "Bitch",
   }

   token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
   ss, err := token.SignedString(key)
   if err != nil {
      logs.Error(err)
      return ""
   }
   return ss
}

3. Verify Token

// 校验token是否有效
func CheckToken(token string) bool {
   _, err := jwt.Parse(token, func(*jwt.Token) (interface{}, error) {
      return key, nil
   })
   if err != nil {
      fmt.Println("parase with claims failed.", err)
      return false
   }
   return true
}


IV. Examples of login authorization

handler/auth.go

package handler

import (
   "fmt"
   "github.com/dgrijalva/jwt-go"
   "github.com/dgrijalva/jwt-go/request"
   "net/http"
)

const (
   SecretKey = "ODcyNDYsIMzY0N"
)

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")
   }
}

handler/account.go

package handler

import (
   "encoding/json"
   "fmt"
   "github.com/dgrijalva/jwt-go"
   "log"
   "net/http"
   "strings"
   "time"
)

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 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) != "admin" {
      if user.Password != "123456" {
         w.WriteHeader(http.StatusForbidden)
         fmt.Fprint(w, "Invalid credentials")
         return
      }
   }

   // 创建Token
   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)
}

func FundHandler(w http.ResponseWriter, r *http.Request) {
   response := Response{"账户余额:1000W"}
   JsonResponse(response, w)
}

func JsonResponse(response interface{}, w http.ResponseWriter) {
   obj, 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(obj)
}

main.go

import (
   "github.com/codegangsta/negroni"
   "log"
   "net/http"
   "proxy/handler"
)

func Server() {
   http.HandleFunc("/login", handler.LoginHandler)

   http.Handle("/data", negroni.New(
      negroni.HandlerFunc(handler.ValidateTokenMiddleware), //中间件
      negroni.Wrap(http.HandlerFunc(handler.FundHandler)),
   ))

   log.Println("服务已启动...")
   http.ListenAndServe(":8080", nil)
}

func main() {
   Server()
}


Five. JWT use

JWT client receives the server returns, can be stored in Cookieit, can also be stored in localStorage.

Thereafter, each time the client and server communications, must bring the JWT. You can put it inside Cookie sent automatically, but this 不能跨域. So a better approach is to put the HTTP request header Authorizationfield inside (or on the body of the POST request data inside).

Authorization: Bearer <token>


Six. JWT Notes

  1. JWT is not encrypted by default, but can be encrypted. After generating the original token can be used to change the token to encrypt again.
  2. JWT not only for authentication, may be used to exchange information. Make good use of JWT helps reduce the number of server requests the database.
  3. JWT biggest drawback is that the server does not save session state, JWT once issued, will remain in effect in the period.
  4. JWT should not be set too long a period, authentication information, so once information leaks, anyone can get a token of all rights.
  5. JWT order to reduce the risk of data theft and theft, JWT is recommended to use an encrypted HTTPS protocol for transmission.




Reference:
http://www.ruanyifeng.com/blog/2019/04/oauth_design.html 关于OAuth2.0
https://blog.csdn.net/wangshubo1989/article/details/74529333
https://blog.csdn.net/idwtwt/ Article This article was / the Details / 80,865,209
https://baijiahao.baidu.com/s?id=1608021814182894637&wfr=spider&for=pc
http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html

Guess you like

Origin www.cnblogs.com/Hollson/p/12169210.html