diff --git a/_examples/auth/basicauth/basic/main.go b/_examples/auth/basicauth/basic/main.go index 7c663cfd..06f3ce5d 100644 --- a/_examples/auth/basicauth/basic/main.go +++ b/_examples/auth/basicauth/basic/main.go @@ -2,6 +2,8 @@ package main import ( "github.com/kataras/iris/v12" + "github.com/kataras/iris/v12/x/errors" + "github.com/kataras/iris/v12/middleware/basicauth" ) @@ -31,8 +33,22 @@ func newApp() *iris.Application { "mySecondusername": "mySecondpassword", }) - // to global app.Use(auth) (or app.UseGlobal before the .Run) - // to routes + // To the next routes of a party (group of routes): + /* + app.Use(auth) + */ + + // For global effect, including not founds: + /* + app.UseRouter(auth) + */ + + // For global effect, excluding http errors such as not founds: + /* + app.UseGlobal(auth) or app.Use(auth) before any route registered. + */ + + // For single/per routes: /* app.Get("/mysecret", auth, h) */ @@ -73,9 +89,11 @@ func handler(ctx iris.Context) { } func logout(ctx iris.Context) { - err := ctx.Logout() // fires 401, invalidates the basic auth. + // fires 401, invalidates the basic auth, + // logout through javascript and ajax is a better solution though. + err := ctx.Logout() if err != nil { - ctx.Application().Logger().Errorf("Logout error: %v", err) + errors.Internal.Err(ctx, err) + return } - ctx.Redirect("/admin", iris.StatusTemporaryRedirect) } diff --git a/_examples/database/sqlx/main.go b/_examples/database/sqlx/main.go index 4ed847e1..c320970c 100644 --- a/_examples/database/sqlx/main.go +++ b/_examples/database/sqlx/main.go @@ -123,17 +123,22 @@ func listEvents(ctx context.Context, db *sql.DB) ([]Event, error) { return list, nil } -func getEvent(ctx context.Context, db *sql.DB, id string) (Event, error) { +func getEvent(ctx context.Context, db *sql.DB, id string) (evt Event, err error) { query := `SELECT * FROM events WHERE id = $1 LIMIT 1;` - rows, err := db.QueryContext(ctx, query, id) - if err != nil { - return Event{}, err - } - - var evt Event - err = sqlx.Bind(&evt, rows) - - return evt, err + err = sqlx.Query(ctx, db, &evt, query, id) + return + // + // Same as: + // + // rows, err := db.QueryContext(ctx, query, id) + // if err != nil { + // return Event{}, err + // } + // + // var evt Event + // err = sqlx.Bind(&evt, rows) + // + // return evt, err } func insert(db *sql.DB) iris.Handler { diff --git a/context/context.go b/context/context.go index 8de072cb..40072716 100644 --- a/context/context.go +++ b/context/context.go @@ -2160,6 +2160,15 @@ func (ctx *Context) AbsoluteURI(s string) string { return "" } + userInfo := "" + if s[0] == '@' { + endUserInfoIdx := strings.IndexByte(s, '/') + if endUserInfoIdx > 0 && len(s) > endUserInfoIdx { + userInfo = s[1:endUserInfoIdx] + "@" + s = s[endUserInfoIdx:] + } + } + if s[0] == '/' { scheme := ctx.request.URL.Scheme if scheme == "" { @@ -2172,7 +2181,7 @@ func (ctx *Context) AbsoluteURI(s string) string { host := ctx.Host() - return scheme + "//" + host + path.Clean(s) + return scheme + "//" + userInfo + host + path.Clean(s) } if u, err := url.Parse(s); err == nil { diff --git a/middleware/basicauth/basicauth.go b/middleware/basicauth/basicauth.go index a044c76a..97fbb85e 100644 --- a/middleware/basicauth/basicauth.go +++ b/middleware/basicauth/basicauth.go @@ -493,6 +493,12 @@ func (b *BasicAuth) logout(ctx *context.Context) { b.mu.Lock() delete(b.credentials, fullUser) b.mu.Unlock() + + if b.opts.MaxTries > 0 { + b.setCurrentTries(ctx, 0) + } + + ctx.StatusCode(http.StatusUnauthorized) } } diff --git a/x/sqlx/sqlx.go b/x/sqlx/sqlx.go index bf438381..a2af5e90 100644 --- a/x/sqlx/sqlx.go +++ b/x/sqlx/sqlx.go @@ -1,6 +1,7 @@ package sqlx import ( + "context" "database/sql" "fmt" "reflect" @@ -54,6 +55,11 @@ func Register(tableName string, value interface{}) *Schema { return DefaultSchema.Register(tableName, value) } +// Query is a shortcut of executing a query and bind the result to "dst". +func Query(ctx context.Context, db *sql.DB, dst interface{}, query string, args ...interface{}) error { + return DefaultSchema.Query(ctx, db, dst, query, args...) +} + // Bind sets "dst" to the result of "src" and reports any errors. func Bind(dst interface{}, src *sql.Rows) error { return DefaultSchema.Bind(dst, src) @@ -90,6 +96,21 @@ func (s *Schema) Register(tableName string, value interface{}) *Schema { return s } +// Query is a shortcut of executing a query and bind the result to "dst". +func (s *Schema) Query(ctx context.Context, db *sql.DB, dst interface{}, query string, args ...interface{}) error { + rows, err := db.QueryContext(ctx, query, args...) + if err != nil { + return err + } + + if !s.AutoCloseRows { // if not close on bind, we must close it here. + defer rows.Close() + } + + err = s.Bind(dst, rows) + return err +} + // Bind sets "dst" to the result of "src" and reports any errors. func (s *Schema) Bind(dst interface{}, src *sql.Rows) error { typ := reflect.TypeOf(dst)