github.com/aldelo/common@v1.5.1/wrapper/gin/ginjwt.go (about) 1 package gin 2 3 /* 4 * Copyright 2020-2023 Aldelo, LP 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 import ( 20 "fmt" 21 util "github.com/aldelo/common" 22 "github.com/aldelo/common/wrapper/gin/ginbindtype" 23 "github.com/aldelo/common/wrapper/gin/ginjwtsignalgorithm" 24 "log" 25 "net/http" 26 "time" 27 28 jwt "github.com/appleboy/gin-jwt/v2" 29 "github.com/gin-gonic/gin" 30 ) 31 32 // NewGinJwtMiddleware helper method returns a GinJwt struct object ready for setup and use 33 // 34 // Realm = (required) Realm name to display to the user 35 // IdentityKey = (required) IdentityKey defines the key used for storing identity info in jwt claim 36 // SigningSecretKey = (required) Secret key used for signing 37 // AuthenticateBindingType = (required) AuthenticateBindingType defines the binding type to use for login form field data 38 func NewGinJwtMiddleware(realm string, identityKey string, signingSecretKey string, authenticateBindingType ginbindtype.GinBindType) *GinJwt { 39 return &GinJwt{ 40 Realm: realm, 41 IdentityKey: identityKey, 42 SigningSecretKey: signingSecretKey, 43 SigningAlgorithm: ginjwtsignalgorithm.HS256, 44 AuthenticateBindingType: authenticateBindingType, 45 } 46 } 47 48 // GinJwt struct encapsulates gin authentication and authorization related services, along with jwt handling 49 // 50 // *** Basic Setup *** 51 // Realm = (required) Realm name to display to the user 52 // IdentityKey = (required) IdentityKey defines the key used for storing identity info in jwt claim 53 // SigningSecretKey = (required) Secret key used for signing 54 // SigningAlgorithm = (required) HS256, HS384, HS512, RS256, RS384 or RS512 Optional, default is HS256 55 // PrivateKeyFile = (optional) Private key file for asymmetric algorithms 56 // PublicKeyFile = (optional) Public key file for asymmetric algorithms 57 // TokenValidDuration = (required) Duration that a jwt token is valid. Optional, defaults to one hour. (aka Timeout) 58 // TokenMaxRefreshDuration = (required) This field allows clients to refresh their token until MaxRefresh has passed, 59 // 60 // Note that clients can refresh their token in the last moment of MaxRefresh, 61 // This means that the maximum validity timespan for a token is TokenTime + MaxRefresh, 62 // Optional, defaults to 0 meaning not refreshable 63 // 64 // SendAuthorization = (optional) SendAuthorization allow return authorization header for every request, default = false 65 // DisableAbort = (optional) Disable abort() of context, default = false 66 // TokenLookup = (optional) TokenLookup is a string in the form of "<source>:<name>" that is used to extract token from the request, 67 // 68 // Optional. Default value = "header: Authorization", 69 // Possible values: 70 // - "header:<name>" 71 // - "query:<name>" 72 // - "cookie:<name>" 73 // - "param:<name>" 74 // Examples: 75 // TokenLookup: "header: Authorization, query: token, cookie: jwt", 76 // TokenLookup: "query:token", 77 // TokenLookup: "cookie:token", 78 // 79 // TokenHeadName = (optional) TokenHeadName is a string in the header. Default value = "Bearer" 80 // 81 // *** Cookie Setup *** 82 // SendCookie = (optional) Optionally return the token as a cookie, default = false 83 // CookieHttpOnly = (optional) Allow cookies to be accessed client side for development, default = true 84 // SecureCookie = (optional) Allow insecure cookies for development over http, default = true 85 // CookieMaxAge = (optional) Duration that a cookie is valid. Optional, by default = Timeout value 86 // CookieDomain = (optional) Allow cookie domain change for development, default = "" 87 // CookieName = (optional) CookieName allow cookie name change for development, default = "" 88 // CookieSameSite = (optional) CookieSameSite allow use http.SameSite cookie param, default = SameSiteDefaultMode 89 // 90 // values = default, lax, strict, none 91 // 92 // *** Authentication Setup *** 93 // AuthenticateBindingType = (required) AuthenticateBindingType defines the binding type to use for login form field data 94 // LoginRequestDataPtr = (optional) LoginRequestDataPtr contains pointer object that represents login request (used for binding), if not set, default = &UserLogin helper struct 95 // LoginRoutePath = (required) LoginRoutePath defines the relative path to the gin jwt middleware's built-in LoginHandler action, sets up as POST 96 // LogoutRoutePath = (optional) LogoutRoutePath defines the relative path to the gin jwt middleware's built-in LogoutHandler action, sets up as POST 97 // RefreshTokenRoutePath = (optional) RefreshTokenRoutePath defines the relative path to the middleware's built-in RefreshHandler action, sets up as GET 98 // AuthenticateHandler = (required) AuthenticateHandler func is called by Authenticator, 99 // 100 // receives loginRequestDataPtr for authentication use, 101 // if authentication succeeds, returns the loggedInCredentialPtr object 102 // (which typically is a user object containing user information logged in) 103 // 104 // AddClaimsHandler = (optional) LoggedInMapClaimsHandler func is called during Authenticator action upon success, 105 // 106 // so that this handler when coded can insert jwt additional payload data, 107 // - loggedInCredentialPtr = the returning loggedInCredentialPtr from LoginHandler, 108 // - identityKeyValue = string value for the named identityKey defined within the struct 109 // 110 // GetIdentityHandler = (optional) GetIdentityHandler func is called when IdentityHandler is triggered, 111 // 112 // field values from claims will be parsed and returned via object by the implementation code 113 // 114 // LoginResponseHandler = (optional) Callback function to handle custom login response 115 // LogoutResponseHandler = (optional) Callback function to handle custom logout response 116 // RefreshTokenResponseHandler = (optional) Callback function to handle custom token refresh response 117 // 118 // *** Authorization Setup *** 119 // AuthorizerHandler = (optional) AuthorizerHandler func is called during authorization after authentication, 120 // 121 // to validate if the current credential has access rights to certain parts of the target site, 122 // the loggedInCredentialPtr is the object that LoginHandler returns upon successful authentication, 123 // - return value of true indicates authorization success, 124 // - return value of false indicates authorization failure 125 // 126 // UnauthorizedHandler = (optional) UnauthorizedHandler func is called when the authorization is not authorized, 127 // 128 // this handler will return the unauthorized message content to caller, 129 // such as via c.JSON, c.HTML, etc as dictated by the handler implementation process, 130 // - c *gin.Context = context used to return the unauthorized access content 131 // - code / message = unauthorized code and message as given by the web server to respond back to the caller 132 // 133 // *** Other Handlers *** 134 // TimeHandler = (optional) TimeHandler provides the current time, 135 // 136 // override it to use another time value, 137 // useful for testing or if server uses a different time zone than the tokens, 138 // default = time.Now() 139 // 140 // NoRouteHandler = (optional) Defines the route handler to execute when no route is encountered 141 // MiddlewareErrorEvaluator = (optional) HTTP Status messages for when something in the JWT middleware fails, 142 // 143 // Check error (e) to determine the appropriate error message 144 type GinJwt struct { 145 // ----------------------------------------------------------------------------------------------------------------- 146 // gin jwt setup fields 147 // ----------------------------------------------------------------------------------------------------------------- 148 149 // Realm name to display to the user. Required. 150 Realm string 151 152 // IdentityKey defines the key used for storing identity info in jwt claim 153 IdentityKey string 154 155 // Secret key used for signing. Required. 156 SigningSecretKey string 157 158 // HS256, HS384, HS512, RS256, RS384 or RS512 Optional, default is HS256. 159 SigningAlgorithm ginjwtsignalgorithm.GinJwtSignAlgorithm 160 161 // Private key file for asymmetric algorithms 162 PrivateKeyFile string 163 164 // Public key file for asymmetric algorithms 165 PublicKeyFile string 166 167 // Duration that a jwt token is valid. Optional, defaults to one hour. (aka Timeout) 168 TokenValidDuration time.Duration 169 170 // This field allows clients to refresh their token until MaxRefresh has passed. 171 // Note that clients can refresh their token in the last moment of MaxRefresh. 172 // This means that the maximum validity timespan for a token is TokenTime + MaxRefresh. 173 // Optional, defaults to 0 meaning not refreshable. 174 TokenMaxRefreshDuration time.Duration 175 176 // SendAuthorization allow return authorization header for every request 177 SendAuthorization bool 178 179 // Disable abort() of context. 180 DisableAbort bool 181 182 // TokenLookup is a string in the form of "<source>:<name>" that is used to extract token from the request. 183 // Optional. Default value "header:Authorization". 184 // Possible values: 185 // - "header:<name>" 186 // - "query:<name>" 187 // - "cookie:<name>" 188 // - "param:<name>" 189 // TokenLookup: "header: Authorization, query: token, cookie: jwt", 190 // TokenLookup: "query:token", 191 // TokenLookup: "cookie:token", 192 TokenLookup string 193 194 // TokenHeadName is a string in the header. Default value is "Bearer" 195 // "Bearer" 196 TokenHeadName string 197 198 // ----------------------------------------------------------------------------------------------------------------- 199 // cookie setup 200 // ----------------------------------------------------------------------------------------------------------------- 201 SendCookie bool 202 CookieMaxAge time.Duration 203 SecureCookie *bool 204 CookieHTTPOnly *bool 205 CookieDomain string 206 CookieName string 207 CookieSameSite *http.SameSite 208 209 // ----------------------------------------------------------------------------------------------------------------- 210 // authentication setup 211 // ----------------------------------------------------------------------------------------------------------------- 212 213 // AuthenticateBindingType defines the binding type to use for login form field data 214 AuthenticateBindingType ginbindtype.GinBindType 215 216 // LoginRequestDataPtr contains pointer object that represents login request (used for binding), if not set, default = &UserLogin helper struct 217 LoginRequestDataPtr interface{} 218 219 // LoginRoutePath defines the relative path to the middleware's built-in LoginHandler, 220 // this route path is setup as POST with the gin engine 221 LoginRoutePath string 222 223 // LogoutRoutePath defines the relative path to the middleware's built-in LogoutHandler, 224 // this route path is setup as POST with the gin engine 225 LogoutRoutePath string 226 227 // RefreshTokenRoutePath defines the relative path to the middleware's built-in RefreshHandler, 228 // this route path is setup as GET with the gin engine 229 RefreshTokenRoutePath string 230 231 // AuthenticateHandler func is called by Authenticator, 232 // receives loginRequestDataPtr for authentication use, 233 // if authentication succeeds, returns the loggedInCredentialPtr object 234 // (which typically is a user object containing user information logged in) 235 AuthenticateHandler func(loginRequestDataPtr interface{}) (loggedInCredentialPtr interface{}) 236 237 // AddClaimsHandler func is called during Authenticator action upon success, 238 // so that this handler when coded can insert jwt additional payload data 239 // 240 // loggedInCredentialPtr = the returning loggedInCredentialPtr from LoginHandler 241 // identityKeyValue = string value for the named identityKey defined within the struct 242 AddClaimsHandler func(loggedInCredentialPtr interface{}) (identityKeyValue string, claims map[string]interface{}) 243 244 // GetIdentityHandler func is called when IdentityHandler is triggered, 245 // field values from claims will be parsed and returned via object by the implementation code 246 GetIdentityHandler func(claims map[string]interface{}) interface{} 247 248 // Callback function to handle custom login response 249 LoginResponseHandler func(c *gin.Context, statusCode int, token string, expires time.Time) 250 251 // Callback function to handle custom logout response 252 LogoutResponseHandler func(c *gin.Context, statusCode int) 253 254 // Callback function to handle custom token refresh response 255 RefreshTokenResponseHandler func(c *gin.Context, statusCode int, token string, expires time.Time) 256 257 // ----------------------------------------------------------------------------------------------------------------- 258 // authorization setup 259 // ----------------------------------------------------------------------------------------------------------------- 260 261 // AuthorizerHandler func is called during authorization after authentication, 262 // to validate if the current credential has access rights to certain parts of the target site, 263 // the loggedInCredentialPtr is the object that LoginHandler returns upon successful authentication, 264 // return value of true indicates authorization success, 265 // return value of false indicates authorization failure 266 AuthorizerHandler func(loggedInCredentialPtr interface{}, c *gin.Context) bool 267 268 // UnauthorizedHandler func is called when the authorization is not authorized, 269 // this handler will return the unauthorized message content to caller, 270 // such as via c.JSON, c.HTML, etc as dictated by the handler implementation process 271 // 272 // c *gin.Context = context used to return the unauthorized access content 273 // code / message = unauthorized code and message as given by the web server to respond back to the caller 274 UnauthorizedHandler func(c *gin.Context, code int, message string) 275 276 // ----------------------------------------------------------------------------------------------------------------- 277 // other handlers 278 // ----------------------------------------------------------------------------------------------------------------- 279 280 // TimeFunc provides the current time. 281 // override it to use another time value. 282 // useful for testing or if server uses a different time zone than the tokens. 283 TimeHandler func() time.Time 284 285 // NoRouteHandler is called when no route situation is encountered 286 NoRouteHandler func(claims map[string]interface{}, c *gin.Context) 287 288 // HTTP Status messages for when something in the JWT middleware fails. 289 // Check error (e) to determine the appropriate error message. 290 MiddlewareErrorEvaluator func(e error, c *gin.Context) string 291 292 // ----------------------------------------------------------------------------------------------------------------- 293 // local var 294 // ----------------------------------------------------------------------------------------------------------------- 295 _ginJwtMiddleware *jwt.GinJWTMiddleware 296 } 297 298 // BuildGinJwtMiddleware sets up auth jwt middleware for gin web server, 299 // including adding login, logout, refreshtoken, and other routes where applicable 300 func (j *GinJwt) BuildGinJwtMiddleware(g *Gin) error { 301 j._ginJwtMiddleware = nil 302 303 if g == nil { 304 return fmt.Errorf("Gin Wrapper Object is Required") 305 } 306 307 if g._ginEngine == nil { 308 return fmt.Errorf("Gin Engine is Required") 309 } 310 311 if !j.AuthenticateBindingType.Valid() { 312 return fmt.Errorf("Authenticate Binding Type is Required") 313 } 314 315 if j.AuthenticateHandler == nil { 316 return fmt.Errorf("Authenticate Handler is Required") 317 } 318 319 if j.TokenValidDuration == 0 { 320 j.TokenValidDuration = 15 * time.Minute 321 } 322 323 if j.TokenMaxRefreshDuration == 0 { 324 j.TokenMaxRefreshDuration = 24 * time.Hour 325 } 326 327 if j.LoginRequestDataPtr == nil { 328 j.LoginRequestDataPtr = &UserLogin{} 329 } 330 331 // the jwt middleware 332 authMiddleware, err := jwt.New(&jwt.GinJWTMiddleware{ 333 Realm: j.Realm, 334 IdentityKey: j.IdentityKey, 335 Key: []byte(j.SigningSecretKey), 336 SigningAlgorithm: j.SigningAlgorithm.Key(), 337 PrivKeyFile: j.PrivateKeyFile, 338 PubKeyFile: j.PublicKeyFile, 339 Timeout: j.TokenValidDuration, 340 MaxRefresh: j.TokenMaxRefreshDuration, 341 SendAuthorization: j.SendAuthorization, 342 DisabledAbort: j.DisableAbort, 343 TokenLookup: j.TokenLookup, 344 TokenHeadName: j.TokenHeadName, 345 346 // TimeFunc provides the current time. 347 // override it to use another time value. 348 // useful for testing or if server uses a different time zone than the tokens. 349 TimeFunc: time.Now, 350 351 // Callback function that should perform the authentication of the user based on login info. 352 // Must return user data as user identifier, 353 // it will be stored in Claim Array. Required. 354 // Check error (e) to determine the appropriate error message. 355 Authenticator: func(c *gin.Context) (interface{}, error) { 356 if j.AuthenticateHandler == nil { 357 return nil, jwt.ErrMissingAuthenticatorFunc 358 } 359 360 // loginFields struct represents the login form fields serialized from context input 361 var loginRequestData interface{} 362 loginRequestData = j.LoginRequestDataPtr 363 364 if err := g.bindInput(c, j.AuthenticateBindingType, loginRequestData); err != nil { 365 return nil, fmt.Errorf(jwt.ErrMissingLoginValues.Error() + ": " + err.Error()) 366 } 367 368 if loggedInCredential := j.AuthenticateHandler(loginRequestData); loggedInCredential != nil { 369 return loggedInCredential, nil 370 } else { 371 return nil, jwt.ErrFailedAuthentication 372 } 373 }, 374 375 // Callback function that should perform the authorization of the authenticated user. 376 // Called only after an authentication success. 377 // Must return true on success, false on failure. 378 // Optional, default to success. 379 Authorizator: func(data interface{}, c *gin.Context) bool { 380 if j.AuthorizerHandler != nil { 381 return j.AuthorizerHandler(data, c) 382 } else { 383 return true 384 } 385 }, 386 387 // UnauthorizedHandler func is called when the authorization is not authorized, 388 // this handler will return the unauthorized message content to caller, 389 // such as via c.JSON, c.HTML, etc as dictated by the handler implementation process 390 // 391 // c *gin.Context = context used to return the unauthorized access content 392 // code / message = unauthorized code and message as given by the web server to respond back to the caller 393 Unauthorized: func(c *gin.Context, code int, message string) { 394 if j.UnauthorizedHandler != nil { 395 j.UnauthorizedHandler(c, code, message) 396 } else { 397 c.JSON(code, gin.H{ 398 "code": code, 399 "message": message, 400 }) 401 } 402 }, 403 }) 404 405 if err != nil { 406 return fmt.Errorf("Setup Gin Jwt Middleware Failed: %s", err.Error()) 407 } 408 409 if j.AddClaimsHandler != nil { 410 // Callback function that will be called during login. 411 // Using this function it is possible to add additional payload data to the web token. 412 // The data is then made available during requests via c.Get("JWT_PAYLOAD"). 413 // Note that the payload is not encrypted. 414 // The attributes mentioned on jwt.io can't be used as keys for the map. 415 // Optional, by default no additional data will be set 416 // 417 // reserved claims: do not use 418 // iss = issuer of the jwt 419 // sub = subject of the jwt (the user) 420 // aud = audience / recipient for which the jwt is intended 421 // exp = expiration time after which the jwt expires 422 // nbf = not before time which the jwt must not be accepted for processing 423 // iat = issued at time which the jwt was issued, can be used to determine the age of the jwt 424 // jti = jwt id, the unique identifier, used to prevent jwt from being replayed (allows a token to be used only once) 425 // more jwt reserved tokens, see = https://www.iana.org/assignments/jwt/jwt.xhtml#claims 426 // 427 // notes: 428 // 1) data interface{} = this object represents the Authenticator return object (loggedInCredential interface{}) 429 // 2) internal code can assert the loggedInCredential to the actual struct to retrieve its field values 430 // such as: v, ok := data.(*User) 431 authMiddleware.PayloadFunc = func(data interface{}) jwt.MapClaims { 432 if j.AddClaimsHandler != nil && data != nil { 433 if identVal, customMap := j.AddClaimsHandler(data); util.LenTrim(identVal) > 0 || customMap != nil { 434 if customMap == nil { 435 return jwt.MapClaims{ 436 j.IdentityKey: identVal, 437 } 438 } else { 439 if util.LenTrim(identVal) > 0 { 440 customMap[j.IdentityKey] = identVal 441 } 442 443 return customMap 444 } 445 } else { 446 return nil 447 } 448 } else { 449 return nil 450 } 451 } 452 } 453 454 // Callback function to retrieve the identity info via gin context's jwt claims by identityKey 455 if j.GetIdentityHandler != nil { 456 authMiddleware.IdentityHandler = func(context *gin.Context) interface{} { 457 if j.GetIdentityHandler == nil { 458 return nil 459 } 460 461 claims := jwt.ExtractClaims(context) 462 463 if claims != nil { 464 return j.GetIdentityHandler(claims) 465 } else { 466 return nil 467 } 468 } 469 } 470 471 // Callback function to handle custom login response, 472 // i = status code 473 // s = token 474 // t = expires 475 if j.LoginResponseHandler != nil { 476 authMiddleware.LoginResponse = func(context *gin.Context, i int, s string, t time.Time) { 477 j.LoginResponseHandler(context, i, s, t) 478 } 479 } 480 481 // Callback function to handle custom logout response, 482 // i = status code 483 if j.LogoutResponseHandler != nil { 484 authMiddleware.LogoutResponse = func(context *gin.Context, i int) { 485 j.LogoutResponseHandler(context, i) 486 } 487 } 488 489 // Callback function to handle custom token refresh response, 490 // i = status code, 491 // s = token 492 // t = expires 493 if j.RefreshTokenResponseHandler != nil { 494 authMiddleware.RefreshResponse = func(context *gin.Context, i int, s string, t time.Time) { 495 j.RefreshTokenResponseHandler(context, i, s, t) 496 } 497 } 498 499 // TimeFunc provides the current time. 500 // override it to use another time value. 501 // useful for testing or if server uses a different time zone than the tokens. 502 if j.TimeHandler != nil { 503 authMiddleware.TimeFunc = func() time.Time { 504 return j.TimeHandler() 505 } 506 } 507 508 // HTTP Status messages for when something in the JWT middleware fails, 509 // Check error (e) to determine the appropriate error message 510 if j.MiddlewareErrorEvaluator != nil { 511 authMiddleware.HTTPStatusMessageFunc = func(e error, c *gin.Context) string { 512 return j.MiddlewareErrorEvaluator(e, c) 513 } 514 } 515 516 // setup cookie options if applicable 517 authMiddleware.SendCookie = j.SendCookie 518 authMiddleware.CookieMaxAge = j.TokenValidDuration 519 520 if j.SecureCookie == nil { 521 authMiddleware.SecureCookie = true 522 } else { 523 authMiddleware.SecureCookie = *j.SecureCookie 524 } 525 526 if j.CookieHTTPOnly == nil { 527 authMiddleware.CookieHTTPOnly = true 528 } else { 529 authMiddleware.CookieHTTPOnly = *j.CookieHTTPOnly 530 } 531 532 authMiddleware.CookieDomain = j.CookieDomain 533 authMiddleware.CookieName = j.CookieName 534 535 if j.CookieSameSite == nil { 536 authMiddleware.CookieSameSite = http.SameSiteDefaultMode 537 } else { 538 authMiddleware.CookieSameSite = *j.CookieSameSite 539 } 540 541 // now init middleware to set default values if required var not set during setup 542 if errInit := authMiddleware.MiddlewareInit(); errInit != nil { 543 return fmt.Errorf("Init Gin Jwt Middleware Failed: %s", errInit.Error()) 544 } 545 546 // setup login route for LoginHandler 547 if util.LenTrim(j.LoginRoutePath) > 0 { 548 log.Println("Jwt Auth Login Set: (Custom) " + j.LoginRoutePath) 549 g._ginEngine.POST(j.LoginRoutePath, authMiddleware.LoginHandler) 550 } else { 551 log.Println("Jwt Auth Login Set: (Default) " + "/login") 552 g._ginEngine.POST("/login", authMiddleware.LoginHandler) 553 } 554 555 // setup logout route for LogoutHandler 556 if util.LenTrim(j.LogoutRoutePath) > 0 { 557 log.Println("Jwt Auth Logout Set: (Custom) " + j.LogoutRoutePath) 558 g._ginEngine.POST(j.LogoutRoutePath, authMiddleware.LogoutHandler) 559 } else { 560 log.Println("Jwt Auth Logout Set: (Default) " + "/logout") 561 g._ginEngine.POST("/logout", authMiddleware.LogoutHandler) 562 } 563 564 // setup refresh token route for RefreshHandler 565 if util.LenTrim(j.RefreshTokenRoutePath) > 0 { 566 log.Println("Jwt Token Refresh Set: (Custom) " + j.RefreshTokenRoutePath) 567 g._ginEngine.GET(j.RefreshTokenRoutePath, authMiddleware.RefreshHandler) 568 } else { 569 log.Println("Jwt Token Refresh Set: (Default) " + "/refreshtoken") 570 g._ginEngine.GET("/refreshtoken", authMiddleware.RefreshHandler) 571 } 572 573 // setup no route handler 574 if j.NoRouteHandler != nil { 575 g._ginEngine.NoRoute(authMiddleware.MiddlewareFunc(), func(context *gin.Context) { 576 claims := jwt.ExtractClaims(context) 577 j.NoRouteHandler(claims, context) 578 }) 579 } 580 581 // setup middleware successful 582 j._ginJwtMiddleware = authMiddleware 583 return nil 584 } 585 586 // AuthMiddleware returns the GinJwt Middleware HandlerFunc, 587 // so that it can perform jwt related auth services, 588 // for all route path defined within the same router group 589 // 590 // For example: 591 // 592 // ginJwt := <Gin Jwt Struct Object Obtained> 593 // authGroup := g.Group("/auth") 594 // authGroup.Use(ginJwt.AuthMiddleware()) 595 // authGroup.GET("/hello", ...) // route path within this auth group now secured by AuthMiddleware 596 func (j *GinJwt) AuthMiddleware() gin.HandlerFunc { 597 if j._ginJwtMiddleware != nil { 598 return j._ginJwtMiddleware.MiddlewareFunc() 599 } else { 600 return nil 601 } 602 } 603 604 // ExtractClaims extracts jwt claims from context and return via map 605 func (j *GinJwt) ExtractClaims(c *gin.Context) map[string]interface{} { 606 return jwt.ExtractClaims(c) 607 } 608 609 // ===================================================================================================================== 610 // Identity Helper Structs 611 // ===================================================================================================================== 612 613 // UserLogin is a helper struct for use in authentication, 614 // this struct represents a common use case for user based login request data, 615 // however, any other custom struct can be used instead as desired 616 type UserLogin struct { 617 Username string `form:"username" json:"username" binding:"required"` 618 Password string `form:"password" json:"password" binding:"required"` 619 } 620 621 // SystemLogin is a helper struct for use in authentication, 622 // this struct represents a common use case for system based login request data, 623 // however, any other custom struct can be used instead as desired 624 type SystemLogin struct { 625 AccessID string `form:"accessid" json:"accessid" binding:"required"` 626 SecretKey string `form:"secretkey" json:"secretkey" binding:"required"` 627 } 628 629 // UserInfo is a helper struct for use in authentication, authorization and identity, 630 // this struct represents a common use case for user based identity info, 631 // however, any other custom struct can be used instead as desired 632 type UserInfo struct { 633 UserName string 634 FirstName string 635 LastName string 636 Scopes []string 637 } 638 639 // SystemInfo is a helper struct for use in authentication, authorization, and identity, 640 // this struct represents a common use case for system based identity info, 641 // however, any other custom struct can be used instead as desired 642 type SystemInfo struct { 643 SystemName string 644 Scopes []string 645 } 646 647 /* 648 Example: 649 650 func helloHandler(c *gin.Context) { 651 claims := jwt.ExtractClaims(c) 652 user, _ := c.Get(identityKey) 653 654 c.JSON(200, gin.H{ 655 "userID": claims[identityKey], 656 "userName": user.(*User).UserName, 657 "text": "Hello World", 658 }) 659 } 660 */