zhangzengfei
2024-10-22 a254bc563003a9e7b3a8f1307df38b8ae4274a4f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// Package auth is an implementation of HTTP Basic and HTTP Digest authentication.
package auth
 
import (
    "context"
    "net/http"
)
 
// AuthenticatedRequest is passed to AuthenticatedHandlerFunc instead
// of *http.Request.
type AuthenticatedRequest struct {
    http.Request
    // Username is the authenticated user name. Current API implies that
    // Username is never empty, which means that authentication is
    // always done before calling the request handler.
    Username string
}
 
// AuthenticatedHandlerFunc is like http.HandlerFunc, but takes
// AuthenticatedRequest instead of http.Request
type AuthenticatedHandlerFunc func(http.ResponseWriter, *AuthenticatedRequest)
 
// Authenticator wraps an AuthenticatedHandlerFunc with
// authentication-checking code.
//
// Typical Authenticator usage is something like:
//
//   authenticator := SomeAuthenticator(...)
//   http.HandleFunc("/", authenticator(my_handler))
//
// Authenticator wrapper checks the user authentication and calls the
// wrapped function only after authentication has succeeded. Otherwise,
// it returns a handler which initiates the authentication procedure.
type Authenticator func(AuthenticatedHandlerFunc) http.HandlerFunc
 
// Info contains authentication information for the request.
type Info struct {
    // Authenticated is set to true when request was authenticated
    // successfully, i.e. username and password passed in request did
    // pass the check.
    Authenticated bool
 
    // Username contains a user name passed in the request when
    // Authenticated is true. It's value is undefined if Authenticated
    // is false.
    Username string
 
    // ResponseHeaders contains extra headers that must be set by server
    // when sending back HTTP response.
    ResponseHeaders http.Header
}
 
// UpdateHeaders updates headers with this Info's ResponseHeaders. It is
// safe to call this function on nil Info.
func (i *Info) UpdateHeaders(headers http.Header) {
    if i == nil {
        return
    }
    for k, values := range i.ResponseHeaders {
        for _, v := range values {
            headers.Add(k, v)
        }
    }
}
 
type key int // used for context keys
 
var infoKey key
 
// AuthenticatorInterface is the interface implemented by BasicAuth
// and DigestAuth authenticators.
//
// Deprecated: this interface is not coherent. New code should define
// and use your own interfaces with a required subset of authenticator
// methods.
type AuthenticatorInterface interface {
    // NewContext returns a new context carrying authentication
    // information extracted from the request.
    NewContext(ctx context.Context, r *http.Request) context.Context
 
    // Wrap returns an http.HandlerFunc which wraps
    // AuthenticatedHandlerFunc with this authenticator's
    // authentication checks.
    Wrap(AuthenticatedHandlerFunc) http.HandlerFunc
}
 
// FromContext returns authentication information from the context or
// nil if no such information present.
func FromContext(ctx context.Context) *Info {
    info, ok := ctx.Value(infoKey).(*Info)
    if !ok {
        return nil
    }
    return info
}
 
// AuthUsernameHeader is the header set by JustCheck functions. It
// contains an authenticated username (if authentication was
// successful).
const AuthUsernameHeader = "X-Authenticated-Username"
 
// JustCheck returns a new http.HandlerFunc, which requires
// authenticator to successfully authenticate a user before calling
// wrapped http.HandlerFunc.
func JustCheck(auth AuthenticatorInterface, wrapped http.HandlerFunc) http.HandlerFunc {
    return auth.Wrap(func(w http.ResponseWriter, ar *AuthenticatedRequest) {
        ar.Header.Set(AuthUsernameHeader, ar.Username)
        wrapped(w, &ar.Request)
    })
}