1
0

jwtauth.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. package jwtauth
  2. import (
  3. "crypto/rsa"
  4. "errors"
  5. "github.com/dgrijalva/jwt-go"
  6. "github.com/gin-gonic/gin"
  7. "github.com/go-redis/redis/v7"
  8. "io/ioutil"
  9. "net/http"
  10. "strings"
  11. "time"
  12. )
  13. const JwtPayloadKey = "JWT_PAYLOAD"
  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
  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 RefreshResponse func.
  55. RefreshResponse func(*gin.Context, int, string, time.Time)
  56. // Set the identity handler function
  57. IdentityHandler func(*gin.Context) interface{}
  58. // Set the identity key
  59. IdentityKey string
  60. // username
  61. NiceKey string
  62. DataScopeKey string
  63. // rolekey
  64. RKey string
  65. // roleId
  66. RoleIdKey string
  67. //deptId
  68. DeptIdKey string
  69. DeptNameKey string
  70. RoleKey string
  71. // roleName
  72. RoleNameKey string
  73. SingleKey bool
  74. // TokenLookup is a string in the form of "<source>:<name>" that is used
  75. // to extract token from the request.
  76. // Optional. Default value "header:Authorization".
  77. // Possible values:
  78. // - "header:<name>"
  79. // - "query:<name>"
  80. // - "cookie:<name>"
  81. TokenLookup string
  82. // TokenHeadName is a string in the header. Default value is "Bearer"
  83. TokenHeadName string
  84. // 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.
  85. TimeFunc func() time.Time
  86. // HTTP Status messages for when something in the JWT middleware fails.
  87. // Check error (e) to determine the appropriate error message.
  88. HTTPStatusMessageFunc func(e error, c *gin.Context) string
  89. // Private key file for asymmetric algorithms
  90. PrivKeyFile string
  91. // Public key file for asymmetric algorithms
  92. PubKeyFile string
  93. // Private key
  94. privKey *rsa.PrivateKey
  95. // Public key
  96. pubKey *rsa.PublicKey
  97. // Optionally return the token as a cookie
  98. SendCookie bool
  99. // Allow insecure cookies for development over http
  100. SecureCookie bool
  101. // Allow cookies to be accessed client side for development
  102. CookieHTTPOnly bool
  103. // Allow cookie domain change for development
  104. CookieDomain string
  105. // SendAuthorization allow return authorization header for every request
  106. SendAuthorization bool
  107. // Disable abort() of context.
  108. DisabledAbort bool
  109. // CookieName allow cookie name change for development
  110. CookieName string
  111. // 保存token的key
  112. SaveNewestToken func(c *gin.Context, userId int64, token string, expire int64) error
  113. GetNewestToken func(c *gin.Context, userId int64) (string, error)
  114. SetEnterDeptId func(c *gin.Context, newTToken string,userId int64) error
  115. }
  116. var (
  117. // ErrMissingSecretKey indicates Secret key is required
  118. ErrMissingSecretKey = errors.New("secret key is required")
  119. // ErrForbidden when HTTP status 403 is given
  120. ErrForbidden = errors.New("you don't have permission to access this resource")
  121. // ErrMissingAuthenticatorFunc indicates Authenticator is required
  122. ErrMissingAuthenticatorFunc = errors.New("ginJWTMiddleware.Authenticator func is undefined")
  123. // ErrMissingLoginValues indicates a user tried to authenticate without username or password
  124. ErrMissingLoginValues = errors.New("missing Username or Password or Code")
  125. // ErrFailedAuthentication indicates authentication failed, could be faulty username or password
  126. //ErrFailedAuthentication = errors.New("incorrect Username or Password")
  127. ErrFailedAuthentication = errors.New("用户名或密码不正确")
  128. ErrFailedSmsVerifyCode = errors.New("短信验证码错误")
  129. ErrAccountDeactivated = errors.New("账号已停用")
  130. ErrSingleLogin = errors.New("您的账号已在其他地方登录,请重新登录或退出")
  131. // ErrFailedTokenCreation indicates JWT Token failed to create, reason unknown
  132. ErrFailedTokenCreation = errors.New("failed to create JWT Token")
  133. // ErrExpiredToken indicates JWT token has expired. Can't refresh.
  134. ErrExpiredToken = errors.New("Token is expired")
  135. // ErrEmptyAuthHeader can be thrown if authing with a HTTP header, the Auth header needs to be set
  136. ErrEmptyAuthHeader = errors.New("auth header is empty")
  137. // ErrMissingExpField missing exp field in token
  138. ErrMissingExpField = errors.New("missing exp field")
  139. // ErrWrongFormatOfExp field must be float64 format
  140. ErrWrongFormatOfExp = errors.New("exp must be float64 format")
  141. // ErrInvalidAuthHeader indicates auth header is invalid, could for example have the wrong Realm name
  142. ErrInvalidAuthHeader = errors.New("auth header is invalid")
  143. // ErrEmptyQueryToken can be thrown if authing with URL Query, the query token variable is empty
  144. ErrEmptyQueryToken = errors.New("query token is empty")
  145. // ErrEmptyCookieToken can be thrown if authing with a cookie, the token cokie is empty
  146. ErrEmptyCookieToken = errors.New("cookie token is empty")
  147. // ErrEmptyParamToken can be thrown if authing with parameter in path, the parameter in path is empty
  148. ErrEmptyParamToken = errors.New("parameter token is empty")
  149. // ErrInvalidSigningAlgorithm indicates signing algorithm is invalid, needs to be HS256, HS384, HS512, RS256, RS384 or RS512
  150. ErrInvalidSigningAlgorithm = errors.New("invalid signing algorithm")
  151. ErrInvalidVerificationCode = errors.New("验证码错误")
  152. // ErrNoPrivKeyFile indicates that the given private key is unreadable
  153. ErrNoPrivKeyFile = errors.New("private key file unreadable")
  154. // ErrNoPubKeyFile indicates that the given public key is unreadable
  155. ErrNoPubKeyFile = errors.New("public key file unreadable")
  156. // ErrInvalidPrivKey indicates that the given private key is invalid
  157. ErrInvalidPrivKey = errors.New("private key invalid")
  158. // ErrInvalidPubKey indicates the the given public key is invalid
  159. ErrInvalidPubKey = errors.New("public key invalid")
  160. UUIDKey = "uuid"
  161. // IdentityKey default identity key
  162. IdentityKey = "identity"
  163. UserNameKey = "username"
  164. DataScopeKey = "dataScope"
  165. // RoleIdKey 角色id Old
  166. RoleIdKey = "roleId"
  167. // RoleKey 角色key Old
  168. RoleKey = "roleKey"
  169. // RoleNameKey 角色名称 Old
  170. RoleNameKey = "roleName"
  171. // 单一登录标识
  172. SingleKey = "single"
  173. // DeptIdKey 部门 Old
  174. DeptIdKey = "deptId"
  175. DeptNameKey = "deptName"
  176. RandomKey = "randomName"
  177. )
  178. // New for check error with GinJWTMiddleware
  179. func New(m *GinJWTMiddleware) (*GinJWTMiddleware, error) {
  180. if err := m.MiddlewareInit(); err != nil {
  181. return nil, err
  182. }
  183. return m, nil
  184. }
  185. func (mw *GinJWTMiddleware) readKeys() error {
  186. err := mw.privateKey()
  187. if err != nil {
  188. return err
  189. }
  190. err = mw.publicKey()
  191. if err != nil {
  192. return err
  193. }
  194. return nil
  195. }
  196. func (mw *GinJWTMiddleware) privateKey() error {
  197. keyData, err := ioutil.ReadFile(mw.PrivKeyFile)
  198. if err != nil {
  199. return ErrNoPrivKeyFile
  200. }
  201. key, err := jwt.ParseRSAPrivateKeyFromPEM(keyData)
  202. if err != nil {
  203. return ErrInvalidPrivKey
  204. }
  205. mw.privKey = key
  206. return nil
  207. }
  208. func (mw *GinJWTMiddleware) publicKey() error {
  209. keyData, err := ioutil.ReadFile(mw.PubKeyFile)
  210. if err != nil {
  211. return ErrNoPubKeyFile
  212. }
  213. key, err := jwt.ParseRSAPublicKeyFromPEM(keyData)
  214. if err != nil {
  215. return ErrInvalidPubKey
  216. }
  217. mw.pubKey = key
  218. return nil
  219. }
  220. func (mw *GinJWTMiddleware) usingPublicKeyAlgo() bool {
  221. switch mw.SigningAlgorithm {
  222. case "RS256", "RS512", "RS384":
  223. return true
  224. }
  225. return false
  226. }
  227. // MiddlewareInit initialize jwt configs.
  228. func (mw *GinJWTMiddleware) MiddlewareInit() error {
  229. if mw.TokenLookup == "" {
  230. mw.TokenLookup = "header:Authorization"
  231. }
  232. if mw.SigningAlgorithm == "" {
  233. mw.SigningAlgorithm = "HS256"
  234. }
  235. if mw.TimeFunc == nil {
  236. mw.TimeFunc = time.Now
  237. }
  238. mw.TokenHeadName = strings.TrimSpace(mw.TokenHeadName)
  239. if len(mw.TokenHeadName) == 0 {
  240. mw.TokenHeadName = "Bearer"
  241. }
  242. if mw.Authorizator == nil {
  243. mw.Authorizator = func(data interface{}, c *gin.Context) bool {
  244. return true
  245. }
  246. }
  247. if mw.Unauthorized == nil {
  248. mw.Unauthorized = func(c *gin.Context, code int, message string) {
  249. c.JSON(http.StatusOK, gin.H{
  250. "code": code,
  251. "message": message,
  252. })
  253. }
  254. }
  255. if mw.LoginResponse == nil {
  256. mw.LoginResponse = func(c *gin.Context, code int, token string, expire time.Time) {
  257. c.JSON(http.StatusOK, gin.H{
  258. "code": http.StatusOK,
  259. "token": token,
  260. "expire": expire.Format(time.RFC3339),
  261. })
  262. }
  263. }
  264. if mw.RefreshResponse == nil {
  265. mw.RefreshResponse = func(c *gin.Context, code int, token string, expire time.Time) {
  266. c.JSON(http.StatusOK, gin.H{
  267. "code": http.StatusOK,
  268. "token": token,
  269. "expire": expire.Format(time.RFC3339),
  270. })
  271. }
  272. }
  273. if mw.IdentityKey == "" {
  274. mw.IdentityKey = IdentityKey
  275. }
  276. if mw.IdentityHandler == nil {
  277. mw.IdentityHandler = func(c *gin.Context) interface{} {
  278. claims := ExtractClaims(c)
  279. return claims
  280. }
  281. }
  282. if mw.HTTPStatusMessageFunc == nil {
  283. mw.HTTPStatusMessageFunc = func(e error, c *gin.Context) string {
  284. return e.Error()
  285. }
  286. }
  287. if mw.Realm == "" {
  288. mw.Realm = "gin jwt"
  289. }
  290. if mw.CookieName == "" {
  291. mw.CookieName = "jwt"
  292. }
  293. if mw.usingPublicKeyAlgo() {
  294. return mw.readKeys()
  295. }
  296. if mw.Key == nil {
  297. return ErrMissingSecretKey
  298. }
  299. return nil
  300. }
  301. // MiddlewareFunc makes GinJWTMiddleware implement the Middleware interface.
  302. func (mw *GinJWTMiddleware) MiddlewareFunc() gin.HandlerFunc {
  303. return func(c *gin.Context) {
  304. mw.middlewareImpl(c)
  305. }
  306. }
  307. func (mw *GinJWTMiddleware) middlewareImpl(c *gin.Context) {
  308. claims, err := mw.GetClaimsFromJWT(c)
  309. if err != nil {
  310. if err.Error() == ErrExpiredToken.Error() {
  311. mw.unauthorized(c, 6401, mw.HTTPStatusMessageFunc(ErrExpiredToken, c))
  312. return
  313. } else {
  314. mw.unauthorized(c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(err, c))
  315. return
  316. }
  317. }
  318. if claims["exp"] == nil {
  319. mw.unauthorized(c, http.StatusBadRequest, mw.HTTPStatusMessageFunc(ErrMissingExpField, c))
  320. return
  321. }
  322. if _, ok := claims["exp"].(float64); !ok {
  323. mw.unauthorized(c, http.StatusBadRequest, mw.HTTPStatusMessageFunc(ErrWrongFormatOfExp, c))
  324. return
  325. }
  326. if int64(claims["exp"].(float64)) < mw.TimeFunc().Unix() {
  327. mw.unauthorized(c, 6401, mw.HTTPStatusMessageFunc(ErrExpiredToken, c))
  328. return
  329. }
  330. c.Set(JwtPayloadKey, claims)
  331. identity := mw.IdentityHandler(c)
  332. if identity != nil {
  333. c.Set(mw.IdentityKey, identity)
  334. }
  335. if !mw.Authorizator(identity, c) {
  336. mw.unauthorized(c, http.StatusForbidden, mw.HTTPStatusMessageFunc(ErrForbidden, c))
  337. return
  338. }
  339. if claims["single"].(bool) {
  340. token, err := mw.GetNewestToken(c, int64(claims["identity"].(float64)))
  341. if err != nil && errors.Is(err, redis.Nil) {
  342. // 没有获取到最新的token
  343. mw.unauthorized(c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(ErrEmptyQueryToken, c))
  344. return
  345. }
  346. if token != GetToken(c) {
  347. mw.unauthorized(c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(ErrSingleLogin, c))
  348. return
  349. }
  350. }
  351. c.Next()
  352. }
  353. // GetClaimsFromJWT get claims from JWT token
  354. func (mw *GinJWTMiddleware) GetClaimsFromJWT(c *gin.Context) (MapClaims, error) {
  355. token, err := mw.ParseToken(c)
  356. if err != nil {
  357. return nil, err
  358. }
  359. if mw.SendAuthorization {
  360. if v, ok := c.Get("JWT_TOKEN"); ok {
  361. c.Header("Authorization", mw.TokenHeadName+" "+v.(string))
  362. }
  363. }
  364. claims := MapClaims{}
  365. for key, value := range token.Claims.(jwt.MapClaims) {
  366. claims[key] = value
  367. }
  368. return claims, nil
  369. }
  370. // LoginHandler can be used by clients to get a jwt token.
  371. // Payload needs to be json in the form of {"username": "USERNAME", "password": "PASSWORD"}.
  372. // Reply will be of the form {"token": "TOKEN"}.
  373. func (mw *GinJWTMiddleware) LoginHandler(c *gin.Context) {
  374. if mw.Authenticator == nil {
  375. mw.unauthorized(c, http.StatusInternalServerError, mw.HTTPStatusMessageFunc(ErrMissingAuthenticatorFunc, c))
  376. return
  377. }
  378. data, err := mw.Authenticator(c)
  379. if err != nil {
  380. mw.unauthorized(c, 400, mw.HTTPStatusMessageFunc(err, c))
  381. return
  382. }
  383. // Create the token
  384. token := jwt.New(jwt.GetSigningMethod(mw.SigningAlgorithm))
  385. claims := token.Claims.(jwt.MapClaims)
  386. if mw.PayloadFunc != nil {
  387. for key, value := range mw.PayloadFunc(data) {
  388. claims[key] = value
  389. }
  390. }
  391. expire := mw.TimeFunc().Add(mw.Timeout)
  392. // 登录类型 手机登录
  393. if v, ok := data.(map[string]interface{}); ok {
  394. if t, ok2 := v["mobile"].(bool); ok2 {
  395. if t {
  396. expire = mw.TimeFunc().Add(time.Duration(876000/2) * time.Hour)
  397. //mw.Timeout = time.Duration(876000) * time.Hour
  398. }
  399. }
  400. }
  401. claims["exp"] = expire.Unix()
  402. claims["orig_iat"] = mw.TimeFunc().Unix()
  403. tokenString, err := mw.signedString(token)
  404. if err != nil {
  405. mw.unauthorized(c, http.StatusInternalServerError, mw.HTTPStatusMessageFunc(ErrFailedTokenCreation, c))
  406. return
  407. }
  408. // set cookie
  409. if mw.SendCookie {
  410. maxage := int(expire.Unix() - time.Now().Unix())
  411. c.SetCookie(
  412. mw.CookieName,
  413. tokenString,
  414. maxage,
  415. "/",
  416. mw.CookieDomain,
  417. mw.SecureCookie,
  418. mw.CookieHTTPOnly,
  419. )
  420. }
  421. if claims["single"].(bool) {
  422. _ = mw.SaveNewestToken(c, int64(claims["identity"].(int)), tokenString, int64(mw.Timeout)/3600)
  423. }
  424. mw.LoginResponse(c, http.StatusOK, tokenString, expire)
  425. }
  426. func (mw *GinJWTMiddleware) signedString(token *jwt.Token) (string, error) {
  427. var tokenString string
  428. var err error
  429. if mw.usingPublicKeyAlgo() {
  430. tokenString, err = token.SignedString(mw.privKey)
  431. } else {
  432. tokenString, err = token.SignedString(mw.Key)
  433. }
  434. return tokenString, err
  435. }
  436. func (mw *GinJWTMiddleware) RefreshHandler(c *gin.Context) {
  437. tokenString, expire, err := mw.RefreshToken(c)
  438. if err != nil {
  439. mw.unauthorized(c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(err, c))
  440. return
  441. }
  442. mw.RefreshResponse(c, http.StatusOK, tokenString, expire)
  443. }
  444. // RefreshToken refresh token and check if token is expired
  445. func (mw *GinJWTMiddleware) RefreshToken(c *gin.Context) (string, time.Time, error) {
  446. claims, err := mw.CheckIfTokenExpire(c)
  447. if err != nil {
  448. return "", time.Now(), err
  449. }
  450. // Create the token
  451. newToken := jwt.New(jwt.GetSigningMethod(mw.SigningAlgorithm))
  452. newClaims := newToken.Claims.(jwt.MapClaims)
  453. for key := range claims {
  454. newClaims[key] = claims[key]
  455. }
  456. expire := mw.TimeFunc().Add(mw.Timeout)
  457. newClaims["exp"] = expire.Unix()
  458. newClaims["orig_iat"] = mw.TimeFunc().Unix()
  459. tokenString, err := mw.signedString(newToken)
  460. if err != nil {
  461. return "", time.Now(), err
  462. }
  463. // set cookie
  464. if mw.SendCookie {
  465. maxage := int(expire.Unix() - time.Now().Unix())
  466. c.SetCookie(
  467. mw.CookieName,
  468. tokenString,
  469. maxage,
  470. "/",
  471. mw.CookieDomain,
  472. mw.SecureCookie,
  473. mw.CookieHTTPOnly,
  474. )
  475. }
  476. if mw.SetEnterDeptId != nil {
  477. mw.SetEnterDeptId(c,tokenString,int64(claims["identity"].(float64)))
  478. }
  479. if claims["single"].(bool) {
  480. _ = mw.SaveNewestToken(c, int64(claims["identity"].(float64)), tokenString, int64(mw.Timeout)/3600)
  481. }
  482. return tokenString, expire, nil
  483. }
  484. // CheckIfTokenExpire check if token expire
  485. func (mw *GinJWTMiddleware) CheckIfTokenExpire(c *gin.Context) (jwt.MapClaims, error) {
  486. token, err := mw.ParseToken(c)
  487. if err != nil {
  488. // If we receive an error, and the error is anything other than a single
  489. // ValidationErrorExpired, we want to return the error.
  490. // If the error is just ValidationErrorExpired, we want to continue, as we can still
  491. // refresh the token if it's within the MaxRefresh time.
  492. // (see https://github.com/appleboy/gin-jwt/issues/176)
  493. validationErr, ok := err.(*jwt.ValidationError)
  494. if !ok || validationErr.Errors != jwt.ValidationErrorExpired {
  495. return nil, err
  496. }
  497. }
  498. claims := token.Claims.(jwt.MapClaims)
  499. origIat := int64(claims["orig_iat"].(float64))
  500. if origIat < mw.TimeFunc().Add(-mw.MaxRefresh).Unix() {
  501. return nil, ErrExpiredToken
  502. }
  503. return claims, nil
  504. }
  505. // TokenGenerator method that clients can use to get a jwt token.
  506. func (mw *GinJWTMiddleware) TokenGenerator(data interface{}) (string, time.Time, error) {
  507. token := jwt.New(jwt.GetSigningMethod(mw.SigningAlgorithm))
  508. claims := token.Claims.(jwt.MapClaims)
  509. if mw.PayloadFunc != nil {
  510. for key, value := range mw.PayloadFunc(data) {
  511. claims[key] = value
  512. }
  513. }
  514. expire := mw.TimeFunc().UTC().Add(mw.Timeout)
  515. claims["exp"] = expire.Unix()
  516. claims["orig_iat"] = mw.TimeFunc().Unix()
  517. tokenString, err := mw.signedString(token)
  518. if err != nil {
  519. return "", time.Time{}, err
  520. }
  521. return tokenString, expire, nil
  522. }
  523. func (mw *GinJWTMiddleware) jwtFromHeader(c *gin.Context, key string) (string, error) {
  524. authHeader := c.Request.Header.Get(key)
  525. if authHeader == "" {
  526. return "", ErrEmptyAuthHeader
  527. }
  528. parts := strings.SplitN(authHeader, " ", 2)
  529. if !(len(parts) == 2 && parts[0] == mw.TokenHeadName) {
  530. return "", ErrInvalidAuthHeader
  531. }
  532. return parts[1], nil
  533. }
  534. func (mw *GinJWTMiddleware) jwtFromQuery(c *gin.Context, key string) (string, error) {
  535. token := c.Query(key)
  536. if token == "" {
  537. return "", ErrEmptyQueryToken
  538. }
  539. return token, nil
  540. }
  541. func (mw *GinJWTMiddleware) jwtFromCookie(c *gin.Context, key string) (string, error) {
  542. cookie, _ := c.Cookie(key)
  543. if cookie == "" {
  544. return "", ErrEmptyCookieToken
  545. }
  546. return cookie, nil
  547. }
  548. func (mw *GinJWTMiddleware) jwtFromParam(c *gin.Context, key string) (string, error) {
  549. token := c.Param(key)
  550. if token == "" {
  551. return "", ErrEmptyParamToken
  552. }
  553. return token, nil
  554. }
  555. // ParseToken parse jwt token from gin context
  556. func (mw *GinJWTMiddleware) ParseToken(c *gin.Context) (*jwt.Token, error) {
  557. var token string
  558. var err error
  559. methods := strings.Split(mw.TokenLookup, ",")
  560. for _, method := range methods {
  561. if len(token) > 0 {
  562. break
  563. }
  564. parts := strings.Split(strings.TrimSpace(method), ":")
  565. k := strings.TrimSpace(parts[0])
  566. v := strings.TrimSpace(parts[1])
  567. switch k {
  568. case "header":
  569. token, err = mw.jwtFromHeader(c, v)
  570. case "query":
  571. token, err = mw.jwtFromQuery(c, v)
  572. case "cookie":
  573. token, err = mw.jwtFromCookie(c, v)
  574. case "param":
  575. token, err = mw.jwtFromParam(c, v)
  576. }
  577. }
  578. if err != nil {
  579. return nil, err
  580. }
  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. c.Set("JWT_TOKEN", token)
  589. return mw.Key, nil
  590. })
  591. }
  592. // ParseTokenString parse jwt token string
  593. func (mw *GinJWTMiddleware) ParseTokenString(token string) (*jwt.Token, error) {
  594. return jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
  595. if jwt.GetSigningMethod(mw.SigningAlgorithm) != t.Method {
  596. return nil, ErrInvalidSigningAlgorithm
  597. }
  598. if mw.usingPublicKeyAlgo() {
  599. return mw.pubKey, nil
  600. }
  601. return mw.Key, nil
  602. })
  603. }
  604. func (mw *GinJWTMiddleware) unauthorized(c *gin.Context, code int, message string) {
  605. c.Header("WWW-Authenticate", "JWT realm="+mw.Realm)
  606. if !mw.DisabledAbort {
  607. c.Abort()
  608. }
  609. mw.Unauthorized(c, code, message)
  610. }
  611. // ExtractClaims help to extract the JWT claims
  612. func ExtractClaims(c *gin.Context) MapClaims {
  613. claims, exists := c.Get(JwtPayloadKey)
  614. if !exists {
  615. return make(MapClaims)
  616. }
  617. return claims.(MapClaims)
  618. }
  619. // ExtractClaimsFromToken help to extract the JWT claims from token
  620. func ExtractClaimsFromToken(token *jwt.Token) MapClaims {
  621. if token == nil {
  622. return make(MapClaims)
  623. }
  624. claims := MapClaims{}
  625. for key, value := range token.Claims.(jwt.MapClaims) {
  626. claims[key] = value
  627. }
  628. return claims
  629. }
  630. // GetToken help to get the JWT token string
  631. func GetToken(c *gin.Context) string {
  632. token, exists := c.Get("JWT_TOKEN")
  633. if !exists {
  634. return ""
  635. }
  636. return token.(string)
  637. }