##困っていること
GoでJWT認証の実装を試しているが、JWTを返却する際(w.Write([]byte(tokenString)))にエラー(invalid memory address or nil pointer dereference)が発生してしまう。
*[]byte(tokenString))自体は値が入っていること確認済み(下記に詳細提示しております)
理想は、w.Write([]byte(tokenString))実行時のエラーを解消しJWTをローカルストレージに保管したい。
##利用技術
サーバーサイド
Go
webフレームワーク:gin
フロントサイド
Vue(VueCLI)
##試していること
JWT認証を追加するクラス
Go
1package auth 2 3import ( 4 "fmt" 5 "net/http" 6 "os" 7 "time" 8 9 jwtmiddleware "github.com/auth0/go-jwt-middleware" 10 jwt "github.com/dgrijalva/jwt-go" 11 "github.com/joho/godotenv" 12) 13 14// GetTokenHandler get token 15var GetTokenHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 16 17 // headerのセット 18 token := jwt.New(jwt.SigningMethodHS256) 19 // claimsのセット 20 claims := token.Claims.(jwt.MapClaims) 21 claims["sub"] = "54546557354" 22 claims["name"] = "taro" 23 claims["iat"] = time.Now() 24 claims["exp"] = time.Now().Add(time.Hour * 24).Unix() 25 26 err := godotenv.Load("../.env") 27 if err != nil { 28 fmt.Println(err) 29 } 30 // 電子署名 31 tokenString, _ := token.SignedString([]byte(os.Getenv("SIGNINGKEY"))) 32 fmt.Println(tokenString) 33 fmt.Println([]byte(tokenString)) 34 // JWTを返却 35 w.Write([]byte(tokenString)) //ここでエラーが発生する 36})
JWT認証を追加するメソッド実行時のコンソール
Go
1 2fmt.Println(tokenString)の内容 3eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MDEzNTcwMDYsImlhdCI6IjIwMjAtMDktMjhUMTQ6MjM6MjYuMjgyMDcxKzA5OjAwIiwibmFtZSI6InRhcm8iLCJzdWIiOiI1NDU0NjU1NzM1NCJ9.cfl04EpZsN00cvtKw7QO2RNU8rSyqKPBiMRwT9M5Hjo 4 5fmt.Println([]byte(tokenString))の内容 6[101 121 74 104 98 71 99 105 79 105 74 73 85 122 73 49 78 105 73 115 73 110 82 53 99 67 73 54 73 107 112 88 86 67 74 57 46 101 121 74 108 101 72 65 105 79 106 69 50 77 68 69 122 78 84 85 49 78 122 73 115 73 109 108 104 100 67 73 54 73 106 73 119 77 106 65 116 77 68 107 116 77 106 104 85 77 84 77 54 78 84 107 54 77 122 73 117 77 84 73 121 78 106 69 51 75 122 65 53 79 106 65 119 73 105 119 105 98 109 70 116 90 83 73 54 73 110 82 104 99 109 56 105 76 67 74 122 100 87 73 105 79 105 73 49 78 68 85 48 78 106 85 49 78 122 77 49 78 67 74 57 46 65 74 104 54 56 90 99 86 81 102 122 77 107 118 77 79 77 84 74 74 97 49 97 55 101 85 113 106 52 57 65 104 65 75 88 78 76 111 67 108 56 48 111] 7 8以下エラーメッセージ(w.Write([]byte(tokenString))発動時) 9Failed to continue - runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation] 10Unable to propogate EXC_BAD_ACCESS signal to target process and panic (see https://github.com/go-delve/delve/issues/852) 11Last known immediate stacktrace (goroutine id 20): 12 /Users/go/src/sharechoco-go/auth/auth.go:37 13 goapp/auth.glob..func1 14 /Users/go/src/sharechoco-go/controller/login_controller.go:47 15 goapp/controller.LoginController.PostLogin 16 /Users/go/src/sharechoco-go/controller/login_controller.go:23 17 goapp/controller.LoginController.PostLogin-fm 18 /Users/go/pkg/mod/github.com/gin-gonic/gin@v1.5.0/context.go:147 19 github.com/gin-gonic/gin.(*Context).Next 20 /Users/go/pkg/mod/github.com/gin-contrib/sessions@v0.0.3/sessions.go:52 21 github.com/gin-contrib/sessions.Sessions.func1 22 /Users/go/pkg/mod/github.com/gin-gonic/gin@v1.5.0/context.go:147 23 github.com/gin-gonic/gin.(*Context).Next 24 /Users/go/pkg/mod/github.com/gin-gonic/gin@v1.5.0/recovery.go:83 25 github.com/gin-gonic/gin.RecoveryWithWriter.func1 26 /Users/go/pkg/mod/github.com/gin-gonic/gin@v1.5.0/context.go:147 27 github.com/gin-gonic/gin.(*Context).Next 28 /Users/go/pkg/mod/github.com/gin-gonic/gin@v1.5.0/logger.go:241 29 github.com/gin-gonic/gin.LoggerWithConfig.func1 30 /Users/go/pkg/mod/github.com/gin-gonic/gin@v1.5.0/context.go:147 31 github.com/gin-gonic/gin.(*Context).Next 32 /Users/go/pkg/mod/github.com/gin-gonic/gin@v1.5.0/gin.go:403 33 github.com/gin-gonic/gin.(*Engine).handleHTTPRequest 34 /Users/go/pkg/mod/github.com/gin-gonic/gin@v1.5.0/gin.go:364 35 github.com/gin-gonic/gin.(*Engine).ServeHTTP 36 /usr/local/Cellar/go/1.14[...]
JWT認証を追加するメソッドを呼び出すクラス
Go
1package controller 2 3import ( 4 "fmt" 5 6 "goapp/models" 7 "goapp/service" 8 "log" 9 10 "github.com/gin-gonic/gin" 11 "golang.org/x/crypto/bcrypt" 12) 13 14// LoginController is Login controlller 15type LoginController struct{} 16 17// User is Login controlller 18type User models.User 19 20//PostLogin ログイン処理を行う 21func (lg LoginController) PostLogin(c *gin.Context) { 22 var posteduser User 23 var s service.UserService 24 if err := c.BindJSON(&posteduser); err != nil { 25 log.Println(err) 26 } 27 28 user, err := s.GetByMailAddress(posteduser.MailAddress) 29 30 passCheckErr := passwordVerify(user.Password, posteduser.Password) 31 if passCheckErr != nil { 32 fmt.Println("パスワードが一致しません") 33 34 log.Println(err) 35 } 36 37 if err != nil { 38 c.AbortWithStatus(404) 39 fmt.Println(err) 40 fmt.Println("アドレスの登録がありません。") 41 } else if user.UserID != 0 { 42 log.Println("ログイン処理") 43 var w http.ResponseWriter 44 var r *http.Request 45 auth.GetTokenHandler(w, r)//ここでJWT認証を追加するメソッドを呼び出す 46 fmt.Println("ログイン成功") 47 } 48 49} 50 51func passwordVerify(hash, pw string) error { 52 return bcrypt.CompareHashAndPassword([]byte(hash), []byte(pw)) 53} 54
##参考にしているサイト
https://qiita.com/po3rin/items/740445d21487dfcb5d9f
##追加の質問(上記エラーの解消法となるハンドラのチェインでメソッドを呼ぶ方法について)
上記ケースのauth.GetTokenHandlerをハンドラのチェイン内で呼ぼうとしたが、上手くいかず、
まずはよりシンプルなケースで以下のコードを試してみたが、404エラーが発生してしまいました。
rout := mux.NewRouter()の利用方法が誤っているのかと思いますが、どこがエラーの原因になっているかが分からず、お手数ですがよろしくお願い申し上げます。
Go
1func Init() { 2r := router() 3 4r.Run(":3000") 5rout := mux.NewRouter() 6rout.HandleFunc("/", rootPage) →このパスをターミナルで叩くと404エラーになってしまう 7} 8 9func rootPage(w http.ResponseWriter, r *http.Request) { 10fmt.Fprintf(w, "Welcome to the Go Api Server") 11fmt.Println("Root endpoint is hooked!") 12}
コンソール画面
Go
1[GIN-debug] Listening and serving HTTP on :3000 2[GIN] 2020/09/29 - 14:44:18 | 404 | 14.537µs | ::1 | GET /
ターミナルで叩いたコマンド
curl http://localhost:3000/
参考にしたサイト
https://qiita.com/stranger1989/items/7d95778d26d34fd1ddef
https://github.com/gorilla/mux
当初の質問の解決策
auth.GetTokenHandlerのメソッドをハンドラチェインの中で呼び出すことで解決
JWT認証を追加するメソッドを呼び出すクラス
Go
1package controller 2 3import ( 4 "fmt" 5 6 "goapp/models" 7 "goapp/service" 8 "log" 9 10 "github.com/gin-gonic/gin" 11 "golang.org/x/crypto/bcrypt" 12) 13 14// LoginController is Login controlller 15type LoginController struct{} 16 17// User is Login controlller 18type User models.User 19 20//PostLogin ログイン処理を行う 21func (lg LoginController) PostLogin(c *gin.Context) { 22 var posteduser User 23 var s service.UserService 24 if err := c.BindJSON(&posteduser); err != nil { 25 log.Println(err) 26 } 27 28 user, err := s.GetByMailAddress(posteduser.MailAddress) 29 30 passCheckErr := passwordVerify(user.Password, posteduser.Password) 31 if passCheckErr != nil { 32 fmt.Println("パスワードが一致しません") 33 34 log.Println(err) 35 } 36 37 if err != nil { 38 c.AbortWithStatus(404) 39 fmt.Println(err) 40 fmt.Println("アドレスの登録がありません。") 41 } else if user.UserID != 0 { 42 log.Println("ログイン処理") 43 // var w http.ResponseWriter 44 // var r *http.Request 45 // →http.ResponseWriter *http.Request は初期化しない 46 auth.GetTokenHandler(c) → tokenをgetするメソッドを呼ぶ 47 fmt.Println("ログイン成功") 48 } 49 50} 51 52func passwordVerify(hash, pw string) error { 53 return bcrypt.CompareHashAndPassword([]byte(hash), []byte(pw)) 54} 55
追加質問の解決策
tokenをgetするメソッド(authクラス)http.HandlerFuncの引数を
func(w http.ResponseWriter, r *http.Request){ → func(c *gin.Context) {
に変更することで解決
*webフレームワークGinを利用していたためw http.ResponseWriter, r *http.Requestの代わりにc *gin.Contextを利用
Go
1package auth 2 3import ( 4 "fmt" 5 "net/http" 6 "os" 7 "time" 8 9 jwtmiddleware "github.com/auth0/go-jwt-middleware" 10 jwt "github.com/dgrijalva/jwt-go" 11 "github.com/joho/godotenv" 12) 13 14//var GetTokenHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 15//→var GetTokenHandler = func(c *gin.Context) {に変更することで解決 16 17// GetTokenHandler get token 18var GetTokenHandler = func(c *gin.Context) { 19 // headerのセット 20 token := jwt.New(jwt.SigningMethodHS256) 21 // claimsのセット 22 claims := token.Claims.(jwt.MapClaims) 23 claims["sub"] = "54546557354" 24 claims["name"] = "taro" 25 claims["iat"] = time.Now() 26 claims["exp"] = time.Now().Add(time.Hour * 24).Unix() 27 28 err := godotenv.Load("../.env") 29 if err != nil { 30 fmt.Println(err) 31 } 32 // 電子署名 33 tokenString, _ := token.SignedString([]byte(os.Getenv("SIGNINGKEY"))) 34 fmt.Println(tokenString) 35 fmt.Println([]byte(tokenString)) 36 // JWTを返却 37 w.Write([]byte(tokenString)) //ここでエラーが発生する 38 } 39}
tokenをgetするメソッドを呼ぶメソッド
Go
1//PostLogin ログイン処理を行う 2func (lg LoginController) PostLogin(c *gin.Context) { 3 var posteduser User 4 var s service.UserService 5 if err := c.BindJSON(&posteduser); err != nil { 6 log.Println(err) 7 } 8 9 user, err := s.GetByMailAddress(posteduser.MailAddress) 10 11 passCheckErr := passwordVerify(user.Password, posteduser.Password) 12 if passCheckErr != nil { 13 fmt.Println("パスワードが一致しません") 14 15 log.Println(err) 16 } 17 18 if err != nil { 19 c.AbortWithStatus(404) 20 fmt.Println(err) 21 fmt.Println("アドレスの登録がありません。") 22 } else if user.UserID != 0 { 23 log.Println("ログイン処理") 24 auth.GetTokenHandler(c) → tokenをgetするメソッドを呼ぶ 25 fmt.Println("ログイン成功") 26 } 27 28}
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。