OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / go-kit / kit / auth / jwt / middleware.go
1 package jwt
2
3 import (
4         "context"
5         "errors"
6
7         jwt "github.com/dgrijalva/jwt-go"
8
9         "github.com/go-kit/kit/endpoint"
10 )
11
12 type contextKey string
13
14 const (
15         // JWTTokenContextKey holds the key used to store a JWT Token in the
16         // context.
17         JWTTokenContextKey contextKey = "JWTToken"
18
19         // JWTClaimsContextKey holds the key used to store the JWT Claims in the
20         // context.
21         JWTClaimsContextKey contextKey = "JWTClaims"
22 )
23
24 var (
25         // ErrTokenContextMissing denotes a token was not passed into the parsing
26         // middleware's context.
27         ErrTokenContextMissing = errors.New("token up for parsing was not passed through the context")
28
29         // ErrTokenInvalid denotes a token was not able to be validated.
30         ErrTokenInvalid = errors.New("JWT Token was invalid")
31
32         // ErrTokenExpired denotes a token's expire header (exp) has since passed.
33         ErrTokenExpired = errors.New("JWT Token is expired")
34
35         // ErrTokenMalformed denotes a token was not formatted as a JWT token.
36         ErrTokenMalformed = errors.New("JWT Token is malformed")
37
38         // ErrTokenNotActive denotes a token's not before header (nbf) is in the
39         // future.
40         ErrTokenNotActive = errors.New("token is not valid yet")
41
42         // ErrUnexpectedSigningMethod denotes a token was signed with an unexpected
43         // signing method.
44         ErrUnexpectedSigningMethod = errors.New("unexpected signing method")
45 )
46
47 // NewSigner creates a new JWT token generating middleware, specifying key ID,
48 // signing string, signing method and the claims you would like it to contain.
49 // Tokens are signed with a Key ID header (kid) which is useful for determining
50 // the key to use for parsing. Particularly useful for clients.
51 func NewSigner(kid string, key []byte, method jwt.SigningMethod, claims jwt.Claims) endpoint.Middleware {
52         return func(next endpoint.Endpoint) endpoint.Endpoint {
53                 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
54                         token := jwt.NewWithClaims(method, claims)
55                         token.Header["kid"] = kid
56
57                         // Sign and get the complete encoded token as a string using the secret
58                         tokenString, err := token.SignedString(key)
59                         if err != nil {
60                                 return nil, err
61                         }
62                         ctx = context.WithValue(ctx, JWTTokenContextKey, tokenString)
63
64                         return next(ctx, request)
65                 }
66         }
67 }
68
69 // ClaimsFactory is a factory for jwt.Claims.
70 // Useful in NewParser middleware.
71 type ClaimsFactory func() jwt.Claims
72
73 // MapClaimsFactory is a ClaimsFactory that returns
74 // an empty jwt.MapClaims.
75 func MapClaimsFactory() jwt.Claims {
76         return jwt.MapClaims{}
77 }
78
79 // StandardClaimsFactory is a ClaimsFactory that returns
80 // an empty jwt.StandardClaims.
81 func StandardClaimsFactory() jwt.Claims {
82         return &jwt.StandardClaims{}
83 }
84
85 // NewParser creates a new JWT token parsing middleware, specifying a
86 // jwt.Keyfunc interface, the signing method and the claims type to be used. NewParser
87 // adds the resulting claims to endpoint context or returns error on invalid token.
88 // Particularly useful for servers.
89 func NewParser(keyFunc jwt.Keyfunc, method jwt.SigningMethod, newClaims ClaimsFactory) endpoint.Middleware {
90         return func(next endpoint.Endpoint) endpoint.Endpoint {
91                 return func(ctx context.Context, request interface{}) (response interface{}, err error) {
92                         // tokenString is stored in the context from the transport handlers.
93                         tokenString, ok := ctx.Value(JWTTokenContextKey).(string)
94                         if !ok {
95                                 return nil, ErrTokenContextMissing
96                         }
97
98                         // Parse takes the token string and a function for looking up the
99                         // key. The latter is especially useful if you use multiple keys
100                         // for your application.  The standard is to use 'kid' in the head
101                         // of the token to identify which key to use, but the parsed token
102                         // (head and claims) is provided to the callback, providing
103                         // flexibility.
104                         token, err := jwt.ParseWithClaims(tokenString, newClaims(), func(token *jwt.Token) (interface{}, error) {
105                                 // Don't forget to validate the alg is what you expect:
106                                 if token.Method != method {
107                                         return nil, ErrUnexpectedSigningMethod
108                                 }
109
110                                 return keyFunc(token)
111                         })
112                         if err != nil {
113                                 if e, ok := err.(*jwt.ValidationError); ok {
114                                         switch {
115                                         case e.Errors&jwt.ValidationErrorMalformed != 0:
116                                                 // Token is malformed
117                                                 return nil, ErrTokenMalformed
118                                         case e.Errors&jwt.ValidationErrorExpired != 0:
119                                                 // Token is expired
120                                                 return nil, ErrTokenExpired
121                                         case e.Errors&jwt.ValidationErrorNotValidYet != 0:
122                                                 // Token is not active yet
123                                                 return nil, ErrTokenNotActive
124                                         case e.Inner != nil:
125                                                 // report e.Inner
126                                                 return nil, e.Inner
127                                         }
128                                         // We have a ValidationError but have no specific Go kit error for it.
129                                         // Fall through to return original error.
130                                 }
131                                 return nil, err
132                         }
133
134                         if !token.Valid {
135                                 return nil, ErrTokenInvalid
136                         }
137
138                         ctx = context.WithValue(ctx, JWTClaimsContextKey, token.Claims)
139
140                         return next(ctx, request)
141                 }
142         }
143 }