github.com/angenalZZZ/gofunc@v0.0.0-20210507121333-48ff1be3917b/http/fast/middleware/basicauth/basicauth.go (about)

     1  package basicauth
     2  
     3  import (
     4  	"encoding/base64"
     5  	"github.com/angenalZZZ/gofunc/http/fast"
     6  	"strings"
     7  )
     8  
     9  // Config defines the config for BasicAuth middleware
    10  type Config struct {
    11  	// Filter defines a function to skip middleware.
    12  	// Optional. Default: nil
    13  	Filter func(*fast.Ctx) bool
    14  	// Users defines the allowed credentials
    15  	// Required. Default: map[string]string{}
    16  	Users map[string]string
    17  	// Realm is a string to define realm attribute of BasicAuth.
    18  	// the realm identifies the system to authenticate against
    19  	// and can be used by clients to save credentials
    20  	// Optional. Default: "Restricted".
    21  	Realm string
    22  	// Authorize defines a function you can pass
    23  	// to check the credentials however you want.
    24  	// It will be called with a username and password
    25  	// and is expected to return true or false to indicate
    26  	// that the credentials were approved or not.
    27  	// Optional. Default: nil.
    28  	Authorize func(string, string) bool
    29  	// Unauthorized defines the response body for unauthorized responses.
    30  	// Optional. Default: nil
    31  	Unauthorized func(*fast.Ctx)
    32  }
    33  
    34  // New middleware.
    35  //  cfg := basicauth.Config{
    36  //    Users: map[string]string{
    37  //      "admin":  "123456",
    38  //    },
    39  //  }
    40  //  app.Use(basicauth.New(cfg))
    41  func New(config ...Config) func(*fast.Ctx) {
    42  	// Init config
    43  	var cfg Config
    44  	if len(config) > 0 {
    45  		cfg = config[0]
    46  	}
    47  	if cfg.Users == nil {
    48  		cfg.Users = map[string]string{}
    49  	}
    50  	if cfg.Realm == "" {
    51  		cfg.Realm = "Restricted"
    52  	}
    53  	if cfg.Authorize == nil {
    54  		cfg.Authorize = func(user, pass string) bool {
    55  			if user == "" || pass == "" {
    56  				return false
    57  			}
    58  			if _pass, ok := cfg.Users[user]; ok {
    59  				return _pass == pass
    60  			}
    61  			return false
    62  		}
    63  	}
    64  	if cfg.Unauthorized == nil {
    65  		cfg.Unauthorized = func(c *fast.Ctx) {
    66  			c.SetHeader("WWW-Authenticate", "basic realm="+cfg.Realm)
    67  			c.SendStatus(401)
    68  		}
    69  	}
    70  	// Return middleware handler
    71  	return func(c *fast.Ctx) {
    72  		// Filter request to skip middleware
    73  		if cfg.Filter != nil && cfg.Filter(c) {
    74  			c.Next()
    75  			return
    76  		}
    77  		// GetHeader authorization header
    78  		auth := c.GetHeader("Authorization")
    79  		// Check if header is valid
    80  		if len(auth) > 6 && strings.ToLower(auth[:5]) == "basic" {
    81  			// Try to decode
    82  			if raw, err := base64.StdEncoding.DecodeString(auth[6:]); err == nil {
    83  				// Convert to string
    84  				cred := string(raw)
    85  				// Find semi column
    86  				for i := 0; i < len(cred); i++ {
    87  					if cred[i] == ':' {
    88  						// Split into user & pass
    89  						user := cred[:i]
    90  						pass := cred[i+1:]
    91  						// If exist & match in Users, we let him pass
    92  						if cfg.Authorize(user, pass) {
    93  							c.Next()
    94  							return
    95  						}
    96  					}
    97  				}
    98  			}
    99  		}
   100  		// Authentication failed
   101  		cfg.Unauthorized(c)
   102  	}
   103  }