Implement authorization middleware
Change WriteJson function to use only for successful response Implement WriteError function
Showing
3 changed files
with
50 additions
and
12 deletions
| ... | @@ -10,6 +10,12 @@ import ( | ... | @@ -10,6 +10,12 @@ import ( |
| 10 | "github.com/jmoiron/sqlx" | 10 | "github.com/jmoiron/sqlx" |
| 11 | ) | 11 | ) |
| 12 | 12 | ||
| 13 | +type Prop int | ||
| 14 | + | ||
| 15 | +const ( | ||
| 16 | + PropUserNo Prop = iota | ||
| 17 | +) | ||
| 18 | + | ||
| 13 | type App struct { | 19 | type App struct { |
| 14 | Config Config | 20 | Config Config |
| 15 | db *sqlx.DB | 21 | db *sqlx.DB | ... | ... |
| 1 | package main | 1 | package main |
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | + "context" | ||
| 4 | "encoding/json" | 5 | "encoding/json" |
| 5 | "net/http" | 6 | "net/http" |
| 7 | + "strings" | ||
| 6 | "time" | 8 | "time" |
| 7 | 9 | ||
| 8 | "github.com/dgrijalva/jwt-go" | 10 | "github.com/dgrijalva/jwt-go" |
| ... | @@ -22,7 +24,7 @@ func (app *App) PostUsers(w http.ResponseWriter, r *http.Request) { | ... | @@ -22,7 +24,7 @@ func (app *App) PostUsers(w http.ResponseWriter, r *http.Request) { |
| 22 | body := make(map[string]interface{}) | 24 | body := make(map[string]interface{}) |
| 23 | err := json.NewDecoder(r.Body).Decode(&body) | 25 | err := json.NewDecoder(r.Body).Decode(&body) |
| 24 | if err != nil { | 26 | if err != nil { |
| 25 | - WriteJson(w, http.StatusBadRequest, map[string]interface{}{"msg": "Failed to parse request json"}) | 27 | + WriteError(w, http.StatusBadRequest, "Failed to parse request json") |
| 26 | return | 28 | return |
| 27 | } | 29 | } |
| 28 | 30 | ||
| ... | @@ -32,48 +34,73 @@ func (app *App) PostUsers(w http.ResponseWriter, r *http.Request) { | ... | @@ -32,48 +34,73 @@ func (app *App) PostUsers(w http.ResponseWriter, r *http.Request) { |
| 32 | if err != nil { | 34 | if err != nil { |
| 33 | if merr, ok := err.(*mysql.MySQLError); ok { | 35 | if merr, ok := err.(*mysql.MySQLError); ok { |
| 34 | if merr.Number == 1062 { | 36 | if merr.Number == 1062 { |
| 35 | - WriteJson(w, http.StatusConflict, map[string]interface{}{"msg": "Already registered"}) | 37 | + WriteError(w, http.StatusConflict, "Already registered") |
| 36 | return | 38 | return |
| 37 | } | 39 | } |
| 38 | } | 40 | } |
| 39 | 41 | ||
| 40 | - WriteJson(w, http.StatusInternalServerError, map[string]interface{}{"msg": "Failed to register"}) | 42 | + WriteError(w, http.StatusInternalServerError, "Failed to register") |
| 41 | return | 43 | return |
| 42 | } | 44 | } |
| 43 | 45 | ||
| 44 | no, _ := res.LastInsertId() | 46 | no, _ := res.LastInsertId() |
| 45 | - WriteJson(w, http.StatusOK, map[string]interface{}{"user_no": no}) | 47 | + WriteJson(w, map[string]interface{}{"user_no": no}) |
| 48 | +} | ||
| 49 | + | ||
| 50 | +type AuthClaims struct { | ||
| 51 | + UserNo uint64 `json:"user_no"` | ||
| 52 | + jwt.StandardClaims | ||
| 46 | } | 53 | } |
| 47 | 54 | ||
| 48 | func (app *App) PostTokens(w http.ResponseWriter, r *http.Request) { | 55 | func (app *App) PostTokens(w http.ResponseWriter, r *http.Request) { |
| 49 | body := make(map[string]interface{}) | 56 | body := make(map[string]interface{}) |
| 50 | err := json.NewDecoder(r.Body).Decode(&body) | 57 | err := json.NewDecoder(r.Body).Decode(&body) |
| 51 | if err != nil { | 58 | if err != nil { |
| 52 | - WriteJson(w, http.StatusBadRequest, map[string]interface{}{"msg": "Failed to parse request json"}) | 59 | + WriteError(w, http.StatusBadRequest, "Failed to parse request json") |
| 53 | return | 60 | return |
| 54 | } | 61 | } |
| 55 | 62 | ||
| 56 | hash := sha3.Sum256([]byte(body["password"].(string))) | 63 | hash := sha3.Sum256([]byte(body["password"].(string))) |
| 57 | rows, err := app.db.Query("SELECT `no` FROM users WHERE `id`=? AND `password`=?", body["id"], hash[:]) | 64 | rows, err := app.db.Query("SELECT `no` FROM users WHERE `id`=? AND `password`=?", body["id"], hash[:]) |
| 58 | if err != nil { | 65 | if err != nil { |
| 59 | - WriteJson(w, http.StatusInternalServerError, map[string]interface{}{"msg": "Failed to register"}) | 66 | + WriteError(w, http.StatusInternalServerError, "Failed to register") |
| 60 | return | 67 | return |
| 61 | } | 68 | } |
| 62 | 69 | ||
| 63 | if !rows.Next() { | 70 | if !rows.Next() { |
| 64 | - WriteJson(w, http.StatusUnauthorized, map[string]interface{}{"msg": "Login failed"}) | 71 | + WriteError(w, http.StatusUnauthorized, "Login failed") |
| 65 | return | 72 | return |
| 66 | } | 73 | } |
| 67 | 74 | ||
| 68 | no := uint64(0) | 75 | no := uint64(0) |
| 69 | rows.Scan(&no) | 76 | rows.Scan(&no) |
| 70 | 77 | ||
| 71 | - token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{"no": no}) | 78 | + token := jwt.NewWithClaims(jwt.SigningMethodHS256, AuthClaims{UserNo: no}) |
| 72 | auth, err := token.SignedString([]byte(app.Config.TokenSecret)) | 79 | auth, err := token.SignedString([]byte(app.Config.TokenSecret)) |
| 73 | if err != nil { | 80 | if err != nil { |
| 74 | - WriteJson(w, http.StatusInternalServerError, map[string]interface{}{"msg": "Login failed"}) | 81 | + WriteError(w, http.StatusInternalServerError, "Login failed") |
| 75 | return | 82 | return |
| 76 | } | 83 | } |
| 77 | 84 | ||
| 78 | - WriteJson(w, http.StatusOK, map[string]interface{}{"token": auth}) | 85 | + WriteJson(w, map[string]interface{}{"token": auth}) |
| 86 | +} | ||
| 87 | + | ||
| 88 | +func (app *App) WithAuth(next func(http.ResponseWriter, *http.Request)) http.Handler { | ||
| 89 | + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
| 90 | + auth := r.Header.Get("Authorization") | ||
| 91 | + if len(auth) > 6 && strings.Index(auth, "Bearer ") == 0 { | ||
| 92 | + token, err := jwt.ParseWithClaims(auth[7:], &AuthClaims{}, func(token *jwt.Token) (interface{}, error) { | ||
| 93 | + return []byte(app.Config.TokenSecret), nil | ||
| 94 | + }) | ||
| 95 | + | ||
| 96 | + if err == nil { | ||
| 97 | + claims := token.Claims.(*AuthClaims) | ||
| 98 | + ctx := context.WithValue(r.Context(), PropUserNo, claims.UserNo) | ||
| 99 | + next(w, r.WithContext(ctx)) | ||
| 100 | + return | ||
| 101 | + } | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + WriteError(w, http.StatusUnauthorized, "Authorization failed") | ||
| 105 | + }) | ||
| 79 | } | 106 | } | ... | ... |
| ... | @@ -5,8 +5,13 @@ import ( | ... | @@ -5,8 +5,13 @@ import ( |
| 5 | "net/http" | 5 | "net/http" |
| 6 | ) | 6 | ) |
| 7 | 7 | ||
| 8 | -func WriteJson(w http.ResponseWriter, status int, data interface{}) { | 8 | +func WriteJson(w http.ResponseWriter, data interface{}) { |
| 9 | w.Header().Set("Content-Type", "application/json") | 9 | w.Header().Set("Content-Type", "application/json") |
| 10 | - w.WriteHeader(status) | ||
| 11 | json.NewEncoder(w).Encode(data) | 10 | json.NewEncoder(w).Encode(data) |
| 12 | } | 11 | } |
| 12 | + | ||
| 13 | +func WriteError(w http.ResponseWriter, status int, message string) { | ||
| 14 | + w.Header().Set("Content-Type", "application/json") | ||
| 15 | + w.WriteHeader(status) | ||
| 16 | + json.NewEncoder(w).Encode(map[string]interface{}{"msg": message}) | ||
| 17 | +} | ... | ... |
-
Please register or login to post a comment