【问题标题】:JWT is always valid even when incorrect params passed即使传递了不正确的参数,JWT 也始终有效
【发布时间】:2020-04-29 04:44:47
【问题描述】:

我正在使用 jwt-go 库,并且我已经编写了测试以在我的应用程序中实现它。但是,无论我创建什么令牌,它都会作为有效返回。我猜我不是在检查什么。 documentation 已过期,因为声明不再支持索引。

这是我的应用程序代码:

// AuthService - provides authentication
type AuthService struct{}

// CreateToken - signs and encrypts auth token
func (a *AuthService) CreateToken(email, password string) (string, error) {
    token := jwt.New(jwt.SigningMethodHS256)
    token.Claims = buildClaims(email, password)

    tokenString, err := token.SignedString([]byte(os.Getenv("AUTH_SECRET")))
    if err != nil {
        return "", err
    }

    return tokenString, nil
}

// VerifyToken - ensures that the token is valid
func (a *AuthService) VerifyToken(email, password, token string) bool {
    claims := buildClaims(email, password)
    parser := new(jwt.Parser)

    parsedClaims, _ := parser.ParseWithClaims(token, claims, getKey)

    return parsedClaims.Valid
}

func getKey(t *jwt.Token) (interface{}, error) {
    return []byte(os.Getenv("AUTH_SECRET")), nil
}

func buildClaims(email, password string) jwt.Claims {
    claims := make(jwt.MapClaims)

    claims["email"] = email
    claims["password"] = password
    claims["exp"] = time.Now().Add(time.Hour * 24).Unix()
    claims["iat"] = time.Now().Unix()

    return claims
}

这是失败的测试:

func TestAuthToken(t *testing.T) {
    // var err error
    var valid bool

    os.Setenv("AUTH_SECRET", "secret")

    email := "test@test.com"
    password := "password"

    auth := &AuthService{}

    token, err := auth.CreateToken(email, password)
    if err != nil {
        t.Errorf("AuthService failed to create a token: %v", err)
    }

    valid = auth.VerifyToken(email, password, token)
    if !valid {
        t.Errorf("AuthService failed to verify token: %v", err)
    }

    valid = auth.VerifyToken("invalid", "", token)
    fmt.Println(valid)
    if valid {
        t.Error("AuthService verified a bad password")
    }
}

我不明白为什么最终测试会返回有效。事实上,我可以在密码或电子邮件中输入任何内容,它们将被视为有效。

这可能与密码和电子邮件不是标准声明有关吗?

【问题讨论】:

    标签: go jwt jwt-go


    【解决方案1】:

    是的,这是因为 emailpassword 不是标准声明的一部分,因此您的示例中使用了验证方法

    func (m MapClaims) Valid() error {
        vErr := new(ValidationError)
        now := TimeFunc().Unix()
    
        if m.VerifyExpiresAt(now, false) == false {
            vErr.Inner = errors.New("Token is expired")
            vErr.Errors |= ValidationErrorExpired
        }
    
        if m.VerifyIssuedAt(now, false) == false {
            vErr.Inner = errors.New("Token used before issued")
            vErr.Errors |= ValidationErrorIssuedAt
        }
    
        if m.VerifyNotBefore(now, false) == false {
            vErr.Inner = errors.New("Token is not valid yet")
            vErr.Errors |= ValidationErrorNotValidYet
        }
    
        if vErr.valid() {
            return nil
        }
    
        return vErr
    }
    

    您真的需要验证密码和用户名吗?因为在传递整个令牌时已经检查过它。但是如果你无论如何都想检查这些数据,你可以做一些struct

    type CustomClaims struct {
        jwt.StandardClaims
        Email    string `json:"email,omitempty"`
        Password string `json:"password,omitempty"`
    }
    

    然后您可以在解析 calims 后在您的 VerifyToken method 令牌中进行验证。

    if claims, ok := parsedClaims.Claims.(*CustomClaims); ok {
        if claims.Password != password {
            parsedClaims.Valid = false
        }
        if claims.Email != username {
            parsedClaims.Valid = false
        }
    }
    

    其他一些事情:

    1. 您无需在 VerifeToken 中构建calims,只需传递Claims 对象或使用您自定义的Valid 方法传递您自己的满足接口的方法
    2. 要创建令牌,您可以使用NewWithClaims 方法

    【讨论】:

    • 你完全正确。我是 JWT 的新手,我的理解是不正确的。令牌字符串本身就是验证声明的内容。很好的例子。感谢添加。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-26
    • 2017-12-17
    相关资源
    最近更新 更多