-
Notifications
You must be signed in to change notification settings - Fork 0
/
session.go
101 lines (93 loc) · 3.31 KB
/
session.go
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
package sessions
import (
"errors"
"fmt"
"net/http"
"strings"
)
const headerAuthorization = "Authorization"
const schemeBearer = "Bearer "
//ErrNoSessionID is used when no session ID was found in the Authorization header
var ErrNoSessionID = errors.New("no session ID found in " + headerAuthorization + " header")
//ErrInvalidScheme is used when the authorization scheme is not supported
var ErrInvalidScheme = errors.New("scheme used in Authorization header is not supported")
//BeginSession creates a new session ID, saves the state to the store, adds a
//header to the response with the session ID, and returns the new session ID
func BeginSession(signingKey string, store Store, state interface{}, w http.ResponseWriter) (SessionID, error) {
//create a new SessionID
//if you get an error, return InvalidSessionID and the error
sid, err := NewSessionID(signingKey)
if err != nil {
return InvalidSessionID, err
}
//save the state to the store
//if you get an error, return InvalidSessionID and the error
err = store.Save(sid, state)
if err != nil {
return InvalidSessionID, err
}
//Add a response header like this:
// Authorization: Bearer <sid>
//where <sid> is the new SessionID
w.Header().Add(headerAuthorization, fmt.Sprintf("%s%s", schemeBearer, sid))
//return the new SessionID and nil
return sid, nil
}
//GetSessionID extracts and validates the SessionID from the request headers
func GetSessionID(r *http.Request, signingKey string) (SessionID, error) {
//get the value of the Authorization header
headAuth := r.Header.Get(headerAuthorization)
//if it's zero-length, return InvalidSessionID and ErrNoSessionID
if len(headAuth) == 0 {
return InvalidSessionID, ErrNoSessionID
}
//if it doesn't start with "Bearer ",
//return InvalidSessionID and ErrInvalidScheme
if !strings.HasPrefix(headAuth, schemeBearer) {
return InvalidSessionID, ErrInvalidScheme
}
//trim off the "Bearer " prefix and validate the remaining id
//if you get an error return InvalidSessionID and the error
sid := strings.TrimPrefix(headAuth, schemeBearer)
vsid, err := ValidateID(sid, signingKey)
if err != nil {
return InvalidSessionID, err
}
//return the validated SessionID and nil
return vsid, nil
}
//GetState extracts the SessionID from the request,
//and gets the associated state from the provided store
func GetState(r *http.Request, signingKey string, store Store, state interface{}) (SessionID, error) {
//get the SessionID from the request
//if you get an error, return the SessionID and error
sid, err := GetSessionID(r, signingKey)
if err != nil {
return sid, err
}
//get the associated state data from the provided store
//if you get an error return the SessionID and the error
err = store.Get(sid, state)
if err != nil {
return sid, err
}
//return the SessionID and nil
return sid, nil
}
//EndSession extracts the SessionID from the request,
//and deletes the associated data in the provided store
func EndSession(r *http.Request, signingKey string, store Store) (SessionID, error) {
//get the SessionID from the request
//if you get an error return the SessionID and error
sid, err := GetSessionID(r, signingKey)
if err != nil {
return sid, err
}
//delete the associated data in the provided store
err = store.Delete(sid)
if err != nil {
return sid, err
}
//return the SessionID and nil
return sid, nil
}