auth.go (3048B)
1 package main 2 3 import ( 4 "errors" 5 "log" 6 "net/http" 7 "time" 8 9 "github.com/gin-gonic/gin" 10 jwt "github.com/appleboy/gin-jwt/v2" 11 12 "jacobedwards.org/spaceplanner.app/internal/backend" 13 ) 14 15 var ( 16 identityKey = "id" 17 ) 18 19 func AuthMiddleware(authMiddleware *jwt.GinJWTMiddleware) gin.HandlerFunc { 20 return func(context *gin.Context) { 21 errInit := authMiddleware.MiddlewareInit() 22 if errInit != nil { 23 log.Fatal("authMiddleware.MiddlewareInit() Error:" + errInit.Error()) 24 } 25 } 26 } 27 28 func (e *Env) AuthParams(key []byte) (*jwt.GinJWTMiddleware, error) { 29 if key == nil || len(key) == 0 { 30 return nil, errors.New("Invalid key") 31 } 32 return &jwt.GinJWTMiddleware{ 33 // TODO: Don't know what Realm is, but should probably be changed 34 Realm: "test zone", 35 Key: key, 36 Timeout: time.Hour * 24 * 7, 37 MaxRefresh: time.Hour * 24, 38 IdentityKey: identityKey, 39 PayloadFunc: payloadFunc(), 40 41 IdentityHandler: identityHandler(), 42 Authenticator: e.authenticator(), 43 Authorizator: authorizator(), 44 Unauthorized: unauthorized(), 45 TokenLookup: "header: Authorization, query: token, cookie: jwt", 46 // TokenLookup: "query:token", 47 // TokenLookup: "cookie:token", 48 TokenHeadName: "Bearer", 49 TimeFunc: time.Now, 50 }, nil 51 } 52 53 func payloadFunc() func(data interface{}) jwt.MapClaims { 54 return func(data interface{}) jwt.MapClaims { 55 if v, ok := data.(backend.User); ok { 56 return jwt.MapClaims{ 57 identityKey: v.Name, 58 } 59 } 60 return jwt.MapClaims{} 61 } 62 } 63 64 func identityHandler() func(c *gin.Context) interface{} { 65 return func(c *gin.Context) interface{} { 66 claims := jwt.ExtractClaims(c) 67 return &backend.User{ 68 Name: claims[identityKey].(string), 69 } 70 } 71 } 72 73 func (e *Env) authenticator() func(c *gin.Context) (interface{}, error) { 74 return func(c *gin.Context) (interface{}, error) { 75 var creds Credentials 76 if err := c.ShouldBind(&creds); err != nil { 77 return "", jwt.ErrMissingLoginValues 78 } 79 80 user, err := e.backend.LoginUser(creds.Username, creds.Password) 81 if err != nil { 82 return nil, err 83 } 84 return user, nil 85 } 86 } 87 88 func authorizator() func(data interface{}, c *gin.Context) bool { 89 // Is authenticated user allowed to do X? 90 return func(data interface{}, c *gin.Context) bool { 91 owner := c.Param("user") 92 v, ok := data.(*backend.User) 93 if !ok { 94 log.Panic("Expected *backend.User") 95 } 96 97 if v.Name == owner { 98 return true 99 } 100 log.Printf("User %q unauthorized to access resource owned by %q", v.Name, owner) 101 return false 102 } 103 } 104 105 func unauthorized() func(c *gin.Context, code int, message string) { 106 return func(c *gin.Context, code int, message string) { 107 RespondError(c, code, "Unauthorized: %s", message); 108 } 109 } 110 111 func handleNoRoute() func(c *gin.Context) { 112 return func(c *gin.Context) { 113 claims := jwt.ExtractClaims(c) 114 log.Printf("NoRoute claims: %#v\n", claims) 115 RespondError(c, http.StatusNotFound, "Endpoint not found") 116 } 117 } 118 119 func testHandler(c *gin.Context) { 120 claims := jwt.ExtractClaims(c) 121 user, _ := c.Get(identityKey) 122 c.JSON(200, gin.H{ 123 "ID": claims[identityKey], 124 "Username": user, 125 "text": "Test.", 126 }) 127 }