mirror of
https://github.com/kataras/iris.git
synced 2025-03-21 11:16:28 +01:00
jwt: add VerifyJSON and ReadJSON helpers
This commit is contained in:
parent
1864f99145
commit
a412ee55ae
|
@ -2,6 +2,7 @@ package jwt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto"
|
"crypto"
|
||||||
|
"encoding/json"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -449,6 +450,17 @@ func Get(ctx *context.Context) interface{} {
|
||||||
switch v := tok.Value.(type) {
|
switch v := tok.Value.(type) {
|
||||||
case *context.Map:
|
case *context.Map:
|
||||||
return *v
|
return *v
|
||||||
|
case *json.RawMessage:
|
||||||
|
// This is useful when we can accept more than one
|
||||||
|
// type of JWT token in the same request path,
|
||||||
|
// but we also want to keep type safety.
|
||||||
|
// Usage:
|
||||||
|
// type myClaims struct { Roles []string `json:"roles"`}
|
||||||
|
// v := jwt.Get(ctx)
|
||||||
|
// var claims myClaims
|
||||||
|
// jwt.Unmarshal(v, &claims)
|
||||||
|
// [...claims.Roles]
|
||||||
|
return *v
|
||||||
default:
|
default:
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
@ -621,7 +633,19 @@ func (j *JWT) TokenPair(refreshMaxAge time.Duration, refreshClaims interface{},
|
||||||
// - The Context Logout method is set if Blocklist was initialized
|
// - The Context Logout method is set if Blocklist was initialized
|
||||||
// Any error is captured to the Context,
|
// Any error is captured to the Context,
|
||||||
// which can be retrieved by a `ctx.GetErr()` call.
|
// which can be retrieved by a `ctx.GetErr()` call.
|
||||||
|
//
|
||||||
|
// See `VerifyJSON` too.
|
||||||
func (j *JWT) Verify(newPtr func() interface{}, expections ...Expectation) context.Handler {
|
func (j *JWT) Verify(newPtr func() interface{}, expections ...Expectation) context.Handler {
|
||||||
|
if newPtr == nil {
|
||||||
|
newPtr = func() interface{} {
|
||||||
|
// Return a map here as the default type one,
|
||||||
|
// as it does allow .Get callers to access its fields with ease
|
||||||
|
// (although, I always recommend using structs for type-safety and
|
||||||
|
// also they can accept a required tag option too).
|
||||||
|
return &context.Map{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
expections = append(expections, MeetRequirements(newPtr()))
|
expections = append(expections, MeetRequirements(newPtr()))
|
||||||
|
|
||||||
return func(ctx *context.Context) {
|
return func(ctx *context.Context) {
|
||||||
|
@ -647,6 +671,39 @@ func (j *JWT) Verify(newPtr func() interface{}, expections ...Expectation) conte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VerifyJSON works like `Verify` but instead it
|
||||||
|
// binds its "newPtr" function to return a raw JSON message.
|
||||||
|
// This allows the caller to bind this JSON message to any Go structure (or map).
|
||||||
|
// This is useful when we can accept more than one
|
||||||
|
// type of JWT token in the same request path,
|
||||||
|
// but we also want to keep type safety.
|
||||||
|
// Usage:
|
||||||
|
// app.Use(jwt.VerifyJSON())
|
||||||
|
// Inside a route Handler:
|
||||||
|
// claims := struct { Roles []string `json:"roles"`}{}
|
||||||
|
// jwt.ReadJSON(ctx, &claims)
|
||||||
|
// ...access to claims.Roles as []string
|
||||||
|
func (j *JWT) VerifyJSON(expections ...Expectation) context.Handler {
|
||||||
|
return j.Verify(func() interface{} {
|
||||||
|
return new(json.RawMessage)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadJSON is a helper which binds "claimsPtr" to the
|
||||||
|
// raw JSON token claims.
|
||||||
|
// Use inside the handlers when `VerifyJSON()` middleware was registered.
|
||||||
|
func ReadJSON(ctx *context.Context, claimsPtr interface{}) error {
|
||||||
|
v := Get(ctx)
|
||||||
|
if v == nil {
|
||||||
|
return ErrMissing
|
||||||
|
}
|
||||||
|
data, ok := v.(json.RawMessage)
|
||||||
|
if !ok {
|
||||||
|
return ErrMissing
|
||||||
|
}
|
||||||
|
return Unmarshal(data, claimsPtr)
|
||||||
|
}
|
||||||
|
|
||||||
// NewUser returns a new User based on the given "opts".
|
// NewUser returns a new User based on the given "opts".
|
||||||
// The caller can modify the User until its `GetToken` is called.
|
// The caller can modify the User until its `GetToken` is called.
|
||||||
func (j *JWT) NewUser(opts ...UserOption) *User {
|
func (j *JWT) NewUser(opts ...UserOption) *User {
|
||||||
|
|
|
@ -192,9 +192,7 @@ func TestVerifyMap(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test map + Verify middleware.
|
// Test map + Verify middleware.
|
||||||
userAPI.Post("/middleware", j.Verify(func() interface{} {
|
userAPI.Post("/middleware", j.Verify(nil), func(ctx iris.Context) {
|
||||||
return &iris.Map{} // or &map[string]interface{}{}
|
|
||||||
}), func(ctx iris.Context) {
|
|
||||||
claims := jwt.Get(ctx)
|
claims := jwt.Get(ctx)
|
||||||
ctx.JSON(claims)
|
ctx.JSON(claims)
|
||||||
})
|
})
|
||||||
|
@ -265,6 +263,38 @@ func TestVerifyStruct(t *testing.T) {
|
||||||
e.POST("/user").WithHeader("Authorization", "Bearer "+token).Expect().Status(httptest.StatusUnauthorized)
|
e.POST("/user").WithHeader("Authorization", "Bearer "+token).Expect().Status(httptest.StatusUnauthorized)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVerifyJSON(t *testing.T) {
|
||||||
|
j := jwt.HMAC(testMaxAge, "secret", "itsa16bytesecret")
|
||||||
|
|
||||||
|
app := iris.New()
|
||||||
|
app.Get("/user/auth", func(ctx iris.Context) {
|
||||||
|
err := j.WriteToken(ctx, iris.Map{"roles": []string{"admin"}})
|
||||||
|
if err != nil {
|
||||||
|
ctx.StopWithError(iris.StatusUnauthorized, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.Post("/", j.VerifyJSON(), func(ctx iris.Context) {
|
||||||
|
claims := struct {
|
||||||
|
Roles []string `json:"roles"`
|
||||||
|
}{}
|
||||||
|
jwt.ReadJSON(ctx, &claims)
|
||||||
|
ctx.JSON(claims)
|
||||||
|
})
|
||||||
|
|
||||||
|
e := httptest.New(t, app, httptest.LogLevel("error"))
|
||||||
|
token := e.GET("/user/auth").Expect().Status(httptest.StatusOK).Body().Raw()
|
||||||
|
if token == "" {
|
||||||
|
t.Fatalf("empty token")
|
||||||
|
}
|
||||||
|
|
||||||
|
e.POST("/").WithHeader("Authorization", "Bearer "+token).Expect().
|
||||||
|
Status(httptest.StatusOK).JSON().Equal(iris.Map{"roles": []string{"admin"}})
|
||||||
|
|
||||||
|
e.POST("/").Expect().Status(httptest.StatusUnauthorized)
|
||||||
|
}
|
||||||
|
|
||||||
func TestVerifyUserAndExpected(t *testing.T) { // Tests the jwt.User struct + context validator + expected.
|
func TestVerifyUserAndExpected(t *testing.T) { // Tests the jwt.User struct + context validator + expected.
|
||||||
maxAge := testMaxAge / 2
|
maxAge := testMaxAge / 2
|
||||||
j := jwt.HMAC(maxAge, "secret", "itsa16bytesecret")
|
j := jwt.HMAC(maxAge, "secret", "itsa16bytesecret")
|
||||||
|
|
Loading…
Reference in New Issue
Block a user