/
jwt.go
98 lines (80 loc) · 2.29 KB
/
jwt.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
package main
import (
"context"
"fmt"
"net/http"
"time"
"github.com/dgrijalva/jwt-go"
)
type Key int
const MyKey Key = 0
// JWT schema of the data it will store
type Claims struct {
Username string `json:"username"`
jwt.StandardClaims
}
// create a JWT and put in the clients cookie
func setToken(res http.ResponseWriter, req *http.Request) {
expireToken := time.Now().Add(time.Hour * 1).Unix()
expireCookie := time.Now().Add(time.Hour * 1)
claims := Claims{
"myusername",
jwt.StandardClaims{
ExpiresAt: expireToken,
Issuer: "localhost:9000",
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
signedToken, _ := token.SignedString([]byte("secret"))
cookie := http.Cookie{Name: "Auth", Value: signedToken, Expires: expireCookie, HttpOnly: true}
http.SetCookie(res, &cookie)
http.Redirect(res, req, "/profile", 307)
}
// middleware to protect private pages
func validate(page http.HandlerFunc) http.HandlerFunc {
return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
cookie, err := req.Cookie("Auth")
if err != nil {
http.NotFound(res, req)
return
}
token, err := jwt.ParseWithClaims(cookie.Value, &Claims{}, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("Unexpected signing method")
}
return []byte("secret"), nil
})
if err != nil {
http.NotFound(res, req)
return
}
if claims, ok := token.Claims.(*Claims); ok && token.Valid {
ctx := context.WithValue(req.Context(), MyKey, *claims)
page(res, req.WithContext(ctx))
} else {
http.NotFound(res, req)
return
}
})
}
// only viewable if the client has a valid token
func protectedProfile(res http.ResponseWriter, req *http.Request) {
claims, ok := req.Context().Value(MyKey).(Claims)
if !ok {
http.NotFound(res, req)
return
}
fmt.Fprintf(res, "Hello %s", claims.Username)
}
// deletes the cookie
func logout(res http.ResponseWriter, req *http.Request) {
deleteCookie := http.Cookie{Name: "Auth", Value: "none", Expires: time.Now()}
http.SetCookie(res, &deleteCookie)
return
}
func main() {
http.HandleFunc("/settoken", setToken)
http.HandleFunc("/profile", validate(protectedProfile))
http.HandleFunc("/logout", validate(logout))
http.ListenAndServe(":9000", nil)
}