Heim >Backend-Entwicklung >Golang >Golang Websocket (Gorilla) mit Cookie-Authentifizierung
In der Webentwicklung ist die Authentifizierung ein wesentliches Merkmal, und die Cookie-basierte Authentifizierung ist eine gängige Methode. Als effiziente und prägnante Programmiersprache verfügt Golang über leistungsstarke Webentwicklungsfunktionen. In diesem Artikel erfahren Sie, wie Sie mit dem Gorilla-Toolkit die Websocket-Funktion mit Cookie-Authentifizierung in Golang implementieren und so Ihre Anwendung sicherer und zuverlässiger machen. Egal, ob Sie ein Golang-Anfänger oder ein erfahrener Entwickler sind, dieser Artikel kann Ihnen den schnellen Einstieg erleichtern. Lass uns einen Blick darauf werfen!
Ich versuche, mit Gorilla Websocket ein Diagramm zu starten. Die Authentifizierungs-Middleware funktioniert über Cookies und JWT-Tokens. Alle meine Endpunkte über http funktionieren, Websocket jedoch nicht. Nachdem ich viele Themen wie Gorilla WebSocket mit Cookie-Authentifizierung gelesen hatte, stellte ich fest, dass meine Cookies leer waren und der Kontext in der WebSocket-Verbindung ebenfalls leer war. Ich verstehe nicht warum? Kann jemand erklären, warum? p.s.: Ich habe versucht, das Upgrade von diesem Handler zu entfernen, und das Cookie und der Kontext kamen erfolgreich durch, aber nach dem Upgrade der Verbindung auf das Websocket-Protokoll schlug es fehl. Das ist meine Datei: Endpunkt:
func (r *router) routes(engine *gin.engine) { engine.use(r.handler.verifyuser()) engine.post("/signup", r.handler.createuser) engine.post("/signin", r.handler.loginuser) engine.get("/welcome", r.handler.welcome) engine.get("/logout", r.handler.logout) engine.post("/ws/createroom", r.wshandler.createroom) engine.get("/ws/joinroom/:roomid", r.wshandler.joinroom) }
ws_handler
func (h *handler) joinroom(c *gin.context) { claims := c.request.context().value("jwt").(models.claims) //couldn't find value with "jwt" key fmt.println(claims.id, claims.name) cookie, err := c.cookie("chartjwt") // allways err no cookie if err != nil { fmt.printf("no cookie, error:%v\n", err) } fmt.printf("cookie: %+v\n", cookie) conn, err := upgrader.upgrade(c.writer, c.request, nil) if err != nil { c.json(http.statusbadrequest, gin.h{"error": err.error()}) return }
Middleware:
func (h *handler) verifyuser() gin.handlerfunc { return func(c *gin.context) { notauth := []string{"/signup", "/signin"} requestpath := c.request.url.path for _, val := range notauth { if val == requestpath { c.next() return } } token, err := c.cookie("chartjwt") if err != nil { c.redirect(http.statuspermanentredirect, signinpage) } claims, ok := validatetoken(token) if !ok { c.json(http.statusbadrequest, gin.h{"error": errors.new("invalid token")}) return } c.request = c.request.withcontext(context.withvalue(c.request.context(), "jwt", *claims)) c.next() } }
Alle anderen Endpunkte funktionieren. Wenn Sie anderen Code benötigen, lassen Sie es mich bitte wissen. Ich möchte mein Problem nicht komplizierter machen, weil ich dachte, es sei einfach, aber ich habe etwas falsch verstanden ( Vielen Dank für Ihre Hilfe und Ihren Rat.
ps.s.: Wenn ich die Middleware ausschalte, funktioniert alles wie erwartet.
Update: Validierungs- und Generierungsfunktionen hinzugefügt
func validatetoken(jwttoken string) (*models.claims, bool) { claims := &models.claims{} token, err := jwt.parsewithclaims(jwttoken, claims, func(token *jwt.token) (interface{}, error) { return []byte(config.secretkey), nil }) if err != nil { return claims, false } if !token.valid { return claims, false } return claims, true } func (h *handler) generatetokenstringforuser(id, name string) (string, error) { // create the jwt claims, which includes the username and expiry time claims := models.claims{ id: id, name: name, registeredclaims: jwt.registeredclaims{ issuer: id, expiresat: jwt.newnumericdate(time.now().add(24 * time.hour)), }, } token := jwt.newwithclaims(jwt.signingmethodhs256, claims) tokenstring, err := token.signedstring([]byte(config.secretkey)) return tokenstring, err }
Anmeldefunktion hinzugefügt, bei der ich Cookies mit JWT-String hinzugefügt habe
func (h *handler) LoginUser(c *gin.Context) { var input models.LoginUserReq if err := c.ShouldBindJSON(&input); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } res, err := h.Service.LoginUser(context.Background(), &input) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } token, err := h.generateTokenStringForUser(res.ID, res.Name) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } c.SetCookie("chartJWT", token, 60*60*24, "/", "localhost", false, true) c.JSON(http.StatusOK, gin.H{"user": res}) }
Update nach Hilfe: Das Problem bestand darin, dass ich in meiner Postman-Setup-Anfrage das Cookie nicht richtig angegeben habe.
Lassen Sie mich versuchen, Ihnen bei der Lösung des Problems zu helfen. Zunächst habe ich Ihr Beispiel etwas vereinfacht, um mich nur auf die relevanten Teile zu konzentrieren. Wenn Sie etwas auslassen müssen, lassen Sie es mich bitte wissen und ich werde die Antwort aktualisieren. Lassen Sie mich zunächst mit der lokalen auth
包中进行的 jwt
Token-Generierung/-Validierung beginnen.
auth/auth.go
Dateienpackage auth import ( "fmt" "strings" "time" "github.com/golang-jwt/jwt" ) func validatetoken(jwttoken string) (*jwt.mapclaims, error) { // parse the token token, err := jwt.parse(strings.replace(jwttoken, "bearer ", "", 1), func(token *jwt.token) (interface{}, error) { _, ok := token.method.(*jwt.signingmethodhmac) if !ok { return nil, fmt.errorf("unexpected signing method: %v", token.header["alg"]) } return []byte("abcd1234!!"), nil }) // err while parsing the token if err != nil { return nil, err } // token valid var claims jwt.mapclaims var ok bool if claims, ok = token.claims.(jwt.mapclaims); ok && token.valid { return &claims, nil } return nil, fmt.errorf("token not valid") } func generatetoken(username, password string) (string, error) { // todo: here you can add logic to check against a db //... // create a new token by providing the cryptographic algorithm token := jwt.new(jwt.signingmethodhs256) // set default/custom claims claims := token.claims.(jwt.mapclaims) claims["exp"] = time.now().add(24 * time.hour * 3).unix() claims["username"] = username claims["password"] = password tokenstring, err := token.signedstring([]byte("abcd1234!!")) if err != nil { return "", err } return tokenstring, nil }
Jetzt kommen wir zum Middleware-Teil.
middlewares/middlewares.go
Dateienpackage middlewares import ( "net/http" "websocketauth/auth" "github.com/gin-gonic/gin" ) func verifyuser() gin.handlerfunc { return func(c *gin.context) { notauth := []string{"/signin"} requestpath := c.request.url.path for _, val := range notauth { if val == requestpath { c.next() return } } token, err := c.cookie("chartjwt") if err != nil { c.redirect(http.statuspermanentredirect, "/signin") } claims, err := auth.validatetoken(token) if err != nil { c.json(http.statusbadrequest, gin.h{"error": err.error()}) return } c.set("jwt", *claims) c.next() } }
Um etwas im Kontext hochladen zu können, sollten Sie die c.set(key, value)
-Methode verwenden. Kommen wir nun zu den Handlern.
handlers/handlers.go
Dateienpackage handlers import ( "fmt" "net/http" "websocketauth/auth" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt" "github.com/gorilla/websocket" ) var upgrader websocket.upgrader type loginuserreq struct { username string `json:"username" binding:"required"` password string `json:"password" binding:"required"` } func loginuser(c *gin.context) { var input loginuserreq if err := c.shouldbind(&input); err != nil { c.json(http.statusbadrequest, gin.h{"error": err.error()}) return } // i don't know what you do within the handler.service.loginuser() method token, err := auth.generatetoken(input.username, input.password) if err != nil { c.json(http.statusbadrequest, gin.h{"error": err.error()}) return } c.setcookie("chartjwt", token, 60*60*24, "/", "localhost", false, true) c.json(http.statusok, gin.h{"user": token}) } func joinroom(c *gin.context) { claims := c.mustget("jwt").(jwt.mapclaims) fmt.println("username", claims["username"]) fmt.println("password", claims["password"]) ws, err := upgrader.upgrade(c.writer, c.request, nil) if err != nil { panic(err) } charttoken, err := c.cookie("chartjwt") if err != nil { panic(err) } fmt.println("charttoken", charttoken) _ = ws }
Fehlende Teile wie handler.service.loginuser()
方法。要正确地从上下文中读取内容,您必须使用 c.mustget(key)
Methoden werden übersprungen, da ich nicht weiß, was sie tun.
main.go
Dateienpackage main import ( "websocketauth/handlers" "websocketauth/middlewares" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" ) func main() { handlers.Upgrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, } gin.SetMode(gin.DebugMode) r := gin.Default() r.Use(middlewares.VerifyUser()) r.GET("/join-room", handlers.JoinRoom) r.POST("/signin", handlers.LoginUser) r.Run(":8000") }
Dies ist die Setup-Logik. Hier gibt es nichts Erwähnenswertes.
Wenn Sie weitere Hilfe benötigen, lassen Sie es mich bitte wissen, vielen Dank!
Das obige ist der detaillierte Inhalt vonGolang Websocket (Gorilla) mit Cookie-Authentifizierung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!