web-dev-qa-db-fra.com

Go et JWT - Authentification simple

Je suis en train de créer une API (avec go) et je travaille sur la partie session . Après des recherches sur les éléments à utiliser pour la session, j'ai trouvé JWT vraiment intéressant.

Cependant, je ne suis pas vraiment sûr de comprendre comment l'utiliser après quelques tutoriels ... C'est donc mon idée:

func main() {

    router := mux.NewRouter().StrictSlash(true)

    router.HandleFunc("/login", login)
    router.HandleFunc("/logout", logout)
    router.HandleFunc("/register", register)

    http.ListenAndServe(":8080", router)

 }

Une fois ces demandes traitées, je crée les différentes fonctions.

func login(w http.ResponseWriter, r *http.Request) {
    /*                                                                                                                                                                                                   
    Here I just have to search in my database (SQL, I know how to do it). If the user is registered, I create a token and give it to him, but how can I do it?                                           
    */
 }

 func logout(w http.ResponseWriter, r *http.Request) {
    /*                                                                                                                                                                                                   
    I get a token and stop/delete it?                                                                                                                                                                    
    */
 }

 func register(w http.ResponseWriter, r *http.Request) {
    /*                                                                                                                                                                                                   
    I search if the user isn't register and then, if it isn't, I create a user in the database (I know how to do it). I connect him but again, how to make a new token?                                  
    */
 }

Beaucoup de tutoriels sur le web semblent très difficiles, mais je veux juste quelque chose de simple. Je veux juste qu'un package de descripteurs (code ci-dessus) qui fonctionne avec un package de services ait quelque chose comme une authentification par jeton de moteur.

Un deuxième point que je ne suis pas sûr de comprendre, c’est l’économie du jeton ... Si un utilisateur se connecte, quel serait le mieux? Chaque fois que l'utilisateur exécute son application, l'application se connecte elle-même et obtient un nouveau jeton à partir d'informations enregistrées (utilisateur/mot de passe) ou l'application sauvegarde-t-elle le jeton pour toujours? Et que dire du serveur, le jeton est-il géré et enregistré automatiquement avec JWT ou dois-je le mettre dans ma base de données SQL?

Merci pour votre aide!

EDIT 1

Je vous remercie ! Donc, après avoir lu votre réponse, j'ai encapsulé mon code (token.go) comme ça

package services

import (
    "fmt"
    "github.com/dgrijalva/jwt-go"
    "time"
    "../models"
)

var tokenEncodeString string = "something"

func createToken(user models.User) (string, error) {
    // create the token                                                                                                                                                                                  
    token := jwt.New(jwt.SigningMethodHS256)

    // set some claims                                                                                                                                                                                   
    token.Claims["username"] = user.Username;
    token.Claims["password"] = user.Password;
    token.Claims["exp"] = time.Now().Add(time.Hour * 72).Unix()

    //Sign and get the complete encoded token as string                                                                                                                                                  
    return (token.SignedString(tokenEncodeString))
}

func parseToken(unparsedToken string) (bool, string) {
    token, err := jwt.Parse(unparsedToken, func(token *jwt.Token) (interface{}, error) {
            // Don't forget to validate the alg is what you expect:                                                                                                                                      
            if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
                    return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
            }
            return myLookupKey(token.Header["kid"]), nil
    })

    if err == nil && token.Valid {
            return true, unparsedToken
    } else {
            return false, ""
    }
 }

Cependant, j'ai eu l'erreur suivante: "token.go: undefined: myLookupKey" J'ai regardé sur Internet et j'ai trouvé une fonction encapsulée qui possède ce prototype:

func ExampleParse(myToken string, myLookupKey func(interface{}) (interface{}, error)) {
 /* same code in my func parseToken() */
}

Alors, quelle est la différence entre ma fonction et celle-ci? Comment puis-je utiliser celui-ci?

Merci !

17
Emixam23

Pour commencer, vous devez importer une bibliothèque JWT à Golang (allez à github.com/dgrijalva/jwt-go). Vous pouvez trouver la documentation de cette bibliothèque dans le lien ci-dessous.

https://github.com/dgrijalva/jwt-go

Tout d'abord, vous devez créer un jeton

// Create the token
token := jwt.New(jwt.SigningMethodHS256)
// Set some claims
token.Claims["foo"] = "bar"
token.Claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
// Sign and get the complete encoded token as a string
tokenString, err := token.SignedString(mySigningKey)

Deuxièmement, analyser ce jeton

token, err := jwt.Parse(myToken, func(token *jwt.Token) (interface{}, error) {
    // Don't forget to validate the alg is what you expect:
    if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
        return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
    }
    return myLookupKey(token.Header["kid"]), nil
})

if err == nil && token.Valid {
    deliverGoodness("!")
} else {
    deliverUtterRejection(":(")
}

En outre, il existe quelques exemples d'utilisation de JWT dans GOlang comme ceci https://github.com/slok/go-jwt-example

EDIT-1

package main

import (
    "fmt"
    "time"

    "github.com/dgrijalva/jwt-go"
)

const (
    mySigningKey = "WOW,MuchShibe,ToDogge"
)

func main() {
    createdToken, err := ExampleNew([]byte(mySigningKey))
    if err != nil {
        fmt.Println("Creating token failed")
    }
    ExampleParse(createdToken, mySigningKey)
}

func ExampleNew(mySigningKey []byte) (string, error) {
    // Create the token
    token := jwt.New(jwt.SigningMethodHS256)
    // Set some claims
    token.Claims["foo"] = "bar"
    token.Claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
    // Sign and get the complete encoded token as a string
    tokenString, err := token.SignedString(mySigningKey)
    return tokenString, err
}

func ExampleParse(myToken string, myKey string) {
    token, err := jwt.Parse(myToken, func(token *jwt.Token) (interface{}, error) {
        return []byte(myKey), nil
    })

    if err == nil && token.Valid {
        fmt.Println("Your token is valid.  I like your style.")
    } else {
        fmt.Println("This token is terrible!  I cannot accept this.")
    }
}
22
Massoud Afrashteh

Juste pour faire la mise à jour de la réponse @ massoud-afrashteh . Dans la version 3 de

// Set some claims claims := make(jwt.MapClaims) claims["foo"] = "bar" claims["exp"] = time.Now().Add(time.Hour * 72).Unix() token.Claims = claims

5
Paval

N'oubliez pas d'exécuter la commande go get github.com/dgrijalva/jwt-go.

Une autre façon de créer plus simple:

token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
   "foo": "bar",
   "nbf": time.Date(2015, 10, 10, 12, 0, 0, 0, time.UTC).Unix(),
})
tokenString, err := token.SignedString([]byte("your key"))
fmt.Println(tokenString, err)
4
icaksama
func GenerateToken(mySigningKey []byte, username string) (string, error) {
    // Create the token
    token := jwt.New(jwt.SigningMethodRS512)
    claims := make(jwt.MapClaims)
    claims[collections.PARAM_USER_NAME] = username
    claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
    token.Claims = claims
    return token.SignedString(mySigningKey)
}
1
Black_Dreams