Bez popisu

oauth2.go 7.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. package main
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "net/http"
  7. "net/url"
  8. "strings"
  9. "github.com/google/go-querystring/query"
  10. "github.com/parnurzeal/gorequest"
  11. "gopkg.in/mgo.v2"
  12. "gopkg.in/mgo.v2/bson"
  13. )
  14. type OAuth2Params struct {
  15. Code string `json:"code" url:"code"`
  16. ClientId string `json:"client_id" url:"client_id"`
  17. ClientSecret string `json:"client_secret" url:"client_secret"`
  18. RedirectUri string `json:"redirect_uri" url:"redirect_uri"`
  19. GrantType string `json:"grant_type,omitempty" url:"grant_type,omitempty"`
  20. }
  21. type accessTokenData struct {
  22. AccessToken string `json:"access_token" url:"access_token"`
  23. TokenType string `json:"token_type" url:"token_type"`
  24. ExpiresIn int `json:"expires_in" url:"expires_in"`
  25. }
  26. func (f *OAuth2Params) LoadFromHTTPRequest(r *http.Request) {
  27. type requestData struct {
  28. Code string `json:"code"`
  29. ClientId string `json:"clientId"`
  30. RedirectUri string `json:"redirectUri"`
  31. }
  32. decoder := json.NewDecoder(r.Body)
  33. var data requestData
  34. err := decoder.Decode(&data)
  35. if err != nil {
  36. panic(err)
  37. }
  38. f.Code = data.Code
  39. f.ClientId = data.ClientId
  40. f.RedirectUri = data.RedirectUri
  41. }
  42. func newFBParams() *OAuth2Params {
  43. return &OAuth2Params{
  44. ClientSecret: config.FACEBOOK_SECRET,
  45. }
  46. }
  47. func newGoogleParams() *OAuth2Params {
  48. return &OAuth2Params{
  49. ClientSecret: config.GOOGLE_SECRET,
  50. GrantType: "authorization_code",
  51. }
  52. }
  53. func LoginWithFacebook(w http.ResponseWriter, r *http.Request) {
  54. apiUrl := "https://graph.facebook.com"
  55. accessTokenPath := "/v2.3/oauth/access_token"
  56. graphApiPath := "/v2.3/me"
  57. // Step 1. Exchange authorization code for access token.
  58. fbparams := newFBParams()
  59. fbparams.LoadFromHTTPRequest(r)
  60. v, _ := query.Values(fbparams)
  61. u, _ := url.ParseRequestURI(apiUrl)
  62. u.Path = accessTokenPath
  63. u.RawQuery = v.Encode()
  64. urlStr := fmt.Sprintf("%v", u)
  65. res, body, _ := gorequest.New().Get(urlStr).End()
  66. if res.StatusCode != 200 {
  67. var errorData map[string]interface{}
  68. json.Unmarshal([]byte(body), &errorData)
  69. ServeJSON(w, r, &Response{
  70. "message": errorData["error"].(map[string]interface{})["message"],
  71. }, 500)
  72. return
  73. }
  74. // Step 2. Retrieve profile information about the current user.
  75. var atData accessTokenData
  76. err := json.Unmarshal([]byte(body), &atData)
  77. v, _ = query.Values(atData)
  78. u, _ = url.ParseRequestURI(apiUrl)
  79. u.Path = graphApiPath
  80. u.RawQuery = v.Encode()
  81. urlStr = fmt.Sprintf("%v", u)
  82. resProfile, body, _ := gorequest.New().Get(urlStr).End()
  83. var profileData map[string]interface{}
  84. err = json.Unmarshal([]byte(body), &profileData)
  85. if resProfile.StatusCode != 200 {
  86. ServeJSON(w, r, &Response{
  87. "message": profileData["error"].(map[string]interface{})["message"],
  88. }, 500)
  89. return
  90. }
  91. db := GetDB(w, r)
  92. if IsTokenSet(r) {
  93. // Step 3a. Link user accounts.
  94. existingUser, errM := FindUserByProvider(db, "facebook", profileData["id"].(string))
  95. if existingUser != nil {
  96. ServeJSON(w, r, &Response{
  97. "message": "There is already a Facebook account that belongs to you",
  98. }, 409)
  99. return
  100. }
  101. if errM != nil && errM.Reason != mgo.ErrNotFound {
  102. HandleModelError(w, r, errM)
  103. return
  104. }
  105. tokenData := GetToken(w, r)
  106. user, errM := FindUserById(db, bson.ObjectIdHex(tokenData.ID))
  107. if user == nil {
  108. ServeJSON(w, r, &Response{
  109. "message": "User not found",
  110. }, 400)
  111. return
  112. }
  113. if errM != nil && errM.Reason != mgo.ErrNotFound {
  114. HandleModelError(w, r, errM)
  115. return
  116. }
  117. user.Facebook = profileData["id"].(string)
  118. if user.Picture == "" {
  119. user.Picture = "https://graph.facebook.com/v2.3/" + profileData["id"].(string) + "/picture?type=large"
  120. }
  121. if user.DisplayName == "" {
  122. user.DisplayName = profileData["name"].(string)
  123. }
  124. err = user.Save(db)
  125. if err != nil {
  126. ISR(w, r, errors.New("Couldn't save user profile informations"))
  127. }
  128. SetToken(w, r, user)
  129. } else {
  130. // Step 3b. Create a new user account or return an existing one.
  131. existingUser, errM := FindUserByProvider(db, "facebook", profileData["id"].(string))
  132. if existingUser != nil {
  133. SetToken(w, r, existingUser)
  134. return
  135. }
  136. if errM != nil && errM.Reason != mgo.ErrNotFound {
  137. HandleModelError(w, r, errM)
  138. return
  139. }
  140. // Create user with his facebook id
  141. user := NewUser()
  142. user.Facebook = profileData["id"].(string)
  143. user.Email = profileData["email"].(string)
  144. user.Picture = "https://graph.facebook.com/v2.3/" + profileData["id"].(string) + "/picture?type=large"
  145. user.DisplayName = profileData["name"].(string)
  146. err = user.Save(db)
  147. if err != nil {
  148. ISR(w, r, err)
  149. return
  150. }
  151. SetToken(w, r, user)
  152. }
  153. }
  154. func LoginWithGoogle(w http.ResponseWriter, r *http.Request) {
  155. accessTokenUrl := "https://accounts.google.com/o/oauth2/token"
  156. peopleApiUrl := "https://www.googleapis.com"
  157. peopleApiPath := "/plus/v1/people/me/openIdConnect"
  158. // Step 1. Exchange authorization code for access token.
  159. googleParams := newGoogleParams()
  160. googleParams.LoadFromHTTPRequest(r)
  161. v, _ := query.Values(googleParams)
  162. res, body, _ := gorequest.New().Post(accessTokenUrl).
  163. Send(v.Encode()).
  164. Type("form").
  165. End()
  166. if res.StatusCode != 200 {
  167. var errorData map[string]interface{}
  168. json.Unmarshal([]byte(body), &errorData)
  169. ServeJSON(w, r, &Response{
  170. "message": errorData["error"].(string),
  171. }, 500)
  172. return
  173. }
  174. // Step 2. Retrieve profile information about the current user.
  175. var atData accessTokenData
  176. err := json.Unmarshal([]byte(body), &atData)
  177. qs, _ := query.Values(atData)
  178. u, _ := url.ParseRequestURI(peopleApiUrl)
  179. u.Path = peopleApiPath
  180. u.RawQuery = qs.Encode()
  181. urlStr := fmt.Sprintf("%v", u)
  182. resProfile, body, _ := gorequest.New().Get(urlStr).End()
  183. var profileData map[string]interface{}
  184. err = json.Unmarshal([]byte(body), &profileData)
  185. if resProfile.StatusCode != 200 {
  186. ServeJSON(w, r, &Response{
  187. "message": profileData["error"].(map[string]interface{})["message"],
  188. }, 500)
  189. return
  190. }
  191. db := GetDB(w, r)
  192. if IsTokenSet(r) {
  193. // Step 3a. Link user accounts.
  194. existingUser, errM := FindUserByProvider(db, "google", profileData["sub"].(string))
  195. if existingUser != nil {
  196. ServeJSON(w, r, &Response{
  197. "message": "There is already a Facebook account that belongs to you",
  198. }, 409)
  199. return
  200. }
  201. if errM != nil && errM.Reason != mgo.ErrNotFound {
  202. HandleModelError(w, r, errM)
  203. return
  204. }
  205. tokenData := GetToken(w, r)
  206. user, errM := FindUserById(db, bson.ObjectIdHex(tokenData.ID))
  207. if user == nil {
  208. ServeJSON(w, r, &Response{
  209. "message": "User not found",
  210. }, 400)
  211. return
  212. }
  213. if errM != nil && errM.Reason != mgo.ErrNotFound {
  214. HandleModelError(w, r, errM)
  215. return
  216. }
  217. user.Google = profileData["sub"].(string)
  218. if user.Picture == "" {
  219. user.Picture = strings.Replace(profileData["picture"].(string), "sz=50", "sz=200", -1)
  220. }
  221. if user.DisplayName == "" {
  222. user.DisplayName = profileData["name"].(string)
  223. }
  224. err = user.Save(db)
  225. if err != nil {
  226. ISR(w, r, errors.New("Couldn't save user profile informations"))
  227. }
  228. SetToken(w, r, user)
  229. } else {
  230. // Step 3b. Create a new user account or return an existing one.
  231. existingUser, errM := FindUserByProvider(db, "google", profileData["sub"].(string))
  232. if existingUser != nil {
  233. SetToken(w, r, existingUser)
  234. return
  235. }
  236. if errM != nil && errM.Reason != mgo.ErrNotFound {
  237. HandleModelError(w, r, errM)
  238. return
  239. }
  240. // Create user with his google id
  241. user := NewUser()
  242. user.Google = profileData["sub"].(string)
  243. user.Email = profileData["email"].(string)
  244. user.Picture = strings.Replace(profileData["picture"].(string), "sz=50", "sz=200", -1)
  245. user.DisplayName = profileData["name"].(string)
  246. err = user.Save(db)
  247. if err != nil {
  248. ISR(w, r, err)
  249. return
  250. }
  251. SetToken(w, r, user)
  252. }
  253. }
  254. func NewClient() *http.Client {
  255. return &http.Client{}
  256. }