jwt note

作者: robertzhai | 来源:发表于2023-05-29 20:17 被阅读0次

    what is jwt

    • Json Web Token
    • 是一个常用语HTTP的客户端和服务端间进行身份认证和鉴权的标准规范,使用JWT可以允许我们在用户和服务器之间传递安全可靠的信息。

    Cookie Session Jwt

    • Cookie 存在客户端,后续请求会携带
    • Session 存在服务器端,配合Cookie使用
    • Jwt 存在客户端, 随请求头 Authorization 发给服务端做校验

    Authorization: Bearer <token>

    JWT Token组成部分

    image.png
    • 不要在header和payload中放置敏感信息,除非加密

    Do note that for signed tokens this information, though protected against tampering, is readable by anyone. Do not put secret information in the payload or header elements of a JWT unless it is encrypted.

    • header 、payload 通过base64_decode可以解析成明文
    • signature 是sha256算法和密钥加密生成的
    • 服务端验证token的过程是解析token的明文部分header和payload,再做一次签名比对结果和signature是否一致
    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
    
    php -r " echo base64_decode('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9');"
    输出:
    php -r " echo base64_decode('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9');"
    {"alg":"HS256","typ":"JWT"}
    
    php -r " echo base64_decode('eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ');"
    输出:
    {"sub":"1234567890","name":"John Doe","iat":1516239022}
    
    // SignedString creates and returns a complete, signed JWT.
    // The token is signed using the SigningMethod specified in the token.
    func (t *Token) SignedString(key interface{}) (string, error) {
        var sig, sstr string
        var err error
        if sstr, err = t.SigningString(); err != nil {
            return "", err
        }
        if sig, err = t.Method.Sign(sstr, key); err != nil {
            return "", err
        }
        return strings.Join([]string{sstr, sig}, "."), nil
    }
    
    // Sign implements token signing for the SigningMethod.
    // Key must be []byte  生成 token中的 signature
    func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) (string, error) {
        if keyBytes, ok := key.([]byte); ok {
            if !m.Hash.Available() {
                return "", ErrHashUnavailable
            }
    
            hasher := hmac.New(m.Hash.New, keyBytes)
            hasher.Write([]byte(signingString))
    
            return EncodeSegment(hasher.Sum(nil)), nil
        }
    
        return "", ErrInvalidKeyType
    }
    
    // 解析 token
    func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {
        token, parts, err := p.ParseUnverified(tokenString, claims)
        if err != nil {
            return token, err
        }
    
        // Verify signing method is in the required set
        if p.ValidMethods != nil {
            var signingMethodValid = false
            var alg = token.Method.Alg()
            for _, m := range p.ValidMethods {
                if m == alg {
                    signingMethodValid = true
                    break
                }
            }
            if !signingMethodValid {
                // signing method is not in the listed set
                return token, NewValidationError(fmt.Sprintf("signing method %v is invalid", alg), ValidationErrorSignatureInvalid)
            }
        }
    
        // Lookup key
        var key interface{}
        if keyFunc == nil {
            // keyFunc was not provided.  short circuiting validation
            return token, NewValidationError("no Keyfunc was provided.", ValidationErrorUnverifiable)
        }
        if key, err = keyFunc(token); err != nil {
            // keyFunc returned an error
            if ve, ok := err.(*ValidationError); ok {
                return token, ve
            }
            return token, &ValidationError{Inner: err, Errors: ValidationErrorUnverifiable}
        }
    
        vErr := &ValidationError{}
    
        // Validate Claims
        if !p.SkipClaimsValidation {
            if err := token.Claims.Valid(); err != nil {
    
                // If the Claims Valid returned an error, check if it is a validation error,
                // If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set
                if e, ok := err.(*ValidationError); !ok {
                    vErr = &ValidationError{Inner: err, Errors: ValidationErrorClaimsInvalid}
                } else {
                    vErr = e
                }
            }
        }
    
        // Perform validation
        token.Signature = parts[2]
            // 解析完token 重新做一次签名,比对签名是否一致
        if err = token.Method.Verify(strings.Join(parts[0:2], "."), token.Signature, key); err != nil {
            vErr.Inner = err
            vErr.Errors |= ValidationErrorSignatureInvalid
        }
    
        if vErr.valid() {
            token.Valid = true
            return token, nil
        }
    
        return token, vErr
    }
    
    
    

    工作原理

    image.png image.png
    • token 可以存于浏览器的localStorage

    https://developer.mozilla.org/zh-CN/docs/Web/API/Window/localStorage
    https://juejin.cn/post/7149380173027573767

    why use jwt

    • 无状态和可扩展性
    • 安全: 防止CSRF攻击;token过期重新认证

    ref

    相关文章

      网友评论

          本文标题:jwt note

          本文链接:https://www.haomeiwen.com/subject/axxsedtx.html