forked from dghubble/gologin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
147 lines (133 loc) · 4.43 KB
/
main.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// main is an example web app using Login with Twitter.
package main
import (
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"github.com/dghubble/ctxh"
"github.com/dghubble/gologin/twitter"
"github.com/dghubble/oauth1"
twitterOAuth1 "github.com/dghubble/oauth1/twitter"
"github.com/dghubble/sessions"
"golang.org/x/net/context"
)
const (
sessionName = "example-twtter-app"
sessionSecret = "example cookie signing secret"
sessionUserKey = "twitterID"
)
// sessionStore encodes and decodes session data stored in signed cookies
var sessionStore = sessions.NewCookieStore([]byte(sessionSecret), nil)
// Config configures the main ServeMux.
type Config struct {
TwitterConsumerKey string
TwitterConsumerSecret string
}
// New returns a new ServeMux with app routes.
func New(config *Config) *http.ServeMux {
mux := http.NewServeMux()
mux.HandleFunc("/", welcomeHandler)
mux.Handle("/profile", requireLogin(http.HandlerFunc(profileHandler)))
mux.HandleFunc("/logout", logoutHandler)
// 1. Register Twitter login and callback handlers
oauth1Config := &oauth1.Config{
ConsumerKey: config.TwitterConsumerKey,
ConsumerSecret: config.TwitterConsumerSecret,
CallbackURL: "http://localhost:8080/twitter/callback",
Endpoint: twitterOAuth1.AuthorizeEndpoint,
}
mux.Handle("/twitter/login", ctxh.NewHandler(twitter.LoginHandler(oauth1Config, nil)))
mux.Handle("/twitter/callback", ctxh.NewHandler(twitter.CallbackHandler(oauth1Config, issueSession(), nil)))
return mux
}
// issueSession issues a cookie session after successful Twitter login
func issueSession() ctxh.ContextHandler {
fn := func(ctx context.Context, w http.ResponseWriter, req *http.Request) {
twitterUser, err := twitter.UserFromContext(ctx)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// 2. Implement a success handler to issue some form of session
session := sessionStore.New(sessionName)
session.Values[sessionUserKey] = twitterUser.ID
session.Save(w)
http.Redirect(w, req, "/profile", http.StatusFound)
}
return ctxh.ContextHandlerFunc(fn)
}
// welcomeHandler shows a welcome message and login button.
func welcomeHandler(w http.ResponseWriter, req *http.Request) {
if req.URL.Path != "/" {
http.NotFound(w, req)
return
}
if isAuthenticated(req) {
http.Redirect(w, req, "/profile", http.StatusFound)
return
}
page, _ := ioutil.ReadFile("home.html")
fmt.Fprintf(w, string(page))
}
// profileHandler shows protected user content.
func profileHandler(w http.ResponseWriter, req *http.Request) {
fmt.Fprint(w, `<p>You are logged in!</p><form action="/logout" method="post"><input type="submit" value="Logout"></form>`)
}
// logoutHandler destroys the session on POSTs and redirects to home.
func logoutHandler(w http.ResponseWriter, req *http.Request) {
if req.Method == "POST" {
sessionStore.Destroy(w, sessionName)
}
http.Redirect(w, req, "/", http.StatusFound)
}
// requireLogin redirects unauthenticated users to the login route.
func requireLogin(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, req *http.Request) {
if !isAuthenticated(req) {
http.Redirect(w, req, "/", http.StatusFound)
return
}
next.ServeHTTP(w, req)
}
return http.HandlerFunc(fn)
}
// isAuthenticated returns true if the user has a signed session cookie.
func isAuthenticated(req *http.Request) bool {
if _, err := sessionStore.Get(req, sessionName); err == nil {
return true
}
return false
}
// main creates and starts a Server listening.
func main() {
const address = "localhost:8080"
// read credentials from environment variables if available
config := &Config{
TwitterConsumerKey: os.Getenv("TWITTER_CONSUMER_KEY"),
TwitterConsumerSecret: os.Getenv("TWITTER_CONSUMER_SECRET"),
}
// allow consumer credential flags to override config fields
consumerKey := flag.String("consumer-key", "", "Twitter Consumer Key")
consumerSecret := flag.String("consumer-secret", "", "Twitter Consumer Secret")
flag.Parse()
if *consumerKey != "" {
config.TwitterConsumerKey = *consumerKey
}
if *consumerSecret != "" {
config.TwitterConsumerSecret = *consumerSecret
}
if config.TwitterConsumerKey == "" {
log.Fatal("Missing Twitter Consumer Key")
}
if config.TwitterConsumerSecret == "" {
log.Fatal("Missing Twitter Consumer Secret")
}
log.Printf("Starting Server listening on %s\n", address)
err := http.ListenAndServe(address, New(config))
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}