Ma Suhyeon

Implement authorization middleware

Change WriteJson function to use only for successful response
Implement WriteError function
...@@ -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 +}
......