1
0
mirror of https://github.com/kataras/iris.git synced 2026-01-03 02:07:06 +00:00

Add Context.SetUser and Context.User methods

relative to: https://github.com/iris-contrib/middleware/issues/63
This commit is contained in:
Gerasimos (Makis) Maropoulos
2020-10-12 15:52:53 +03:00
parent dfe27567ae
commit 8e51a296b9
7 changed files with 242 additions and 19 deletions

View File

@@ -1,7 +1,11 @@
// Package basicauth provides http basic authentication via middleware. See _examples/auth/basicauth
package basicauth
// test file: ../../_examples/auth/basicauth/main_test.go
/*
Test files:
- ../../_examples/auth/basicauth/main_test.go
- ./basicauth_test.go
*/
import (
"encoding/base64"
@@ -16,14 +20,18 @@ func init() {
context.SetHandlerName("iris/middleware/basicauth.*", "iris.basicauth")
}
const authorizationType = "Basic Authentication"
type (
encodedUser struct {
HeaderValue string
Username string
logged bool
forceLogout bool // in order to be able to invalidate and use a redirect response.
expires time.Time
mu sync.RWMutex
HeaderValue string
Username string
Password string
logged bool
forceLogout bool // in order to be able to invalidate and use a redirect response.
authorizedAt time.Time // when from !logged to logged.
expires time.Time
mu sync.RWMutex
}
basicAuthMiddleware struct {
@@ -45,6 +53,8 @@ type (
// 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.
//
// Use the `Context.User` method to retrieve the stored user.
func New(c Config) context.Handler {
config := DefaultConfig()
if c.Realm != "" {
@@ -76,7 +86,13 @@ func (b *basicAuthMiddleware) init() {
for k, v := range b.config.Users {
fullUser := k + ":" + v
header := "Basic " + base64.StdEncoding.EncodeToString([]byte(fullUser))
b.auth = append(b.auth, &encodedUser{HeaderValue: header, Username: k, logged: false, expires: DefaultExpireTime})
b.auth = append(b.auth, &encodedUser{
HeaderValue: header,
Username: k,
Password: v,
logged: false,
expires: DefaultExpireTime,
})
}
// set the auth realm header's value
@@ -106,7 +122,8 @@ func (b *basicAuthMiddleware) askForCredentials(ctx *context.Context) {
}
}
// Serve the actual middleware
// Serve the actual basic authentication middleware.
// Use the Context.User method to retrieve the stored user.
func (b *basicAuthMiddleware) Serve(ctx *context.Context) {
auth, found := b.findAuth(ctx.GetHeader("Authorization"))
if !found || auth.forceLogout {
@@ -122,11 +139,20 @@ func (b *basicAuthMiddleware) Serve(ctx *context.Context) {
// don't continue to the next handler
}
auth.mu.RLock()
logged := auth.logged
auth.mu.RUnlock()
if !logged {
auth.mu.Lock()
auth.authorizedAt = time.Now()
auth.mu.Unlock()
}
// all ok
if b.expireEnabled {
if !auth.logged {
if !logged {
auth.mu.Lock()
auth.expires = time.Now().Add(b.config.Expires)
auth.expires = auth.authorizedAt.Add(b.config.Expires)
auth.logged = true
auth.mu.Unlock()
}
@@ -137,6 +163,7 @@ func (b *basicAuthMiddleware) Serve(ctx *context.Context) {
if expired {
auth.mu.Lock()
auth.logged = false
auth.forceLogout = false
auth.mu.Unlock()
b.askForCredentials(ctx) // ask for authentication again
ctx.StopExecution()
@@ -144,8 +171,18 @@ func (b *basicAuthMiddleware) Serve(ctx *context.Context) {
}
}
if !b.config.DisableLogoutFunc {
if !b.config.DisableContextUser {
ctx.SetLogoutFunc(b.Logout)
auth.mu.RLock()
user := &context.SimpleUser{
Authorization: authorizationType,
AuthorizedAt: auth.authorizedAt,
Username: auth.Username,
Password: auth.Password,
}
auth.mu.RUnlock()
ctx.SetUser(user)
}
ctx.Next() // continue

View File

@@ -20,6 +20,15 @@ func TestBasicAuthUseRouter(t *testing.T) {
app.UseRouter(basicauth.Default(users))
app.Get("/user_json", func(ctx iris.Context) {
ctx.JSON(ctx.User())
})
app.Get("/user_string", func(ctx iris.Context) {
user := ctx.User()
ctx.Writef("%s\n%s\n%s", user.GetAuthorization(), user.GetUsername(), user.GetPassword())
})
app.Get("/", func(ctx iris.Context) {
username, _, _ := ctx.Request().BasicAuth()
ctx.Writef("Hello, %s!", username)
@@ -55,6 +64,13 @@ func TestBasicAuthUseRouter(t *testing.T) {
// Test pass authentication and route found.
e.GET("/").WithBasicAuth(username, password).Expect().
Status(httptest.StatusOK).Body().Equal(fmt.Sprintf("Hello, %s!", username))
e.GET("/user_json").WithBasicAuth(username, password).Expect().
Status(httptest.StatusOK).JSON().Object().ContainsMap(iris.Map{
"username": username,
})
e.GET("/user_string").WithBasicAuth(username, password).Expect().
Status(httptest.StatusOK).Body().
Equal(fmt.Sprintf("%s\n%s\n%s", "Basic Authentication", username, password))
// Test empty auth.
e.GET("/").Expect().Status(httptest.StatusUnauthorized).Body().Equal("Unauthorized")

View File

@@ -43,8 +43,9 @@ type Config struct {
// Defaults to nil.
OnAsk context.Handler
// DisableLogoutFunc disables the registration of the custom basicauth Context.Logout.
DisableLogoutFunc bool
// DisableContextUser disables the registration of the custom basicauth Context.Logout
// and the User.
DisableContextUser bool
}
// DefaultConfig returns the default configs for the BasicAuth middleware