* Updated auth interface * Add Rule * Remove Rule * Return token from Renew * Renew => Refresh * Implement Tokens & Default Auth Implementation * Change default auth to noop * Change default auth to noop * Move token.Token to auth.Token * Remove Token from Account * Auth service implementation * Decode JWT locally * Cookie for secret * Move string to bottom of interface definition * Depricate auth_exclude * Update auth wrappers * Update go.sum Co-authored-by: Ben Toogood <ben@micro.mu>
		
			
				
	
	
		
			90 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			90 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package auth
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"net/http"
 | |
| 	"net/url"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/micro/go-micro/v2/auth"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	// DefaultExcludes is the paths which are allowed by default
 | |
| 	DefaultExcludes = []string{"/favicon.ico"}
 | |
| )
 | |
| 
 | |
| // CombinedAuthHandler wraps a server and authenticates requests
 | |
| func CombinedAuthHandler(h http.Handler) http.Handler {
 | |
| 	return authHandler{
 | |
| 		handler: h,
 | |
| 		auth:    auth.DefaultAuth,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| type authHandler struct {
 | |
| 	handler http.Handler
 | |
| 	auth    auth.Auth
 | |
| }
 | |
| 
 | |
| const (
 | |
| 	// BearerScheme is the prefix in the auth header
 | |
| 	BearerScheme = "Bearer "
 | |
| )
 | |
| 
 | |
| func (h authHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 | |
| 	// Extract the token from the request
 | |
| 	var token string
 | |
| 	if header := req.Header.Get("Authorization"); len(header) > 0 {
 | |
| 		// Extract the auth token from the request
 | |
| 		if strings.HasPrefix(header, BearerScheme) {
 | |
| 			token = header[len(BearerScheme):]
 | |
| 		}
 | |
| 	} else {
 | |
| 		// Get the token out the cookies if not provided in headers
 | |
| 		if c, err := req.Cookie("micro-token"); err == nil && c != nil {
 | |
| 			token = strings.TrimPrefix(c.Value, auth.TokenCookieName+"=")
 | |
| 			req.Header.Set("Authorization", BearerScheme+token)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Get the account using the token, fallback to a blank account
 | |
| 	// since some endpoints can be unauthenticated, so the lack of an
 | |
| 	// account doesn't necesserially mean a forbidden request
 | |
| 	acc, err := h.auth.Inspect(token)
 | |
| 	if err != nil {
 | |
| 		acc = &auth.Account{}
 | |
| 	}
 | |
| 	err = h.auth.Verify(acc, &auth.Resource{
 | |
| 		Type:     "service",
 | |
| 		Name:     "go.micro.web",
 | |
| 		Endpoint: req.URL.Path,
 | |
| 	})
 | |
| 
 | |
| 	// The account has the necessary permissions to access the
 | |
| 	// resource
 | |
| 	if err == nil {
 | |
| 		h.handler.ServeHTTP(w, req)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// The account is set, but they don't have enough permissions,
 | |
| 	// hence we 403.
 | |
| 	if len(acc.ID) > 0 {
 | |
| 		w.WriteHeader(http.StatusForbidden)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// If there is no auth login url set, 401
 | |
| 	loginURL := h.auth.Options().LoginURL
 | |
| 	if loginURL == "" {
 | |
| 		w.WriteHeader(http.StatusUnauthorized)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	// Redirect to the login path
 | |
| 	params := url.Values{"redirect_to": {req.URL.Path}}
 | |
| 	loginWithRedirect := fmt.Sprintf("%v?%v", loginURL, params.Encode())
 | |
| 	http.Redirect(w, req, loginWithRedirect, http.StatusTemporaryRedirect)
 | |
| }
 |