user.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "log"
  6. "net/http"
  7. "strings"
  8. "time"
  9. "zero/core/conf"
  10. "zero/rest"
  11. "zero/rest/httpx"
  12. "github.com/dgrijalva/jwt-go"
  13. "github.com/dgrijalva/jwt-go/request"
  14. )
  15. const jwtUserField = "user"
  16. type (
  17. Config struct {
  18. rest.RestConf
  19. AccessSecret string
  20. AccessExpire int64 `json:",default=1209600"` // 2 weeks
  21. RefreshSecret string
  22. RefreshExpire int64 `json:",default=2419200"` // 4 weeks
  23. RefreshAfter int64 `json:",default=604800"` // 1 week
  24. }
  25. TokenOptions struct {
  26. AccessSecret string
  27. AccessExpire int64
  28. RefreshSecret string
  29. RefreshExpire int64
  30. RefreshAfter int64
  31. Fields map[string]interface{}
  32. }
  33. Tokens struct {
  34. // Access token to access the apis
  35. AccessToken string `json:"access_token"`
  36. // Access token expire time, generated like: time.Now().Add(time.Day*14).Unix()
  37. AccessExpire int64 `json:"access_expire"`
  38. // Refresh token, use this to refresh the token
  39. RefreshToken string `json:"refresh_token"`
  40. // Refresh token expire time, generated like: time.Now().Add(time.Month).Unix()
  41. RefreshExpire int64 `json:"refresh_expire"`
  42. // Recommended time to refresh the access token
  43. RefreshAfter int64 `json:"refresh_after"`
  44. }
  45. UserCredentials struct {
  46. Username string `json:"username"`
  47. Password string `json:"password"`
  48. }
  49. User struct {
  50. ID int `json:"id"`
  51. Name string `json:"name"`
  52. Username string `json:"username"`
  53. Password string `json:"password"`
  54. }
  55. Response struct {
  56. Data string `json:"data"`
  57. }
  58. Token struct {
  59. Token string `json:"token"`
  60. }
  61. AuthRequest struct {
  62. User string `json:"u"`
  63. }
  64. )
  65. func main() {
  66. var c Config
  67. conf.MustLoad("user.json", &c)
  68. engine, err := rest.NewServer(c.RestConf)
  69. if err != nil {
  70. log.Fatal(err)
  71. }
  72. defer engine.Stop()
  73. engine.AddRoute(rest.Route{
  74. Method: http.MethodPost,
  75. Path: "/login",
  76. Handler: LoginHandler(c),
  77. })
  78. engine.AddRoute(rest.Route{
  79. Method: http.MethodGet,
  80. Path: "/resource",
  81. Handler: ProtectedHandler,
  82. }, rest.WithJwt(c.AccessSecret))
  83. engine.AddRoute(rest.Route{
  84. Method: http.MethodPost,
  85. Path: "/refresh",
  86. Handler: RefreshHandler(c),
  87. }, rest.WithJwt(c.RefreshSecret))
  88. fmt.Println("Now listening...")
  89. engine.Start()
  90. }
  91. func RefreshHandler(c Config) http.HandlerFunc {
  92. return func(w http.ResponseWriter, r *http.Request) {
  93. var authReq AuthRequest
  94. if err := httpx.Parse(r, &authReq); err != nil {
  95. w.WriteHeader(http.StatusBadRequest)
  96. fmt.Println(err)
  97. return
  98. }
  99. token, err := request.ParseFromRequest(r, request.AuthorizationHeaderExtractor,
  100. func(token *jwt.Token) (interface{}, error) {
  101. return []byte(c.RefreshSecret), nil
  102. })
  103. if err != nil {
  104. w.WriteHeader(http.StatusUnauthorized)
  105. fmt.Println("Unauthorized access to this resource")
  106. return
  107. }
  108. if !token.Valid {
  109. w.WriteHeader(http.StatusUnauthorized)
  110. fmt.Println("Token is not valid")
  111. return
  112. }
  113. claims, ok := token.Claims.(jwt.MapClaims)
  114. if !ok {
  115. w.WriteHeader(http.StatusBadRequest)
  116. fmt.Println("not a valid jwt.MapClaims")
  117. return
  118. }
  119. user, ok := claims[jwtUserField]
  120. if !ok {
  121. w.WriteHeader(http.StatusBadRequest)
  122. fmt.Println("no user info in fresh token")
  123. return
  124. }
  125. userStr, ok := user.(string)
  126. if !ok || authReq.User != userStr {
  127. w.WriteHeader(http.StatusBadRequest)
  128. fmt.Println("user info not match in query and fresh token")
  129. return
  130. }
  131. respond(w, c, userStr)
  132. }
  133. }
  134. func ProtectedHandler(w http.ResponseWriter, r *http.Request) {
  135. response := Response{"Gained access to protected resource"}
  136. JsonResponse(response, w)
  137. }
  138. func LoginHandler(c Config) http.HandlerFunc {
  139. return func(w http.ResponseWriter, r *http.Request) {
  140. var user UserCredentials
  141. if err := httpx.Parse(r, &user); err != nil {
  142. w.WriteHeader(http.StatusBadRequest)
  143. fmt.Fprint(w, "Error in request")
  144. return
  145. }
  146. if strings.ToLower(user.Username) != "someone" {
  147. if user.Password != "p@ssword" {
  148. w.WriteHeader(http.StatusForbidden)
  149. fmt.Println("Error logging in")
  150. fmt.Fprint(w, "Invalid credentials")
  151. return
  152. }
  153. }
  154. respond(w, c, user.Username)
  155. }
  156. }
  157. func JsonResponse(response interface{}, w http.ResponseWriter) {
  158. content, err := json.Marshal(response)
  159. if err != nil {
  160. http.Error(w, err.Error(), http.StatusInternalServerError)
  161. return
  162. }
  163. w.WriteHeader(http.StatusOK)
  164. w.Header().Set("Content-Type", "application/json")
  165. w.Write(content)
  166. }
  167. type ()
  168. func buildTokens(opt TokenOptions) (Tokens, error) {
  169. var tokens Tokens
  170. accessToken, err := genToken(opt.AccessSecret, opt.Fields, opt.AccessExpire)
  171. if err != nil {
  172. return tokens, err
  173. }
  174. refreshToken, err := genToken(opt.RefreshSecret, opt.Fields, opt.RefreshExpire)
  175. if err != nil {
  176. return tokens, err
  177. }
  178. now := time.Now().Unix()
  179. tokens.AccessToken = accessToken
  180. tokens.AccessExpire = now + opt.AccessExpire
  181. tokens.RefreshAfter = now + opt.RefreshAfter
  182. tokens.RefreshToken = refreshToken
  183. tokens.RefreshExpire = now + opt.RefreshExpire
  184. return tokens, nil
  185. }
  186. func genToken(secretKey string, payloads map[string]interface{}, seconds int64) (string, error) {
  187. now := time.Now().Unix()
  188. claims := make(jwt.MapClaims)
  189. claims["exp"] = now + seconds
  190. claims["iat"] = now
  191. for k, v := range payloads {
  192. claims[k] = v
  193. }
  194. token := jwt.New(jwt.SigningMethodHS256)
  195. token.Claims = claims
  196. return token.SignedString([]byte(secretKey))
  197. }
  198. func respond(w http.ResponseWriter, c Config, user string) {
  199. tokens, err := buildTokens(TokenOptions{
  200. AccessSecret: c.AccessSecret,
  201. AccessExpire: c.AccessExpire,
  202. RefreshSecret: c.RefreshSecret,
  203. RefreshExpire: c.RefreshExpire,
  204. RefreshAfter: c.RefreshAfter,
  205. Fields: map[string]interface{}{
  206. jwtUserField: user,
  207. },
  208. })
  209. if err != nil {
  210. w.WriteHeader(http.StatusServiceUnavailable)
  211. fmt.Println(err)
  212. return
  213. }
  214. httpx.OkJson(w, tokens)
  215. }