8000 Merge pull request #4 from Saxleader/master · Abhicodeitout/GolangTraining@f17a280 · GitHub
[go: up one dir, main page]

Skip to content

Commit f17a280

Browse files
committed
Merge pull request GoesToEleven#4 from Saxleader/master
Oauth2 Google Code Complete
2 parents 01f62a3 + 596f08d commit f17a280

File tree

3 files changed

+206
-0
lines changed

3 files changed

+206
-0
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
application: practical-scion-114602
2+
version: alpha-01
3+
runtime: go
4+
api_version: go1
5+
6+
handlers:
7+
- url: /.*
8+
secure: always
9+
script: _go_app
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
package googleOauth2
2+
3+
import (
4+
"github.com/julienschmidt/httprouter"
5+
6+
"google.golang.org/appengine"
7+
"google.golang.org/appengine/log"
8+
9+
"google.golang.org/api/gmail/v1"
10+
11+
"golang.org/x/oauth2/google"
12+
"golang.org/x/oauth2"
13+
14+
"net/http"
15+
"io"
16+
"github.com/nu7hatch/gouuid"
17+
)
18+
19+
var conf = &oauth2.Config{
20+
ClientID:"979509136073-10ce3r5s8mka304l6od82t3nltp9cf8s.apps.googleusercontent.com",
21+
ClientSecret:"5zwpEL5WwwekeMsZoz6mcC0s",
22+
RedirectURL:"https://practical-scion-114602.appspot.com/oauth2callback",
23+
Scopes:[]string{"https://www.googleapis.com/auth/gmail.readonly"},
24+
Endpoint: google.Endpoint,
25+
}
26+
27+
func init() {
28+
r := httprouter.New()
29+
r.GET("/",handleIndex)
30+
r.GET("/login",handleLogin)
31+
r.GET("/oauth2callback",handleAuthorize)
32+
http.Handle("/",r)
33+
}
34+
35+
func handleIndex(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {
36+
io.WriteString(res,`<!DOCTYPE html>
37+
<html>
38+
<head></head>
39+
<body>
40+
<a href="/login">Login with Google to read your mail</a>
41+
</body>
42+
</html>`)
43+
}
44+
45+
func handleLogin(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {
46+
ctx := appengine.NewContext(req)
47+
48+
//get session for storing state to check on callback
49+
s := getSession(ctx,req)
50+
51+
//generate state for checking later
52+
state, err := uuid.NewV4()
53+
if err != nil {
54+
http.Error(res, "Server Error",http.StatusInternalServerError)
55+
log.Errorf(ctx,err.Error())
56+
return
57+
}
58+
59+
//put state in session and putting to memcache to check on callback
60+
s.State = state.String()
61+
err = putSession(ctx,res,s)
62+
if err != nil {
63+
http.Error(res, "Server Error",http.StatusInternalServerError)
64+
log.Errorf(ctx,err.Error())
65+
return
66+
}
67+
68+
//generate the authorization url that goes to the login and consent page for google.
69+
//I set the ApprovalForce option so that it asks for consent each time so that we can see it.
70+
//Shows application asking to "Have offline access" each time. can remove second arg to remove this.
71+
url := conf.AuthCodeURL(s.State,oauth2.ApprovalForce)
72+
http.Redirect(res,req,url,http.StatusSeeOther)
73+
}
74+
75+
func handleAuthorize(res http.ResponseWriter, req *http.Request, _ httprouter.Params) {
76+
ctx := appengine.NewContext(req)
77+
78+
//retrieve code and state from the callback
79+
code, state := req.FormValue("code"),req.FormValue("state")
80+
81+
//get session from memcache
82+
s := getSession(ctx,req)
83+
84+
//compare state from callback with state stored in memcache
85+
if state != s.State{
86+
http.Error(res, "Detected cross-site attack", http.StatusUnauthorized)
87+
log.Criticalf(ctx, "Non-matching states from %s", req.RemoteAddr)
88+
return
89+
}
90+
91+
//exchange the auth code given for an access token
92+
tok, err := conf.Exchange(ctx,code)
93+
if err != nil {
94+
http.Error(res, "Server Error",http.StatusInternalServerError)
95+
log.Errorf(ctx,err.Error())
96+
return
97+
}
98+
99+
//create a client from the token
100+
client := conf.Client(ctx,tok)
101+
102+
//create a gmail service from the client
103+
srv, err := gmail.New(client)
104+
if err != nil {
105+
http.Error(res, "Server Error",http.StatusInternalServerError)
106+
log.Errorf(ctx,err.Error())
107+
return
108+
}
109+
110+
//request a list of messages in the user's mailbox
111+
list, err := srv.Users.Threads.List("me").Do()
112+
if err != nil {
113+
http.Error(res, "Server Error",http.StatusInternalServerError)
114+
log.Errorf(ctx,err.Error())
115+
return
116+
}
117+
118+
//loop through and print out the first 25 message threads from your mailbox
119+
output := "<p>Messages:</p>"
120+
if len(list.Threads) > 0 {
121+
i := 1
122+
for _, val := range list.Threads {
123+
output += "<p>- "+val.Snippet+"...</p>"
124+
if i > 25 {
125+
break
126+
}
127+
i++
128+
}
129+
}else{
130+
output += "<p>You have no messages!</p>"
131+
}
132+
io.WriteString(res,output)
133+
}
134+
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package googleOauth2
2+
3+
import (
4+
"encoding/json"
5+
"net/http"
6+
7+
"github.com/nu7hatch/gouuid"
8+
"golang.org/x/net/context"
9+
"google.golang.org/appengine/memcache"
10+
)
11+
12+
const cookieName = "sessionid"
13+
14+
type session struct {
15+
ID string `json:"-"`
16+
State string
17+
}
18+
19+
func getSession(ctx context.Context, req *http.Request) session {
20+
cookie, err := req.Cookie(cookieName)
21+
if err != nil || cookie.Value == "" {
22+
uid, _ := uuid.NewV4()
23+
cookie = &http.Cookie{
24+
Name: cookieName,
25+
Value: uid.String(),
26+
}
27+
}
28+
29+
item, err := memcache.Get(ctx, cookie.Value)
30+
if err != nil {
31+
item = &memcache.Item{
32+
Key: cookie.Value,
33+
Value: []byte(""),
34+
}
35+
}
36+
37+
var s session
38+
json.Unmarshal(item.Value, &s)
39+
s.ID = cookie.Value
40+
return s
41+
}
42+
43+
func putSession(ctx context.Context, res http.ResponseWriter, s session) error {
44+
bs, err := json.Marshal(s)
45+
if err != nil {
46+
return err
47+
}
48+
49+
err = memcache.Set(ctx, &memcache.Item{
50+
Key: s.ID,
51+
Value: bs,
52+
})
53+
if err != nil {
54+
return err
55+
}
56+
57+
http.SetCookie(res, &http.Cookie{
58+
Name: cookieName,
59+
Value: s.ID,
60+
})
61+
62+
return nil
63+
}

0 commit comments

Comments
 (0)
0