mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 02:31:04 +01:00
Simplify the basicauth middleware
Former-commit-id: 8d184a434c992a884c5565bc22767ef295a1575a
This commit is contained in:
parent
6ab00aa02f
commit
5fa9789c35
|
@ -29,6 +29,11 @@ Thanks to [Santosh Anand](https://github.com/santoshanand) the http://iris-go.co
|
|||
|
||||
The amount of the next two or three donations you'll send they will be immediately transferred to his own account balance, so be generous please!
|
||||
|
||||
# Sa, 10 June 2017 | v7.0.4
|
||||
|
||||
- Simplify and add a test for the [basicauth middleware](https://github.com/kataras/iris/tree/master/middleware/basicauth), no need to be
|
||||
stored inside the Context anymore, developers can get the validated user(username and password) via `context.Request().BasicAuth()`. `basicauth.Config.ContextKey` was removed, just remove that field from your configuration, it's useless now.
|
||||
|
||||
# Sa, 10 June 2017 | v7.0.3
|
||||
|
||||
- New `context.Session().PeekFlash("key")` added, unlike `GetFlash` this will return the flash value but keep the message valid for the next requests too.
|
||||
|
|
|
@ -6,7 +6,7 @@ A fast, cross-platform and efficient web framework with robust set of well-desig
|
|||
[![Report card](https://img.shields.io/badge/report%20card%20-a%2B-F44336.svg?style=flat-square)](http://goreportcard.com/report/kataras/iris)
|
||||
[![Support forum](https://img.shields.io/badge/support-page-ec2eb4.svg?style=flat-square)](http://support.iris-go.com)
|
||||
[![Examples](https://img.shields.io/badge/howto-examples-3362c2.svg?style=flat-square)](https://github.com/kataras/iris/tree/master/_examples#table-of-contents)
|
||||
[![Godocs](https://img.shields.io/badge/7.0.3-%20documentation-5272B4.svg?style=flat-square)](https://godoc.org/github.com/kataras/iris)
|
||||
[![Godocs](https://img.shields.io/badge/7.0.4-%20documentation-5272B4.svg?style=flat-square)](https://godoc.org/github.com/kataras/iris)
|
||||
[![Chat](https://img.shields.io/badge/community-%20chat-00BCD4.svg?style=flat-square)](https://kataras.rocket.chat/channel/iris)
|
||||
[![Buy me a cup of coffee](https://img.shields.io/badge/support-%20open--source-F4A460.svg?logo=data:image%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxwYXRoIGZpbGw9InJnYigyMjAsMjIwLDIyMCkiIGQ9Ik04ODYuNiwzMDUuM2MtNDUuNywyMDMuMS0xODcsMzEwLjMtNDA5LjYsMzEwLjNoLTc0LjFsLTUxLjUsMzI2LjloLTYybC0zLjIsMjEuMWMtMi4xLDE0LDguNiwyNi40LDIyLjYsMjYuNGgxNTguNWMxOC44LDAsMzQuNy0xMy42LDM3LjctMzIuMmwxLjUtOGwyOS45LTE4OS4zbDEuOS0xMC4zYzIuOS0xOC42LDE4LjktMzIuMiwzNy43LTMyLjJoMjMuNWMxNTMuNSwwLDI3My43LTYyLjQsMzA4LjktMjQyLjdDOTIxLjYsNDA2LjgsOTE2LjcsMzQ4LjYsODg2LjYsMzA1LjN6Ii8%2BPHBhdGggZmlsbD0icmdiKDIyMCwyMjAsMjIwKSIgZD0iTTc5MS45LDgzLjlDNzQ2LjUsMzIuMiw2NjQuNCwxMCw1NTkuNSwxMEgyNTVjLTIxLjQsMC0zOS44LDE1LjUtNDMuMSwzNi44TDg1LDg1MWMtMi41LDE1LjksOS44LDMwLjIsMjUuOCwzMC4ySDI5OWw0Ny4zLTI5OS42bC0xLjUsOS40YzMuMi0yMS4zLDIxLjQtMzYuOCw0Mi45LTM2LjhINDc3YzE3NS41LDAsMzEzLTcxLjIsMzUzLjItMjc3LjVjMS4yLTYuMSwyLjMtMTIuMSwzLjEtMTcuOEM4NDUuMSwxODIuOCw4MzMuMiwxMzAuOCw3OTEuOSw4My45TDc5MS45LDgzLjl6Ii8%2BPC9zdmc%2B)](https://github.com/kataras/iris#buy-me-a-cup-of-coffee)
|
||||
|
||||
|
@ -394,7 +394,7 @@ Besides the fact that we have a [community chat][Chat] for questions or reports
|
|||
Version
|
||||
------------
|
||||
|
||||
Current: **7.0.3**
|
||||
Current: **7.0.4**
|
||||
|
||||
Each new release is pushed to the master. It stays there until the next version. When a next version is released then the previous version goes to its own branch with `gopkg.in` as its import path (and its own vendor folder), in order to keep it working "for-ever".
|
||||
|
||||
|
|
|
@ -12,10 +12,9 @@ func main() {
|
|||
app := iris.New()
|
||||
|
||||
authConfig := basicauth.Config{
|
||||
Users: map[string]string{"myusername": "mypassword", "mySecondusername": "mySecondpassword"},
|
||||
Realm: "Authorization Required", // defaults to "Authorization Required"
|
||||
ContextKey: "user", // defaults to "user"
|
||||
Expires: time.Duration(30) * time.Minute,
|
||||
Users: map[string]string{"myusername": "mypassword", "mySecondusername": "mySecondpassword"},
|
||||
Realm: "Authorization Required", // defaults to "Authorization Required"
|
||||
Expires: time.Duration(30) * time.Minute,
|
||||
}
|
||||
|
||||
authentication := basicauth.New(authConfig)
|
||||
|
@ -23,10 +22,7 @@ func main() {
|
|||
// to global app.Use(authentication) (or app.UseGlobal before the .Run)
|
||||
// to routes
|
||||
/*
|
||||
app.Get("/mysecret", authentication, func(ctx context.Context) {
|
||||
username := ctx.Values().GetString("user") // the Contextkey from the authConfig
|
||||
ctx.Writef("Hello authenticated user: %s ", username)
|
||||
})
|
||||
app.Get("/mysecret", authentication, h)
|
||||
*/
|
||||
|
||||
app.Get("/", func(ctx context.Context) { ctx.Redirect("/admin") })
|
||||
|
@ -36,23 +32,22 @@ func main() {
|
|||
needAuth := app.Party("/admin", authentication)
|
||||
{
|
||||
//http://localhost:8080/admin
|
||||
needAuth.Get("/", func(ctx context.Context) {
|
||||
username := ctx.Values().GetString("user") // the Contextkey from the authConfig
|
||||
ctx.Writef("Hello authenticated user: %s from: %s", username, ctx.Path())
|
||||
})
|
||||
needAuth.Get("/", h)
|
||||
// http://localhost:8080/admin/profile
|
||||
needAuth.Get("/profile", func(ctx context.Context) {
|
||||
username := ctx.Values().GetString("user") // the Contextkey from the authConfig
|
||||
ctx.Writef("Hello authenticated user: %s from: % ", username, ctx.Path())
|
||||
})
|
||||
needAuth.Get("/profile", h)
|
||||
|
||||
// http://localhost:8080/admin/settings
|
||||
needAuth.Get("/settings", func(ctx context.Context) {
|
||||
username := authConfig.User(ctx) // shortcut for ctx.Values().GetString("user")
|
||||
ctx.Writef("Hello authenticated user: %s from: %s", username, ctx.Path())
|
||||
})
|
||||
needAuth.Get("/settings", h)
|
||||
}
|
||||
|
||||
// open http://localhost:8080/admin
|
||||
app.Run(iris.Addr(":8080"))
|
||||
}
|
||||
|
||||
func h(ctx context.Context) {
|
||||
username, password, _ := ctx.Request().BasicAuth()
|
||||
// third parameter it will be always true because the middleware
|
||||
// makes sure for that, otherwise this handler will not be executed.
|
||||
|
||||
ctx.Writef("%s %s:%s", ctx.Path(), username, password)
|
||||
}
|
||||
|
|
|
@ -6,26 +6,15 @@ import (
|
|||
"github.com/kataras/iris/middleware/basicauth"
|
||||
)
|
||||
|
||||
func buildApp() *iris.Application {
|
||||
func newApp() *iris.Application {
|
||||
app := iris.New()
|
||||
|
||||
authConfig := basicauth.Config{
|
||||
Users: map[string]string{"myusername": "mypassword", "mySecondusername": "mySecondpassword"},
|
||||
Realm: "Authorization Required", // defaults to "Authorization Required"
|
||||
ContextKey: "user", // defaults to "user"
|
||||
Users: map[string]string{"myusername": "mypassword"},
|
||||
}
|
||||
|
||||
authentication := basicauth.New(authConfig)
|
||||
|
||||
// to global app.Use(authentication) (or app.UseGlobal before the .Run)
|
||||
// to routes
|
||||
/*
|
||||
app.Get("/mysecret", authentication, func(ctx context.Context) {
|
||||
username := ctx.Values().GetString("user") // the Contextkey from the authConfig
|
||||
ctx.Writef("Hello authenticated user: %s ", username)
|
||||
})
|
||||
*/
|
||||
|
||||
app.Get("/", func(ctx context.Context) { ctx.Redirect("/admin") })
|
||||
|
||||
// to party
|
||||
|
@ -33,27 +22,26 @@ func buildApp() *iris.Application {
|
|||
needAuth := app.Party("/admin", authentication)
|
||||
{
|
||||
//http://localhost:8080/admin
|
||||
needAuth.Get("/", func(ctx context.Context) {
|
||||
username := ctx.Values().GetString("user") // the Contextkey from the authConfig
|
||||
ctx.Writef("Hello authenticated user: %s from: %s", username, ctx.Path())
|
||||
})
|
||||
needAuth.Get("/", h)
|
||||
// http://localhost:8080/admin/profile
|
||||
needAuth.Get("/profile", func(ctx context.Context) {
|
||||
username := ctx.Values().GetString("user") // the Contextkey from the authConfig
|
||||
ctx.Writef("Hello authenticated user: %s from: %s", username, ctx.Path())
|
||||
})
|
||||
needAuth.Get("/profile", h)
|
||||
|
||||
// http://localhost:8080/admin/settings
|
||||
needAuth.Get("/settings", func(ctx context.Context) {
|
||||
username := authConfig.User(ctx) // shortcut for ctx.Values().GetString("user")
|
||||
ctx.Writef("Hello authenticated user: %s from: %s", username, ctx.Path())
|
||||
})
|
||||
needAuth.Get("/settings", h)
|
||||
}
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
func h(ctx context.Context) {
|
||||
username, password, _ := ctx.Request().BasicAuth()
|
||||
// third parameter it will be always true because the middleware
|
||||
// makes sure for that, otherwise this handler will not be executed.
|
||||
|
||||
ctx.Writef("%s %s:%s", ctx.Path(), username, password)
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := buildApp()
|
||||
app := newApp()
|
||||
app.Run(iris.Addr(":8080"))
|
||||
}
|
||||
|
|
|
@ -7,10 +7,10 @@ import (
|
|||
"github.com/kataras/iris/httptest"
|
||||
)
|
||||
|
||||
// $ cd _example
|
||||
// $ cd $GOPATH/src/github.com/kataras/iris/_examples/intermediate/httptest
|
||||
// $ go test -v
|
||||
func TestNewApp(t *testing.T) {
|
||||
app := buildApp()
|
||||
app := newApp()
|
||||
e := httptest.New(app, t)
|
||||
|
||||
// redirects to /admin without basic auth
|
||||
|
@ -20,11 +20,11 @@ func TestNewApp(t *testing.T) {
|
|||
|
||||
// with valid basic auth
|
||||
e.GET("/admin").WithBasicAuth("myusername", "mypassword").Expect().
|
||||
Status(iris.StatusOK).Body().Equal("Hello authenticated user: myusername from: /admin")
|
||||
Status(iris.StatusOK).Body().Equal("/admin myusername:mypassword")
|
||||
e.GET("/admin/profile").WithBasicAuth("myusername", "mypassword").Expect().
|
||||
Status(iris.StatusOK).Body().Equal("Hello authenticated user: myusername from: /admin/profile")
|
||||
Status(iris.StatusOK).Body().Equal("/admin/profile myusername:mypassword")
|
||||
e.GET("/admin/settings").WithBasicAuth("myusername", "mypassword").Expect().
|
||||
Status(iris.StatusOK).Body().Equal("Hello authenticated user: myusername from: /admin/settings")
|
||||
Status(iris.StatusOK).Body().Equal("/admin/settings myusername:mypassword")
|
||||
|
||||
// with invalid basic auth
|
||||
e.GET("/admin/settings").WithBasicAuth("invalidusername", "invalidpassword").
|
||||
|
|
2
iris.go
2
iris.go
|
@ -41,7 +41,7 @@ const (
|
|||
// Version is the current version number of the Iris Web framework.
|
||||
//
|
||||
// Look https://github.com/kataras/iris#where-can-i-find-older-versions for older versions.
|
||||
Version = "7.0.3"
|
||||
Version = "7.0.4"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -34,13 +34,12 @@ type (
|
|||
|
||||
//
|
||||
|
||||
// New takes one parameter, the Config returns a Handler
|
||||
// use: iris.Use(New(...)), iris.Get(...,New(...),...)
|
||||
// New accepts basicauth.Config and returns a new Handler
|
||||
// which will ask the client for basic auth (username, password),
|
||||
// validate that and if valid continues to the next handler, otherwise
|
||||
// throws a StatusUnauthorized http error code.
|
||||
func New(c Config) context.Handler {
|
||||
config := DefaultConfig()
|
||||
if c.ContextKey != "" {
|
||||
config.ContextKey = c.ContextKey
|
||||
}
|
||||
if c.Realm != "" {
|
||||
config.Realm = c.Realm
|
||||
}
|
||||
|
@ -51,8 +50,10 @@ func New(c Config) context.Handler {
|
|||
return b.Serve
|
||||
}
|
||||
|
||||
// Default takes one parameter, the users returns a Handler
|
||||
// use: iris.Use(Default(...)), iris.Get(...,Default(...),...)
|
||||
// Default accepts only the users and returns a new Handler
|
||||
// which will ask the client for basic auth (username, password),
|
||||
// validate that and if valid continues to the next handler, otherwise
|
||||
// throws a StatusUnauthorized http error code.
|
||||
func Default(users map[string]string) context.Handler {
|
||||
c := DefaultConfig()
|
||||
c.Users = users
|
||||
|
@ -101,26 +102,23 @@ func (b *basicAuthMiddleware) askForCredentials(ctx context.Context) {
|
|||
// Serve the actual middleware
|
||||
func (b *basicAuthMiddleware) Serve(ctx context.Context) {
|
||||
|
||||
if auth, found := b.findAuth(ctx.GetHeader("Authorization")); !found {
|
||||
auth, found := b.findAuth(ctx.GetHeader("Authorization"))
|
||||
if !found {
|
||||
b.askForCredentials(ctx)
|
||||
return
|
||||
// don't continue to the next handler
|
||||
} else {
|
||||
// all ok set the context's value in order to be getable from the next handler
|
||||
ctx.Values().Set(b.config.ContextKey, auth.Username)
|
||||
if b.expireEnabled {
|
||||
|
||||
if auth.logged == false {
|
||||
auth.expires = time.Now().Add(b.config.Expires)
|
||||
auth.logged = true
|
||||
}
|
||||
|
||||
if time.Now().After(auth.expires) {
|
||||
b.askForCredentials(ctx) // ask for authentication again
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
ctx.Next() // continue
|
||||
}
|
||||
// all ok
|
||||
if b.expireEnabled {
|
||||
if auth.logged == false {
|
||||
auth.expires = time.Now().Add(b.config.Expires)
|
||||
auth.logged = true
|
||||
}
|
||||
|
||||
if time.Now().After(auth.expires) {
|
||||
b.askForCredentials(ctx) // ask for authentication again
|
||||
return
|
||||
}
|
||||
}
|
||||
ctx.Next() // continue
|
||||
}
|
||||
|
|
67
middleware/basicauth/basicauth_test.go
Normal file
67
middleware/basicauth/basicauth_test.go
Normal file
|
@ -0,0 +1,67 @@
|
|||
// black-box testing
|
||||
package basicauth_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris"
|
||||
"github.com/kataras/iris/context"
|
||||
"github.com/kataras/iris/httptest"
|
||||
"github.com/kataras/iris/middleware/basicauth"
|
||||
)
|
||||
|
||||
func buildApp() *iris.Application {
|
||||
app := iris.New()
|
||||
|
||||
authConfig := basicauth.Config{
|
||||
Users: map[string]string{"myusername": "mypassword"},
|
||||
}
|
||||
|
||||
authentication := basicauth.New(authConfig)
|
||||
|
||||
app.Get("/", func(ctx context.Context) { ctx.Redirect("/admin") })
|
||||
|
||||
// to party
|
||||
|
||||
needAuth := app.Party("/admin", authentication)
|
||||
{
|
||||
//http://localhost:8080/admin
|
||||
needAuth.Get("/", h)
|
||||
// http://localhost:8080/admin/profile
|
||||
needAuth.Get("/profile", h)
|
||||
|
||||
// http://localhost:8080/admin/settings
|
||||
needAuth.Get("/settings", h)
|
||||
}
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
func h(ctx context.Context) {
|
||||
username, password, _ := ctx.Request().BasicAuth()
|
||||
// third parameter it will be always true because the middleware
|
||||
// makes sure for that, otherwise this handler will not be executed.
|
||||
|
||||
ctx.Writef("%s %s:%s", ctx.Path(), username, password)
|
||||
}
|
||||
func TestBasicAuth(t *testing.T) {
|
||||
app := buildApp()
|
||||
e := httptest.New(app, t)
|
||||
|
||||
// redirects to /admin without basic auth
|
||||
e.GET("/").Expect().Status(iris.StatusUnauthorized)
|
||||
// without basic auth
|
||||
e.GET("/admin").Expect().Status(iris.StatusUnauthorized)
|
||||
|
||||
// with valid basic auth
|
||||
e.GET("/admin").WithBasicAuth("myusername", "mypassword").Expect().
|
||||
Status(iris.StatusOK).Body().Equal("/admin myusername:mypassword")
|
||||
e.GET("/admin/profile").WithBasicAuth("myusername", "mypassword").Expect().
|
||||
Status(iris.StatusOK).Body().Equal("/admin/profile myusername:mypassword")
|
||||
e.GET("/admin/settings").WithBasicAuth("myusername", "mypassword").Expect().
|
||||
Status(iris.StatusOK).Body().Equal("/admin/settings myusername:mypassword")
|
||||
|
||||
// with invalid basic auth
|
||||
e.GET("/admin/settings").WithBasicAuth("invalidusername", "invalidpassword").
|
||||
Expect().Status(iris.StatusUnauthorized)
|
||||
}
|
|
@ -13,9 +13,6 @@ import (
|
|||
const (
|
||||
// DefaultBasicAuthRealm is "Authorization Required"
|
||||
DefaultBasicAuthRealm = "Authorization Required"
|
||||
// DefaultBasicAuthContextKey is the "auth"
|
||||
// this key is used to do context.Set("user", theUsernameFromBasicAuth)
|
||||
DefaultBasicAuthContextKey = "user"
|
||||
)
|
||||
|
||||
// DefaultExpireTime zero time
|
||||
|
@ -27,18 +24,16 @@ type Config struct {
|
|||
Users map[string]string
|
||||
// Realm http://tools.ietf.org/html/rfc2617#section-1.2. Default is "Authorization Required"
|
||||
Realm string
|
||||
// ContextKey the key for ctx.GetString(...). Default is 'user'
|
||||
ContextKey string
|
||||
// Expires expiration duration, default is 0 never expires
|
||||
Expires time.Duration
|
||||
}
|
||||
|
||||
// DefaultConfig returns the default configs for the BasicAuth middleware
|
||||
func DefaultConfig() Config {
|
||||
return Config{make(map[string]string), DefaultBasicAuthRealm, DefaultBasicAuthContextKey, 0}
|
||||
return Config{make(map[string]string), DefaultBasicAuthRealm, 0}
|
||||
}
|
||||
|
||||
// User returns the user from context key same as 'ctx.GetString("user")' but cannot be used by the developer, this is only here in order to understand how you can get the authenticated username
|
||||
func (c Config) User(ctx context.Context) string {
|
||||
return ctx.Values().GetString(c.ContextKey)
|
||||
// User returns the user from context key same as ctx.Request().BasicAuth().
|
||||
func (c Config) User(ctx context.Context) (string, string, bool) {
|
||||
return ctx.Request().BasicAuth()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user