preparing for the Iris control panel -- stay tuned when you hear my new project name 'cornea'

Former-commit-id: 8c0ada865ee17801efe90b197bf49bdbd55f636b
This commit is contained in:
Gerasimos (Makis) Maropoulos 2018-08-06 04:20:59 +03:00
parent e5f6bce86f
commit 293c29d6e7
4 changed files with 47 additions and 20 deletions

View File

@ -13,21 +13,21 @@ import (
// path, i.e the min as param name and 1 as the param argument. // path, i.e the min as param name and 1 as the param argument.
type Template struct { type Template struct {
// Src is the original template given by the client // Src is the original template given by the client
Src string Src string `json:"src"`
Params []TemplateParam Params []TemplateParam `json:"params"`
} }
// TemplateParam is the parsed macro parameter's template // TemplateParam is the parsed macro parameter's template
// they are being used to describe the param's syntax result. // they are being used to describe the param's syntax result.
type TemplateParam struct { type TemplateParam struct {
Src string // the unparsed param'false source Src string `json:"src"` // the unparsed param'false source
// Type is not useful anywhere here but maybe // Type is not useful anywhere here but maybe
// it's useful on host to decide how to convert the path template to specific router's syntax // it's useful on host to decide how to convert the path template to specific router's syntax
Type ast.ParamType Type ast.ParamType `json:"type"`
Name string Name string `json:"name"`
ErrCode int ErrCode int `json:"errCode"`
TypeEvaluator EvaluatorFunc TypeEvaluator EvaluatorFunc `json:"-"`
Funcs []EvaluatorFunc Funcs []EvaluatorFunc `json:"-"`
} }
// Parse takes a full route path and a macro map (macro map contains the macro types with their registered param functions) // Parse takes a full route path and a macro map (macro map contains the macro types with their registered param functions)

View File

@ -12,24 +12,24 @@ import (
// If any of the following fields are changed then the // If any of the following fields are changed then the
// caller should Refresh the router. // caller should Refresh the router.
type Route struct { type Route struct {
Name string // "userRoute" Name string `json:"name"` // "userRoute"
Method string // "GET" Method string `json:"method"` // "GET"
Subdomain string // "admin." Subdomain string `json:"subdomain"` // "admin."
tmpl *macro.Template // Tmpl().Src: "/api/user/{id:int}" tmpl *macro.Template // Tmpl().Src: "/api/user/{id:int}"
Path string // "/api/user/:id"
// temp storage, they're appended to the Handlers on build. // temp storage, they're appended to the Handlers on build.
// Execution happens before Handlers, can be empty. // Execution happens before Handlers, can be empty.
beginHandlers context.Handlers beginHandlers context.Handlers
// Handlers are the main route's handlers, executed by order. // Handlers are the main route's handlers, executed by order.
// Cannot be empty. // Cannot be empty.
Handlers context.Handlers Handlers context.Handlers `json:"-"`
MainHandlerName string MainHandlerName string `json:"mainHandlerName"`
// temp storage, they're appended to the Handlers on build. // temp storage, they're appended to the Handlers on build.
// Execution happens after Begin and main Handler(s), can be empty. // Execution happens after Begin and main Handler(s), can be empty.
doneHandlers context.Handlers doneHandlers context.Handlers
Path string `json:"path"` // "/api/user/:id"
// FormattedPath all dynamic named parameters (if any) replaced with %v, // FormattedPath all dynamic named parameters (if any) replaced with %v,
// used by Application to validate param values of a Route based on its name. // used by Application to validate param values of a Route based on its name.
FormattedPath string FormattedPath string `json:"formattedPath"`
} }
// NewRoute returns a new route based on its method, // NewRoute returns a new route based on its method,

View File

@ -26,7 +26,11 @@ type (
// these are filled from the config.Users map at the startup // these are filled from the config.Users map at the startup
auth encodedUsers auth encodedUsers
realmHeaderValue string realmHeaderValue string
expireEnabled bool // if the config.Expires is a valid date, default disabled
// The below can be removed but they are here because on the future we may add dynamic options for those two fields,
// it is a bit faster to check the b.$bool as well.
expireEnabled bool // if the config.Expires is a valid date, default is disabled.
askHandlerEnabled bool // if the config.OnAsk is not nil, defaults to false.
} }
) )
@ -43,6 +47,7 @@ func New(c Config) context.Handler {
} }
config.Users = c.Users config.Users = c.Users
config.Expires = c.Expires config.Expires = c.Expires
config.OnAsk = c.OnAsk
b := &basicAuthMiddleware{config: config} b := &basicAuthMiddleware{config: config}
b.init() b.init()
@ -72,9 +77,8 @@ func (b *basicAuthMiddleware) init() {
// set the auth realm header's value // set the auth realm header's value
b.realmHeaderValue = "Basic realm=" + strconv.Quote(b.config.Realm) b.realmHeaderValue = "Basic realm=" + strconv.Quote(b.config.Realm)
if b.config.Expires > 0 { b.expireEnabled = b.config.Expires > 0
b.expireEnabled = true b.askHandlerEnabled = b.config.OnAsk != nil
}
} }
func (b *basicAuthMiddleware) findAuth(headerValue string) (auth *encodedUser, found bool) { func (b *basicAuthMiddleware) findAuth(headerValue string) (auth *encodedUser, found bool) {
@ -96,6 +100,9 @@ func (b *basicAuthMiddleware) findAuth(headerValue string) (auth *encodedUser, f
func (b *basicAuthMiddleware) askForCredentials(ctx context.Context) { func (b *basicAuthMiddleware) askForCredentials(ctx context.Context) {
ctx.Header("WWW-Authenticate", b.realmHeaderValue) ctx.Header("WWW-Authenticate", b.realmHeaderValue)
ctx.StatusCode(iris.StatusUnauthorized) ctx.StatusCode(iris.StatusUnauthorized)
if b.askHandlerEnabled {
b.config.OnAsk(ctx)
}
} }
// Serve the actual middleware // Serve the actual middleware

View File

@ -22,11 +22,31 @@ type Config struct {
Realm string Realm string
// Expires expiration duration, default is 0 never expires // Expires expiration duration, default is 0 never expires
Expires time.Duration Expires time.Duration
// OnAsk fires each time the server asks to the client for credentials in order to gain access and continue to the next handler.
//
// You could also ignore this option and
// - just add a listener for unauthorized status codes with:
// `app.OnErrorCode(iris.StatusUnauthorized, unauthorizedWantsAccessHandler)`
// - or register a middleware which will force `ctx.Next/or direct call`
// the basicauth middleware and check its `ctx.GetStatusCode()`.
//
// However, this option is very useful when you want the framework to fire a handler
// ONLY when the Basic Authentication sends an `iris.StatusUnauthorized`,
// and free the error code listener to catch other types of unauthorized access, i.e Kerberos.
// Also with this one, not recommended at all but, you are able to "force-allow" other users by calling the `ctx.StatusCode` inside this handler;
// i.e when it is possible to create authorized users dynamically but
// if that is the case then you should go with something like sessions instead of basic authentication.
//
// Usage: basicauth.New(basicauth.Config{..., OnAsk: unauthorizedWantsAccessViaBasicAuthHandler})
//
// Defaults to nil.
OnAsk context.Handler
} }
// DefaultConfig returns the default configs for the BasicAuth middleware // DefaultConfig returns the default configs for the BasicAuth middleware
func DefaultConfig() Config { func DefaultConfig() Config {
return Config{make(map[string]string), DefaultBasicAuthRealm, 0} return Config{make(map[string]string), DefaultBasicAuthRealm, 0, nil}
} }
// User returns the user from context key same as ctx.Request().BasicAuth(). // User returns the user from context key same as ctx.Request().BasicAuth().