jwtauth.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  1. package tools
  2. import (
  3. "crypto/rsa"
  4. "errors"
  5. "io/ioutil"
  6. "net/http"
  7. "strings"
  8. "time"
  9. "github.com/dgrijalva/jwt-go"
  10. "github.com/gin-gonic/gin"
  11. )
  12. // MapClaims type that uses the map[string]interface{} for JSON decoding
  13. // This is the default claims type if you don't supply one
  14. type MapClaims map[string]interface{}
  15. // GinJWTMiddleware provides a Json-Web-Token authentication implementation. On failure, a 401 HTTP response
  16. // is returned. On success, the wrapped middleware is called, and the userID is made available as
  17. // c.Get("userID").(string).
  18. // Users can get a token by posting a json request to LoginHandler. The token then needs to be passed in
  19. // the Authentication header. Example: Authorization:Bearer XXX_TOKEN_XXX
  20. type GinJWTMiddleware struct {
  21. // Realm name to display to the user. Required.
  22. Realm string
  23. // signing algorithm - possible values are HS256, HS384, HS512, RS256, RS384 or RS512
  24. // Optional, default is HS256.
  25. SigningAlgorithm string
  26. // Secret key used for signing. Required.
  27. Key []byte
  28. // Duration that a jwt token is valid. Optional, defaults to one hour.
  29. Timeout time.Duration
  30. // This field allows clients to refresh their token until MaxRefresh has passed.
  31. // Note that clients can refresh their token in the last moment of MaxRefresh.
  32. // This means that the maximum validity timespan for a token is TokenTime + MaxRefresh.
  33. // Optional, defaults to 0 meaning not refreshable.
  34. MaxRefresh time.Duration
  35. // Callback function that should perform the authentication of the user based on login info.
  36. // Must return user data as user identifier, it will be stored in Claim Array. Required.
  37. // Check error (e) to determine the appropriate error message.
  38. Authenticator func(c *gin.Context) (interface{}, error)
  39. // Callback function that should perform the authorization of the authenticated user. Called
  40. // only after an authentication success. Must return true on success, false on failure.
  41. // Optional, default to success.
  42. Authorizator func(data interface{}, c *gin.Context) bool
  43. // Callback function that will be called during login.
  44. // Using this function it is possible to add additional payload data to the webtoken.
  45. // The data is then made available during requests via c.Get("JWT_PAYLOAD").
  46. // Note that the payload is not encrypted.
  47. // The attributes mentioned on jwt.io can't be used as keys for the map.
  48. // Optional, by default no additional data will be set.
  49. PayloadFunc func(data interface{}) MapClaims
  50. // User can define own Unauthorized func.
  51. Unauthorized func(*gin.Context, int, string)
  52. // User can define own LoginResponse func.
  53. LoginResponse func(*gin.Context, int, string, time.Time)
  54. // User can define own LogoutResponse func.
  55. LogoutResponse func(*gin.Context, int)
  56. // User can define own RefreshResponse func.
  57. RefreshResponse func(*gin.Context, int, string, time.Time)
  58. // Set the identity handler function
  59. IdentityHandler func(*gin.Context) interface{}
  60. // Set the identity key
  61. IdentityKey string
  62. // TokenLookup is a string in the form of "<source>:<name>" that is used
  63. // to extract token from the request.
  64. // Optional. Default value "header:Authorization".
  65. // Possible values:
  66. // - "header:<name>"
  67. // - "query:<name>"
  68. // - "cookie:<name>"
  69. TokenLookup string
  70. // TokenHeadName is a string in the header. Default value is "Bearer"
  71. TokenHeadName string
  72. // TimeFunc provides the current time. You can override it to use another time value. This is useful for testing or if your server uses a different time zone than your tokens.
  73. TimeFunc func() time.Time
  74. // HTTP Status messages for when something in the JWT middleware fails.
  75. // Check error (e) to determine the appropriate error message.
  76. HTTPStatusMessageFunc func(e error, c *gin.Context) string
  77. // Private key file for asymmetric algorithms
  78. PrivKeyFile string
  79. // Public key file for asymmetric algorithms
  80. PubKeyFile string
  81. // Private key
  82. privKey *rsa.PrivateKey
  83. // Public key
  84. pubKey *rsa.PublicKey
  85. // Optionally return the token as a cookie
  86. SendCookie bool
  87. // Duration that a cookie is valid. Optional, by default equals to Timeout value.
  88. CookieMaxAge time.Duration
  89. // Allow insecure cookies for development over http
  90. SecureCookie bool
  91. // Allow cookies to be accessed client side for development
  92. CookieHTTPOnly bool
  93. // Allow cookie domain change for development
  94. CookieDomain string
  95. // SendAuthorization allow return authorization header for every request
  96. SendAuthorization bool
  97. // Disable abort() of context.
  98. DisabledAbort bool
  99. // CookieName allow cookie name change for development
  100. CookieName string
  101. // CookieSameSite allow use http.SameSite cookie param
  102. CookieSameSite http.SameSite
  103. }
  104. var (
  105. // ErrMissingSecretKey indicates Secret key is required
  106. ErrMissingSecretKey = errors.New("secret key is required")
  107. // ErrForbidden when HTTP status 403 is given
  108. ErrForbidden = errors.New("you don't have permission to access this resource")
  109. // ErrMissingAuthenticatorFunc indicates Authenticator is required
  110. ErrMissingAuthenticatorFunc = errors.New("ginJWTMiddleware.Authenticator func is undefined")
  111. // ErrMissingLoginValues indicates a user tried to authenticate without username or password
  112. ErrMissingLoginValues = errors.New("missing Username or Password")
  113. // ErrFailedAuthentication indicates authentication failed, could be faulty username or password
  114. ErrFailedAuthentication = errors.New("incorrect Username or Password")
  115. // ErrFailedTokenCreation indicates JWT Token failed to create, reason unknown
  116. ErrFailedTokenCreation = errors.New("failed to create JWT Token")
  117. // ErrExpiredToken indicates JWT token has expired. Can't refresh.
  118. ErrExpiredToken = errors.New("token is expired")
  119. // ErrEmptyAuthHeader can be thrown if authing with a HTTP header, the Auth header needs to be set
  120. ErrEmptyAuthHeader = errors.New("auth header is empty")
  121. // ErrMissingExpField missing exp field in token
  122. ErrMissingExpField = errors.New("missing exp field")
  123. // ErrWrongFormatOfExp field must be float64 format
  124. ErrWrongFormatOfExp = errors.New("exp must be float64 format")
  125. // ErrInvalidAuthHeader indicates auth header is invalid, could for example have the wrong Realm name
  126. ErrInvalidAuthHeader = errors.New("auth header is invalid")
  127. // ErrEmptyQueryToken can be thrown if authing with URL Query, the query token variable is empty
  128. ErrEmptyQueryToken = errors.New("query token is empty")
  129. // ErrEmptyCookieToken can be thrown if authing with a cookie, the token cookie is empty
  130. ErrEmptyCookieToken = errors.New("cookie token is empty")
  131. // ErrEmptyParamToken can be thrown if authing with parameter in path, the parameter in path is empty
  132. ErrEmptyParamToken = errors.New("parameter token is empty")
  133. // ErrInvalidSigningAlgorithm indicates signing algorithm is invalid, needs to be HS256, HS384, HS512, RS256, RS384 or RS512
  134. ErrInvalidSigningAlgorithm = errors.New("invalid signing algorithm")
  135. // ErrNoPrivKeyFile indicates that the given private key is unreadable
  136. ErrNoPrivKeyFile = errors.New("private key file unreadable")
  137. // ErrNoPubKeyFile indicates that the given public key is unreadable
  138. ErrNoPubKeyFile = errors.New("public key file unreadable")
  139. // ErrInvalidPrivKey indicates that the given private key is invalid
  140. ErrInvalidPrivKey = errors.New("private key invalid")
  141. // ErrInvalidPubKey indicates the the given public key is invalid
  142. ErrInvalidPubKey = errors.New("public key invalid")
  143. // IdentityKey default identity key
  144. IdentityKey = "identity"
  145. //NiceKey = "nice"
  146. //
  147. //DataScopeKey = "datascope"
  148. //
  149. //RKey = "r"
  150. //RoleIdKey = "roleid"
  151. //
  152. //RoleKey = "rolekey"
  153. //
  154. //RoleNameKey = "rolename"
  155. )
  156. // New for check error with GinJWTMiddleware
  157. func New(m *GinJWTMiddleware) (*GinJWTMiddleware, error) {
  158. if err := m.MiddlewareInit(); err != nil {
  159. return nil, err
  160. }
  161. return m, nil
  162. }
  163. func (mw *GinJWTMiddleware) readKeys() error {
  164. err := mw.privateKey()
  165. if err != nil {
  166. return err
  167. }
  168. err = mw.publicKey()
  169. if err != nil {
  170. return err
  171. }
  172. return nil
  173. }
  174. func (mw *GinJWTMiddleware) privateKey() error {
  175. keyData, err := ioutil.ReadFile(mw.PrivKeyFile)
  176. if err != nil {
  177. return ErrNoPrivKeyFile
  178. }
  179. key, err := jwt.ParseRSAPrivateKeyFromPEM(keyData)
  180. if err != nil {
  181. return ErrInvalidPrivKey
  182. }
  183. mw.privKey = key
  184. return nil
  185. }
  186. func (mw *GinJWTMiddleware) publicKey() error {
  187. keyData, err := ioutil.ReadFile(mw.PubKeyFile)
  188. if err != nil {
  189. return ErrNoPubKeyFile
  190. }
  191. key, err := jwt.ParseRSAPublicKeyFromPEM(keyData)
  192. if err != nil {
  193. return ErrInvalidPubKey
  194. }
  195. mw.pubKey = key
  196. return nil
  197. }
  198. func (mw *GinJWTMiddleware) usingPublicKeyAlgo() bool {
  199. switch mw.SigningAlgorithm {
  200. case "RS256", "RS512", "RS384":
  201. return true
  202. }
  203. return false
  204. }
  205. // MiddlewareInit initialize jwt configs.
  206. func (mw *GinJWTMiddleware) MiddlewareInit() error {
  207. if mw.TokenLookup == "" {
  208. mw.TokenLookup = "header:Authorization"
  209. }
  210. if mw.SigningAlgorithm == "" {
  211. mw.SigningAlgorithm = "HS256"
  212. }
  213. if mw.Timeout == 0 {
  214. mw.Timeout = time.Hour
  215. }
  216. if mw.TimeFunc == nil {
  217. mw.TimeFunc = time.Now
  218. }
  219. mw.TokenHeadName = strings.TrimSpace(mw.TokenHeadName)
  220. if len(mw.TokenHeadName) == 0 {
  221. mw.TokenHeadName = "Bearer"
  222. }
  223. if mw.Authorizator == nil {
  224. mw.Authorizator = func(data interface{}, c *gin.Context) bool {
  225. return true
  226. }
  227. }
  228. if mw.Unauthorized == nil {
  229. mw.Unauthorized = func(c *gin.Context, code int, message string) {
  230. c.JSON(code, gin.H{
  231. "code": code,
  232. "message": message,
  233. })
  234. }
  235. }
  236. if mw.LoginResponse == nil {
  237. mw.LoginResponse = func(c *gin.Context, code int, token string, expire time.Time) {
  238. c.JSON(http.StatusOK, gin.H{
  239. "code": http.StatusOK,
  240. "token": token,
  241. "expire": expire.Format(time.RFC3339),
  242. })
  243. }
  244. }
  245. if mw.LogoutResponse == nil {
  246. mw.LogoutResponse = func(c *gin.Context, code int) {
  247. c.JSON(http.StatusOK, gin.H{
  248. "code": http.StatusOK,
  249. })
  250. }
  251. }
  252. if mw.RefreshResponse == nil {
  253. mw.RefreshResponse = func(c *gin.Context, code int, token string, expire time.Time) {
  254. c.JSON(http.StatusOK, gin.H{
  255. "code": http.StatusOK,
  256. "token": token,
  257. "expire": expire.Format(time.RFC3339),
  258. })
  259. }
  260. }
  261. if mw.IdentityKey == "" {
  262. mw.IdentityKey = IdentityKey
  263. }
  264. if mw.IdentityHandler == nil {
  265. mw.IdentityHandler = func(c *gin.Context) interface{} {
  266. claims := ExtractClaims(c)
  267. return claims[mw.IdentityKey]
  268. }
  269. }
  270. if mw.HTTPStatusMessageFunc == nil {
  271. mw.HTTPStatusMessageFunc = func(e error, c *gin.Context) string {
  272. return e.Error()
  273. }
  274. }
  275. if mw.Realm == "" {
  276. mw.Realm = "gin jwt"
  277. }
  278. if mw.CookieMaxAge == 0 {
  279. mw.CookieMaxAge = mw.Timeout
  280. }
  281. if mw.CookieName == "" {
  282. mw.CookieName = "jwt"
  283. }
  284. if mw.usingPublicKeyAlgo() {
  285. return mw.readKeys()
  286. }
  287. if mw.Key == nil {
  288. return ErrMissingSecretKey
  289. }
  290. return nil
  291. }
  292. // MiddlewareFunc makes GinJWTMiddleware implement the Middleware interface.
  293. func (mw *GinJWTMiddleware) MiddlewareFunc() gin.HandlerFunc {
  294. return func(c *gin.Context) {
  295. mw.middlewareImpl(c)
  296. }
  297. }
  298. func (mw *GinJWTMiddleware) middlewareImpl(c *gin.Context) {
  299. claims, err := mw.GetClaimsFromJWT(c)
  300. if err != nil {
  301. mw.unauthorized(c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(err, c))
  302. return
  303. }
  304. if claims["exp"] == nil {
  305. mw.unauthorized(c, http.StatusBadRequest, mw.HTTPStatusMessageFunc(ErrMissingExpField, c))
  306. return
  307. }
  308. if _, ok := claims["exp"].(float64); !ok {
  309. mw.unauthorized(c, http.StatusBadRequest, mw.HTTPStatusMessageFunc(ErrWrongFormatOfExp, c))
  310. return
  311. }
  312. if int64(claims["exp"].(float64)) < mw.TimeFunc().Unix() {
  313. mw.unauthorized(c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(ErrExpiredToken, c))
  314. return
  315. }
  316. c.Set("JWT_PAYLOAD", claims)
  317. identity := mw.IdentityHandler(c)
  318. if identity != nil {
  319. c.Set(mw.IdentityKey, identity)
  320. }
  321. if !mw.Authorizator(identity, c) {
  322. mw.unauthorized(c, http.StatusForbidden, mw.HTTPStatusMessageFunc(ErrForbidden, c))
  323. return
  324. }
  325. c.Next()
  326. }
  327. // GetClaimsFromJWT get claims from JWT token
  328. func (mw *GinJWTMiddleware) GetClaimsFromJWT(c *gin.Context) (MapClaims, error) {
  329. token, err := mw.ParseToken(c)
  330. if err != nil {
  331. return nil, err
  332. }
  333. if mw.SendAuthorization {
  334. if v, ok := c.Get("JWT_TOKEN"); ok {
  335. c.Header("Authorization", mw.TokenHeadName+" "+v.(string))
  336. }
  337. }
  338. claims := MapClaims{}
  339. for key, value := range token.Claims.(jwt.MapClaims) {
  340. claims[key] = value
  341. }
  342. return claims, nil
  343. }
  344. // LoginHandler can be used by clients to get a jwt token.
  345. // Payload needs to be json in the form of {"username": "USERNAME", "password": "PASSWORD"}.
  346. // Reply will be of the form {"token": "TOKEN"}.
  347. func (mw *GinJWTMiddleware) LoginHandler(c *gin.Context) {
  348. if mw.Authenticator == nil {
  349. mw.unauthorized(c, http.StatusInternalServerError, mw.HTTPStatusMessageFunc(ErrMissingAuthenticatorFunc, c))
  350. return
  351. }
  352. data, err := mw.Authenticator(c)
  353. if err != nil {
  354. mw.unauthorized(c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(err, c))
  355. return
  356. }
  357. // Create the token
  358. token := jwt.New(jwt.GetSigningMethod(mw.SigningAlgorithm))
  359. claims := token.Claims.(jwt.MapClaims)
  360. if mw.PayloadFunc != nil {
  361. for key, value := range mw.PayloadFunc(data) {
  362. claims[key] = value
  363. }
  364. }
  365. expire := mw.TimeFunc().Add(mw.Timeout)
  366. claims["exp"] = expire.Unix()
  367. claims["orig_iat"] = mw.TimeFunc().Unix()
  368. tokenString, err := mw.signedString(token)
  369. if err != nil {
  370. mw.unauthorized(c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(ErrFailedTokenCreation, c))
  371. return
  372. }
  373. // set cookie
  374. if mw.SendCookie {
  375. expireCookie := mw.TimeFunc().Add(mw.CookieMaxAge)
  376. maxage := int(expireCookie.Unix() - mw.TimeFunc().Unix())
  377. if mw.CookieSameSite != 0 {
  378. c.SetSameSite(mw.CookieSameSite)
  379. }
  380. c.SetCookie(
  381. mw.CookieName,
  382. tokenString,
  383. maxage,
  384. "/",
  385. mw.CookieDomain,
  386. mw.SecureCookie,
  387. mw.CookieHTTPOnly,
  388. )
  389. }
  390. mw.LoginResponse(c, http.StatusOK, tokenString, expire)
  391. }
  392. // LogoutHandler can be used by clients to remove the jwt cookie (if set)
  393. func (mw *GinJWTMiddleware) LogoutHandler(c *gin.Context) {
  394. // delete auth cookie
  395. if mw.SendCookie {
  396. if mw.CookieSameSite != 0 {
  397. c.SetSameSite(mw.CookieSameSite)
  398. }
  399. c.SetCookie(
  400. mw.CookieName,
  401. "",
  402. -1,
  403. "/",
  404. mw.CookieDomain,
  405. mw.SecureCookie,
  406. mw.CookieHTTPOnly,
  407. )
  408. }
  409. mw.LogoutResponse(c, http.StatusOK)
  410. }
  411. func (mw *GinJWTMiddleware) signedString(token *jwt.Token) (string, error) {
  412. var tokenString string
  413. var err error
  414. if mw.usingPublicKeyAlgo() {
  415. tokenString, err = token.SignedString(mw.privKey)
  416. } else {
  417. tokenString, err = token.SignedString(mw.Key)
  418. }
  419. return tokenString, err
  420. }
  421. // RefreshHandler can be used to refresh a token. The token still needs to be valid on refresh.
  422. // Shall be put under an endpoint that is using the GinJWTMiddleware.
  423. // Reply will be of the form {"token": "TOKEN"}.
  424. func (mw *GinJWTMiddleware) RefreshHandler(c *gin.Context) {
  425. tokenString, expire, err := mw.RefreshToken(c)
  426. if err != nil {
  427. mw.unauthorized(c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(err, c))
  428. return
  429. }
  430. mw.RefreshResponse(c, http.StatusOK, tokenString, expire)
  431. }
  432. // RefreshToken refresh token and check if token is expired
  433. func (mw *GinJWTMiddleware) RefreshToken(c *gin.Context) (string, time.Time, error) {
  434. claims, err := mw.CheckIfTokenExpire(c)
  435. if err != nil {
  436. return "", time.Now(), err
  437. }
  438. // Create the token
  439. newToken := jwt.New(jwt.GetSigningMethod(mw.SigningAlgorithm))
  440. newClaims := newToken.Claims.(jwt.MapClaims)
  441. for key := range claims {
  442. newClaims[key] = claims[key]
  443. }
  444. expire := mw.TimeFunc().Add(mw.Timeout)
  445. newClaims["exp"] = expire.Unix()
  446. newClaims["orig_iat"] = mw.TimeFunc().Unix()
  447. tokenString, err := mw.signedString(newToken)
  448. if err != nil {
  449. return "", time.Now(), err
  450. }
  451. // set cookie
  452. if mw.SendCookie {
  453. expireCookie := mw.TimeFunc().Add(mw.CookieMaxAge)
  454. maxage := int(expireCookie.Unix() - time.Now().Unix())
  455. if mw.CookieSameSite != 0 {
  456. c.SetSameSite(mw.CookieSameSite)
  457. }
  458. c.SetCookie(
  459. mw.CookieName,
  460. tokenString,
  461. maxage,
  462. "/",
  463. mw.CookieDomain,
  464. mw.SecureCookie,
  465. mw.CookieHTTPOnly,
  466. )
  467. }
  468. return tokenString, expire, nil
  469. }
  470. // CheckIfTokenExpire check if token expire
  471. func (mw *GinJWTMiddleware) CheckIfTokenExpire(c *gin.Context) (jwt.MapClaims, error) {
  472. token, err := mw.ParseToken(c)
  473. if err != nil {
  474. // If we receive an error, and the error is anything other than a single
  475. // ValidationErrorExpired, we want to return the error.
  476. // If the error is just ValidationErrorExpired, we want to continue, as we can still
  477. // refresh the token if it's within the MaxRefresh time.
  478. // (see https://github.com/appleboy/gin-jwt/issues/176)
  479. validationErr, ok := err.(*jwt.ValidationError)
  480. if !ok || validationErr.Errors != jwt.ValidationErrorExpired {
  481. return nil, err
  482. }
  483. }
  484. claims := token.Claims.(jwt.MapClaims)
  485. origIat := int64(claims["orig_iat"].(float64))
  486. if origIat < mw.TimeFunc().Add(-mw.MaxRefresh).Unix() {
  487. return nil, ErrExpiredToken
  488. }
  489. return claims, nil
  490. }
  491. // TokenGenerator method that clients can use to get a jwt token.
  492. func (mw *GinJWTMiddleware) TokenGenerator(data interface{}) (string, time.Time, error) {
  493. token := jwt.New(jwt.GetSigningMethod(mw.SigningAlgorithm))
  494. claims := token.Claims.(jwt.MapClaims)
  495. if mw.PayloadFunc != nil {
  496. for key, value := range mw.PayloadFunc(data) {
  497. claims[key] = value
  498. }
  499. }
  500. expire := mw.TimeFunc().UTC().Add(mw.Timeout)
  501. claims["exp"] = expire.Unix()
  502. claims["orig_iat"] = mw.TimeFunc().Unix()
  503. tokenString, err := mw.signedString(token)
  504. if err != nil {
  505. return "", time.Time{}, err
  506. }
  507. return tokenString, expire, nil
  508. }
  509. func (mw *GinJWTMiddleware) jwtFromHeader(c *gin.Context, key string) (string, error) {
  510. authHeader := c.Request.Header.Get(key)
  511. if authHeader == "" {
  512. return "", ErrEmptyAuthHeader
  513. }
  514. parts := strings.SplitN(authHeader, " ", 2)
  515. if !(len(parts) == 2 && parts[0] == mw.TokenHeadName) {
  516. return "", ErrInvalidAuthHeader
  517. }
  518. return parts[1], nil
  519. }
  520. func (mw *GinJWTMiddleware) jwtFromQuery(c *gin.Context, key string) (string, error) {
  521. token := c.Query(key)
  522. if token == "" {
  523. return "", ErrEmptyQueryToken
  524. }
  525. return token, nil
  526. }
  527. func (mw *GinJWTMiddleware) jwtFromCookie(c *gin.Context, key string) (string, error) {
  528. cookie, _ := c.Cookie(key)
  529. if cookie == "" {
  530. return "", ErrEmptyCookieToken
  531. }
  532. return cookie, nil
  533. }
  534. func (mw *GinJWTMiddleware) jwtFromParam(c *gin.Context, key string) (string, error) {
  535. token := c.Param(key)
  536. if token == "" {
  537. return "", ErrEmptyParamToken
  538. }
  539. return token, nil
  540. }
  541. // ParseToken parse jwt token from gin context
  542. func (mw *GinJWTMiddleware) ParseToken(c *gin.Context) (*jwt.Token, error) {
  543. var token string
  544. var err error
  545. methods := strings.Split(mw.TokenLookup, ",")
  546. for _, method := range methods {
  547. if len(token) > 0 {
  548. break
  549. }
  550. parts := strings.Split(strings.TrimSpace(method), ":")
  551. k := strings.TrimSpace(parts[0])
  552. v := strings.TrimSpace(parts[1])
  553. switch k {
  554. case "header":
  555. token, err = mw.jwtFromHeader(c, v)
  556. case "query":
  557. token, err = mw.jwtFromQuery(c, v)
  558. case "cookie":
  559. token, err = mw.jwtFromCookie(c, v)
  560. case "param":
  561. token, err = mw.jwtFromParam(c, v)
  562. }
  563. }
  564. if err != nil {
  565. return nil, err
  566. }
  567. return jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
  568. if jwt.GetSigningMethod(mw.SigningAlgorithm) != t.Method {
  569. return nil, ErrInvalidSigningAlgorithm
  570. }
  571. if mw.usingPublicKeyAlgo() {
  572. return mw.pubKey, nil
  573. }
  574. // save token string if vaild
  575. c.Set("JWT_TOKEN", token)
  576. return mw.Key, nil
  577. })
  578. }
  579. // ParseTokenString parse jwt token string
  580. func (mw *GinJWTMiddleware) ParseTokenString(token string) (*jwt.Token, error) {
  581. return jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
  582. if jwt.GetSigningMethod(mw.SigningAlgorithm) != t.Method {
  583. return nil, ErrInvalidSigningAlgorithm
  584. }
  585. if mw.usingPublicKeyAlgo() {
  586. return mw.pubKey, nil
  587. }
  588. return mw.Key, nil
  589. })
  590. }
  591. func (mw *GinJWTMiddleware) unauthorized(c *gin.Context, code int, message string) {
  592. c.Header("WWW-Authenticate", "JWT realm="+mw.Realm)
  593. if !mw.DisabledAbort {
  594. c.Abort()
  595. }
  596. mw.Unauthorized(c, code, message)
  597. }
  598. // ExtractClaims help to extract the JWT claims
  599. func ExtractClaims(c *gin.Context) MapClaims {
  600. claims, exists := c.Get("JWT_PAYLOAD")
  601. if !exists {
  602. return make(MapClaims)
  603. }
  604. return claims.(MapClaims)
  605. }
  606. // ExtractClaimsFromToken help to extract the JWT claims from token
  607. func ExtractClaimsFromToken(token *jwt.Token) MapClaims {
  608. if token == nil {
  609. return make(MapClaims)
  610. }
  611. claims := MapClaims{}
  612. for key, value := range token.Claims.(jwt.MapClaims) {
  613. claims[key] = value
  614. }
  615. return claims
  616. }
  617. // GetToken help to get the JWT token string
  618. func GetToken(c *gin.Context) string {
  619. token, exists := c.Get("JWT_TOKEN")
  620. if !exists {
  621. return ""
  622. }
  623. return token.(string)
  624. }