edit: jwt
add: VerifyOption
edit: Verify
This commit is contained in:
parent
a65a3fe0b3
commit
876df38907
30
jwt/jwt.go
30
jwt/jwt.go
@ -7,6 +7,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.daebt.dev/auth/algo"
|
||||
)
|
||||
@ -24,6 +25,11 @@ var (
|
||||
//
|
||||
ErrNotJWTType = errors.New("token of not JWT type")
|
||||
ErrAlgorithmMismatch = errors.New("token is signed by another algorithm")
|
||||
//
|
||||
Err_1 = errors.New("заданного владельца(ов) не существует")
|
||||
Err_2 = errors.New("заданного aud не существует")
|
||||
ErrExpired = errors.New("token expired")
|
||||
ErrNotActivated = errors.New("token yet not activated")
|
||||
)
|
||||
|
||||
type Token struct {
|
||||
@ -80,7 +86,7 @@ func (t *Token) decodeSegment(str string, val any) error {
|
||||
return json.Unmarshal(buf, val)
|
||||
}
|
||||
|
||||
func (t *Token) Verify(a algo.Algorithm) error {
|
||||
func (t *Token) Verify(a algo.Algorithm, o ...VerifyOption) error {
|
||||
if a == nil {
|
||||
return ErrAlgorithmNil
|
||||
}
|
||||
@ -91,6 +97,28 @@ func (t *Token) Verify(a algo.Algorithm) error {
|
||||
return ErrAlgorithmMismatch
|
||||
}
|
||||
|
||||
if val, err := t.Payload.GetExpirationTime(); err != nil && !errors.Is(err, ErrKeyNotExist) {
|
||||
return err
|
||||
} else if !errors.Is(err, ErrKeyNotExist) {
|
||||
if time.Now().After(val) {
|
||||
return ErrExpired
|
||||
}
|
||||
}
|
||||
|
||||
if val, err := t.Payload.GetNotBefore(); err != nil && !errors.Is(err, ErrKeyNotExist) {
|
||||
return err
|
||||
} else if !errors.Is(err, ErrKeyNotExist) {
|
||||
if time.Now().Before(val) {
|
||||
return ErrNotActivated
|
||||
}
|
||||
}
|
||||
|
||||
for _, f := range o {
|
||||
if err := f(t); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return a.Verify(t.body, t.sign)
|
||||
}
|
||||
|
||||
|
||||
126
jwt/jwt_test.go
126
jwt/jwt_test.go
@ -1,6 +1,7 @@
|
||||
package jwt_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
@ -47,89 +48,92 @@ func TestCreate(t *testing.T) {
|
||||
|
||||
tm := time.Now()
|
||||
|
||||
var data = [][]jwt.Option{
|
||||
var data = []*struct {
|
||||
o []jwt.Option
|
||||
v []jwt.VerifyOption
|
||||
e error
|
||||
}{
|
||||
{
|
||||
jwt.WithHeaderKeyId([]byte("019451f1-f789-72a6-836d-3bc6146ad76a")),
|
||||
[]jwt.Option{
|
||||
jwt.WithIssuer("https://git.daebt.dev"),
|
||||
jwt.WithAudience("https://0.example.com"),
|
||||
jwt.WithSubject("example:0"),
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
jwt.WithHeaderKeyId([]byte("019451f1-f789-72a6-836d-3bc6146ad76a")),
|
||||
[]jwt.Option{
|
||||
jwt.WithIssuer("https://git.daebt.dev"),
|
||||
jwt.WithAudience("https://1.example.com"),
|
||||
jwt.WithSubject("example:1"),
|
||||
jwt.WithIssuedAt(tm),
|
||||
jwt.WithExpirationTime(tm.Add(time.Hour)),
|
||||
},
|
||||
{
|
||||
jwt.WithHeaderKeyId([]byte("019451f1-f789-72a6-2911-3bc6146ad76a")),
|
||||
jwt.WithIssuer("https://git.daebt.dev"),
|
||||
jwt.WithAudience("https://2.example.com"),
|
||||
jwt.WithSubject("example:2"),
|
||||
jwt.WithIssuedAt(tm),
|
||||
jwt.WithNotBefore(tm),
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
jwt.WithHeaderKeyId([]byte("019451f1-f789-72a6-2911-3bc6146ad76a")),
|
||||
[]jwt.Option{
|
||||
jwt.WithIssuer("https://git.daebt.dev"),
|
||||
jwt.WithAudience("https://3.example.com"),
|
||||
jwt.WithSubject("example:3"),
|
||||
jwt.WithIssuedAt(tm),
|
||||
jwt.WithNotBefore(tm.Add(time.Minute)),
|
||||
jwt.WithExpirationTime(tm.Add(-time.Hour)),
|
||||
},
|
||||
nil,
|
||||
jwt.ErrExpired,
|
||||
},
|
||||
{
|
||||
jwt.WithHeaderKeyId([]byte("019451f1-f789-72a6-2911-3bc6146ad76a")),
|
||||
[]jwt.Option{
|
||||
jwt.WithIssuer("https://git.daebt.dev"),
|
||||
jwt.WithAudience("https://4.example.com"),
|
||||
jwt.WithSubject("example:4"),
|
||||
jwt.WithIssuedAt(tm),
|
||||
jwt.WithNotBefore(tm.Add(time.Minute)),
|
||||
jwt.WithExpirationTime(tm.Add(time.Hour)),
|
||||
jwt.WithNotBefore(tm.Add(time.Hour)),
|
||||
},
|
||||
nil,
|
||||
jwt.ErrNotActivated,
|
||||
},
|
||||
{
|
||||
[]jwt.Option{
|
||||
jwt.WithIssuer("https://git.daebt.dev"),
|
||||
jwt.WithIssuedAt(tm),
|
||||
},
|
||||
[]jwt.VerifyOption{
|
||||
jwt.WithVerifyIssuer("https://git.daebt.dev"),
|
||||
},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
[]jwt.Option{
|
||||
jwt.WithIssuedAt(tm),
|
||||
},
|
||||
[]jwt.VerifyOption{
|
||||
jwt.WithVerifyIssuer(),
|
||||
},
|
||||
jwt.ErrKeyNotExist,
|
||||
},
|
||||
{
|
||||
[]jwt.Option{
|
||||
jwt.WithIssuer("https://git.daebt.dev"),
|
||||
jwt.WithIssuedAt(tm),
|
||||
},
|
||||
[]jwt.VerifyOption{
|
||||
jwt.WithVerifyIssuer(),
|
||||
},
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, v := range data {
|
||||
// t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||
val, err := jwt.New(v...).Sign(alg)
|
||||
for i, v := range data {
|
||||
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||
val, err := jwt.New(v.o...).Sign(alg)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
// t.Log(val)
|
||||
fmt.Printf(`"%s",`, val)
|
||||
// })
|
||||
|
||||
tkn, err := jwt.Parse(val)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
if err := tkn.Verify(alg, v.v...); !errors.Is(err, v.e) {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// func TestJwt(t *testing.T) {
|
||||
// alg, err := rs.NewRS256(
|
||||
// rs.WithGenerateKey(2048),
|
||||
// )
|
||||
// if err != nil {
|
||||
// t.Fatal(err.Error())
|
||||
// }
|
||||
|
||||
// tkn := New(
|
||||
// WithSubject("main-jwt-token"),
|
||||
// )
|
||||
|
||||
// str, err := tkn.Sign(alg)
|
||||
// if err != nil {
|
||||
// t.Fatal(err.Error())
|
||||
// }
|
||||
|
||||
// tkn, err = Parse(str)
|
||||
// if err != nil {
|
||||
// t.Fatal(err.Error())
|
||||
// }
|
||||
|
||||
// if err := tkn.Verify(alg); err != nil {
|
||||
// t.Fatal(err.Error())
|
||||
// }
|
||||
|
||||
// tkn.Payload.Range(func(key string, val any) bool {
|
||||
// t.Log(key, val)
|
||||
// return true
|
||||
// })
|
||||
// }
|
||||
|
||||
@ -39,21 +39,22 @@ func WithAudience(aud ...string) Option {
|
||||
// WithExpirationTime устанавливает время истечения срока действия, по истечении которого JWT НЕ ДОЛЖЕН быть принят к обработке
|
||||
func WithExpirationTime(exp time.Time) Option {
|
||||
return func(t *Token) {
|
||||
t.Payload.AppendArg("exp", exp)
|
||||
|
||||
t.Payload.AppendArg("exp", exp.Unix())
|
||||
}
|
||||
}
|
||||
|
||||
// WithNotBefore устанавливает время, до которого JWT НЕ ДОЛЖЕН быть принят к обработке
|
||||
func WithNotBefore(nbf time.Time) Option {
|
||||
return func(t *Token) {
|
||||
t.Payload.AppendArg("nbf", nbf)
|
||||
t.Payload.AppendArg("nbf", nbf.Unix())
|
||||
}
|
||||
}
|
||||
|
||||
// WithIssuedAt устанавливает время, когда был создан JWT
|
||||
func WithIssuedAt(iat time.Time) Option {
|
||||
return func(t *Token) {
|
||||
t.Payload.AppendArg("iat", iat)
|
||||
t.Payload.AppendArg("iat", iat.Unix())
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,3 +89,50 @@ func WithHeaderKeyId(kid []byte) Option {
|
||||
t.Header.AppendArg("kid", base64.RawURLEncoding.EncodeToString(kid))
|
||||
}
|
||||
}
|
||||
|
||||
type VerifyOption func(*Token) error
|
||||
|
||||
// WithVerifyIssuer проверяет существуют ли заданные владельцы
|
||||
func WithVerifyIssuer(iss ...string) VerifyOption {
|
||||
return func(t *Token) error {
|
||||
val, err := t.Payload.GetIssuer()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(iss) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, v := range iss {
|
||||
if v == val {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return Err_1
|
||||
}
|
||||
}
|
||||
|
||||
func WithVerifyAudience(aud ...string) VerifyOption {
|
||||
return func(t *Token) error {
|
||||
val, err := t.Payload.GetAudience()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(aud) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, a := range aud {
|
||||
for _, v := range val {
|
||||
if a == v {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Err_2
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user