JWT 始终有效,即使传递的参数不正确
JWT is always valid even when incorrect params passed
我正在使用 jwt-go 库,并且我已经编写了在我的应用程序中实现它的测试。但是,无论我创建什么令牌,它都是 return 有效的。我猜我不是在检查什么。 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")
}
}
我不明白为什么最终测试会 return 有效。事实上,我可以在密码或电子邮件中放入任何内容,它们将被视为有效。
这是否可能与密码和电子邮件不是标准声明有关?
是的,因为 email
和 password
不是标准声明的一部分,所以您的示例中使用了验证方法
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
}
}
其他一些事情:
- 您不需要在 VerifeToken 中构建 calims,只需传递
Claims
对象或使用您自定义的 Valid
方法传递您自己的对象,这将满足接口
- 要创建令牌,您可以使用
NewWithClaims
方法
我正在使用 jwt-go 库,并且我已经编写了在我的应用程序中实现它的测试。但是,无论我创建什么令牌,它都是 return 有效的。我猜我不是在检查什么。 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")
}
}
我不明白为什么最终测试会 return 有效。事实上,我可以在密码或电子邮件中放入任何内容,它们将被视为有效。
这是否可能与密码和电子邮件不是标准声明有关?
是的,因为 email
和 password
不是标准声明的一部分,所以您的示例中使用了验证方法
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
}
}
其他一些事情:
- 您不需要在 VerifeToken 中构建 calims,只需传递
Claims
对象或使用您自定义的Valid
方法传递您自己的对象,这将满足接口 - 要创建令牌,您可以使用
NewWithClaims
方法