質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

JWT(JSON Web Token)

JWT(JSON Web Token)とは、JSONをベースとしたアクセストークンの仕様。電子署名付きのURL safeなJSONのことを指します。電子署名が付いているため、改ざんをチェックできる点がメリットです。

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

Q&A

解決済

2回答

1915閲覧

JWT認証追加(ログイン時の認証処理) Go Gin Vue

kingcat

総合スコア11

Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

JWT(JSON Web Token)

JWT(JSON Web Token)とは、JSONをベースとしたアクセストークンの仕様。電子署名付きのURL safeなJSONのことを指します。電子署名が付いているため、改ざんをチェックできる点がメリットです。

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

0グッド

0クリップ

投稿2020/09/28 05:32

編集2020/10/02 08:10

##困っていること
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}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

当初の質問の解決策

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}

投稿2020/10/02 08:13

kingcat

総合スコア11

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

var w http.ResponseWriter var r *http.Request

こうしてnil初期化された値をハンドラにそのまま渡してしまっています。
ハンドラ側はこれらがnilではないことを期待しています。
これらの実体はhttp.Serverが内部で作ったものしか使えません(ユーザーが勝手にインスタンスを作ることはできません)。
つまり、ハンドラのチェインの中でしかauth.GetTokenHandlerを呼ぶことはできません。

投稿2020/09/28 07:35

nobonobo

総合スコア3367

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kingcat

2020/09/29 06:01 編集

回答いただき大変ありがとうございます。 昨日回答いただいたことを元に修正を行なっておりますが基本的な部分で上手くいかず、申し訳ございませんが追加で質問させていただきたくよろしくお願い申し上げます。 ハンドラのチェインの中でメソッドを呼ぶことに躓いており、 まずはシンプルなパターンとして、以下のような形式でコードを実装しましたが、 404エラーが発生してしまいました。 基本的なこととなってしまいますが、ハンドラのチェインでメソッドを呼ぶ方法はどのように行えばよろしいでしょうか? ---goのコード--- ・mainクラス func main() { //データベースを接続する db.Init() server.Init() db.Close() } ・serverクラス func Init() { r := router() r.Run(":3000") rout := mux.NewRouter() rout.HandleFunc("/", rootPage) →このパスをターミナルで叩くと404エラーになってしまう } func rootPage(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Welcome to the Go Api Server") fmt.Println("Root endpoint is hooked!") } ---goのコード終了--- ターミナルで叩いたコマンド curl http://localhost:3000/ コンソール [GIN-debug] Listening and serving HTTP on :3000 [GIN] 2020/09/29 - 14:44:18 | 404 | 14.537µs | ::1 | GET / 参考にしたサイト https://qiita.com/stranger1989/items/7d95778d26d34fd1ddef https://github.com/gorilla/mux
nobonobo

2020/09/29 06:11

聞きたい内容が完全に表題と異なる課題に置き換わっています。 まずはrootPageの表示に相当する部分だけのコードに整理して質問し直すか質問に追記しましょう。 (コメント欄の長いコードはすいませんが読みにくいです)
kingcat

2020/09/29 06:42

ご指摘いただきましてありがとうございます。 質問事項に内容を追記いたしました。(rootPageの表示に相当する部分以外は削除いたしました) また何か不手際がございましたらご指摘いただけると幸いです。
nobonobo

2020/09/29 07:17

可能であれば実際に起動できるコードにして欲しい。 Init関数のなかのrouterが何者かがわかりません。
nobonobo

2020/09/30 21:39

ハンドラチェインの呼びどころを教えたいが、404エラーが直らないと進まないので頑張りましょう。
kingcat

2020/10/02 08:12

回答が遅くなり大変申し訳ございません。 結論から申し上げますと、無事JWTの取得はできました。(解決方法を追記しております)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問