Line data Source code
1 : package middlewares 2 : 3 : import ( 4 : "encoding/json" 5 : "fmt" 6 : "io" 7 : "net/http" 8 : "strings" 9 : 10 : "github.com/gin-gonic/gin" 11 : 12 : "github.com/woofdogtw/sylvia-iot-go/sdk/constants" 13 : ) 14 : 15 : // The information contains `GetTokenInfoData` and access token. 16 : type FullTokenInfo struct { 17 : Token string 18 : Info GetTokenInfoData 19 : } 20 : 21 : // The user/client information of the token. 22 : type GetTokenInfo struct { 23 : Data GetTokenInfoData `json:"data"` 24 : } 25 : 26 : // User/client information of the token. 27 : type GetTokenInfoData struct { 28 : UserID string `json:"userId"` 29 : Account string `json:"account"` 30 : Roles map[string]bool `json:"roles"` 31 : Name string `json:"name"` 32 : ClientID string `json:"clientId"` 33 : Scopes []string `json:"scopes"` 34 : } 35 : 36 : // Constants. 37 : const ( 38 : TokenInfoKey = "FullTokenInfo" 39 : ) 40 : 41 : // Generate the Gin authentication middleware. 42 4 : func AuthMiddleware(authUri string) func(*gin.Context) { 43 11 : return func(c *gin.Context) { 44 7 : token := c.GetHeader("Authorization") 45 7 : token = strings.TrimSpace(token) 46 11 : if len(token) < 8 || strings.ToLower(token[:7]) != "bearer " { 47 4 : c.JSON(http.StatusBadRequest, gin.H{ 48 4 : "code": constants.ErrParam.String(), 49 4 : "message": "not bearer token", 50 4 : }) 51 4 : return 52 4 : } 53 : 54 3 : req, err := http.NewRequest(http.MethodGet, authUri, nil) 55 3 : if err != nil { 56 0 : c.JSON(http.StatusServiceUnavailable, gin.H{ 57 0 : "code": constants.ErrRsc.String(), 58 0 : "message": err.Error(), 59 0 : }) 60 0 : return 61 0 : } 62 3 : req.Header.Set("Authorization", "Bearer "+token[7:]) 63 3 : client := http.Client{} 64 3 : res, err := client.Do(req) 65 4 : if err != nil { 66 1 : c.JSON(http.StatusServiceUnavailable, gin.H{ 67 1 : "code": constants.ErrRsc.String(), 68 1 : "message": err.Error(), 69 1 : }) 70 1 : return 71 1 : } 72 2 : defer res.Body.Close() 73 2 : body, err := io.ReadAll(res.Body) 74 2 : if err != nil { 75 0 : c.JSON(http.StatusServiceUnavailable, gin.H{ 76 0 : "code": constants.ErrRsc.String(), 77 0 : "message": err.Error(), 78 0 : }) 79 0 : return 80 0 : } 81 3 : if res.StatusCode == http.StatusUnauthorized { 82 1 : c.JSON(http.StatusUnauthorized, gin.H{"code": constants.ErrAuth.String()}) 83 1 : return 84 2 : } else if res.StatusCode != http.StatusOK { 85 0 : c.JSON(http.StatusServiceUnavailable, gin.H{ 86 0 : "code": constants.ErrIntMsg.String(), 87 0 : "message": fmt.Sprintf("auth error with status code %d", res.StatusCode), 88 0 : }) 89 0 : return 90 0 : } 91 1 : var tokenInfo GetTokenInfo 92 1 : err = json.Unmarshal(body, &tokenInfo) 93 1 : if err != nil { 94 0 : c.JSON(http.StatusServiceUnavailable, gin.H{ 95 0 : "code": constants.ErrIntMsg.String(), 96 0 : "message": err.Error(), 97 0 : }) 98 0 : return 99 0 : } 100 1 : c.Set(TokenInfoKey, &FullTokenInfo{ 101 1 : Token: token[7:], 102 1 : Info: tokenInfo.Data, 103 1 : }) 104 1 : c.Next() 105 : } 106 : }