去和JWT – 简单身份验证

huangapple go评论116阅读模式
英文:

Go and JWT - Simple authentication

问题

我目前正在制作一个API(使用Go语言),并且正在处理会话部分。
在研究了关于会话使用的内容后,我发现JWT非常有趣。

然而,通过一些教程后,我并不确定如何使用它。
所以这是我的想法:

  1. func main() {
  2. router := mux.NewRouter().StrictSlash(true)
  3. router.HandleFunc("/login", login)
  4. router.HandleFunc("/logout", logout)
  5. router.HandleFunc("/register", register)
  6. http.ListenAndServe(":8080", router)
  7. }

在处理这些请求之后,我创建了不同的函数。

  1. func login(w http.ResponseWriter, r *http.Request) {
  2. /*
  3. 在这里,我只需要在我的数据库中搜索(使用SQL,我知道如何做)。如果用户已注册,我会创建一个令牌并将其提供给他,但是我该如何做呢?
  4. */
  5. }
  6. func logout(w http.ResponseWriter, r *http.Request) {
  7. /*
  8. 我获取一个令牌并停止/删除它?
  9. */
  10. }
  11. func register(w http.ResponseWriter, r *http.Request) {
  12. /*
  13. 我搜索用户是否已注册,然后如果没有注册,我在数据库中创建一个用户(我知道如何做)。我连接他,但是如何生成一个新的令牌呢?
  14. */
  15. }

网络上的许多教程似乎非常复杂,但我只想要简单的东西。我只想要一个处理包(上面的代码),它与服务包一起工作,以实现类似于引擎令牌认证的功能。

我还不确定的第二个问题是令牌的保存。
如果用户连接自己,那么什么是最好的方式?每次用户运行他们的应用程序时,应用程序都会连接并从保存的信息(用户/密码)获取一个新的令牌,还是应用程序永久保存令牌?服务器如何处理,令牌是否由JWT自动管理和保存,还是我需要将其放入我的SQL数据库中?

谢谢你的帮助!

编辑1

谢谢!所以在阅读了你的回答后,我将我的代码(token.go)封装如下:

  1. package services
  2. import (
  3. "fmt"
  4. "github.com/dgrijalva/jwt-go"
  5. "time"
  6. "../models"
  7. )
  8. var tokenEncodeString string = "something"
  9. func createToken(user models.User) (string, error) {
  10. // 创建令牌
  11. token := jwt.New(jwt.SigningMethodHS256)
  12. // 设置一些声明
  13. token.Claims["username"] = user.Username;
  14. token.Claims["password"] = user.Password;
  15. token.Claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
  16. // 签名并将完整的编码令牌作为字符串返回
  17. return (token.SignedString(tokenEncodeString))
  18. }
  19. func parseToken(unparsedToken string) (bool, string) {
  20. token, err := jwt.Parse(unparsedToken, func(token *jwt.Token) (interface{}, error) {
  21. // 不要忘记验证算法是否符合预期:
  22. if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
  23. return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
  24. }
  25. return myLookupKey(token.Header["kid"]), nil
  26. })
  27. if err == nil && token.Valid {
  28. return true, unparsedToken
  29. } else {
  30. return false, ""
  31. }
  32. }

然而,我遇到了以下错误:"token.go: undefined: myLookupKey"。
我在互联网上搜索并找到了一个封装的函数,它具有以下原型:

  1. func ExampleParse(myToken string, myLookupKey func(interface{}) (interface{}, error)) {
  2. /* 与我的func parseToken()中的代码相同 */
  3. }

那么我的函数和这个函数有什么区别?我该如何使用这个函数?

谢谢!

英文:

I'm currently making an API (with go) and I'm working on the session part.
After research about what to use for session, I found JWT really interesting.

However I'm not really sure to understand how to use it after some tutorials.
So this is my idea:

  1. func main() {
  2. router := mux.NewRouter().StrictSlash(true)
  3. router.HandleFunc("/login", login)
  4. router.HandleFunc("/logout", logout)
  5. router.HandleFunc("/register", register)
  6. http.ListenAndServe(":8080", router)
  7. }

After those requests handled, I create the differents functions.

  1. func login(w http.ResponseWriter, r *http.Request) {
  2. /*
  3. 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?
  4. */
  5. }
  6. func logout(w http.ResponseWriter, r *http.Request) {
  7. /*
  8. I get a token and stop/delete it?
  9. */
  10. }
  11. func register(w http.ResponseWriter, r *http.Request) {
  12. /*
  13. 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?
  14. */
  15. }

Lot of tutorials on the web seems really hard but I just want something simple. I just want an handle package (code above) which work with a service package to have something like an engine token authentication.

A second point I'm not sure to understand is the saving of the token.
If a user connects himself, then what would be best? Each time the user runs their app, the app connects itself and get a new token from saved information (user/password) or the app just save the token forever? And what about the server, is the token managed and saved automatically with JWT or do I have to put it in my sql database?

Thank for your help !

EDIT 1

Thank you ! So after I read your answer, I encapsulated my code (token.go) like it

  1. package services
  2. import (
  3. "fmt"
  4. "github.com/dgrijalva/jwt-go"
  5. "time"
  6. "../models"
  7. )
  8. var tokenEncodeString string = "something"
  9. func createToken(user models.User) (string, error) {
  10. // create the token
  11. token := jwt.New(jwt.SigningMethodHS256)
  12. // set some claims
  13. token.Claims["username"] = user.Username;
  14. token.Claims["password"] = user.Password;
  15. token.Claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
  16. //Sign and get the complete encoded token as string
  17. return (token.SignedString(tokenEncodeString))
  18. }
  19. func parseToken(unparsedToken string) (bool, string) {
  20. token, err := jwt.Parse(unparsedToken, func(token *jwt.Token) (interface{}, error) {
  21. // Don't forget to validate the alg is what you expect:
  22. if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
  23. return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
  24. }
  25. return myLookupKey(token.Header["kid"]), nil
  26. })
  27. if err == nil && token.Valid {
  28. return true, unparsedToken
  29. } else {
  30. return false, ""
  31. }
  32. }

However, I got the following error: "token.go: undefined: myLookupKey"
I looked on internet and I found an encapsulated function which have this prototype:

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

So what are the difference between my function and this one? How can I use this one?

Thanks !

答案1

得分: 31

注意:
这个包 github.com/dgrijalva/jwt-go 已经被弃用,请使用 github.com/golang-jwt/jwt 替代。

首先,你需要在 Golang 中导入一个 JWT 库(go get github.com/dgrijalva/jwt-go)。你可以在下面的链接中找到该库的文档。

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

首先,你需要创建一个令牌

  1. // 创建令牌
  2. token := jwt.New(jwt.SigningMethodHS256)
  3. // 设置一些声明
  4. token.Claims["foo"] = "bar"
  5. token.Claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
  6. // 签名并将完整的编码令牌作为字符串返回
  7. tokenString, err := token.SignedString(mySigningKey)

其次,解析该令牌

  1. token, err := jwt.Parse(myToken, func(token *jwt.Token) (interface{}, error) {
  2. // 不要忘记验证 alg 是否符合预期:
  3. if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
  4. return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
  5. }
  6. return myLookupKey(token.Header["kid"]), nil
  7. })
  8. if err == nil && token.Valid {
  9. deliverGoodness("!")
  10. } else {
  11. deliverUtterRejection(":(")
  12. }

此外,还有一些在 Golang 中使用 JWT 的示例,例如 https://github.com/slok/go-jwt-example

编辑-1

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. "github.com/dgrijalva/jwt-go"
  6. )
  7. const (
  8. mySigningKey = "WOW,MuchShibe,ToDogge"
  9. )
  10. func main() {
  11. createdToken, err := ExampleNew([]byte(mySigningKey))
  12. if err != nil {
  13. fmt.Println("创建令牌失败")
  14. }
  15. ExampleParse(createdToken, mySigningKey)
  16. }
  17. func ExampleNew(mySigningKey []byte) (string, error) {
  18. // 创建令牌
  19. token := jwt.New(jwt.SigningMethodHS256)
  20. // 设置一些声明
  21. token.Claims["foo"] = "bar"
  22. token.Claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
  23. // 签名并将完整的编码令牌作为字符串返回
  24. tokenString, err := token.SignedString(mySigningKey)
  25. return tokenString, err
  26. }
  27. func ExampleParse(myToken string, myKey string) {
  28. token, err := jwt.Parse(myToken, func(token *jwt.Token) (interface{}, error) {
  29. return []byte(myKey), nil
  30. })
  31. if err == nil && token.Valid {
  32. fmt.Println("你的令牌有效。我喜欢你的风格。")
  33. } else {
  34. fmt.Println("这个令牌太糟糕了!我不能接受这个。")
  35. }
  36. }
英文:

Note:
This package github.com/dgrijalva/jwt-go is deprecated use this instead github.com/golang-jwt/jwt

To start, you need to import a JWT library in Golang (go get github.com/dgrijalva/jwt-go). You can find that library documentation in below link.

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

Firstly, you need to create a token

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

Secondly, parse that token

  1. token, err := jwt.Parse(myToken, func(token *jwt.Token) (interface{}, error) {
  2. // Don't forget to validate the alg is what you expect:
  3. if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
  4. return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
  5. }
  6. return myLookupKey(token.Header["kid"]), nil
  7. })
  8. if err == nil && token.Valid {
  9. deliverGoodness("!")
  10. } else {
  11. deliverUtterRejection(":(")
  12. }

Also, there are some examples for use JWT in GOlang like this https://github.com/slok/go-jwt-example

EDIT-1

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. "github.com/dgrijalva/jwt-go"
  6. )
  7. const (
  8. mySigningKey = "WOW,MuchShibe,ToDogge"
  9. )
  10. func main() {
  11. createdToken, err := ExampleNew([]byte(mySigningKey))
  12. if err != nil {
  13. fmt.Println("Creating token failed")
  14. }
  15. ExampleParse(createdToken, mySigningKey)
  16. }
  17. func ExampleNew(mySigningKey []byte) (string, error) {
  18. // Create the token
  19. token := jwt.New(jwt.SigningMethodHS256)
  20. // Set some claims
  21. token.Claims["foo"] = "bar"
  22. token.Claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
  23. // Sign and get the complete encoded token as a string
  24. tokenString, err := token.SignedString(mySigningKey)
  25. return tokenString, err
  26. }
  27. func ExampleParse(myToken string, myKey string) {
  28. token, err := jwt.Parse(myToken, func(token *jwt.Token) (interface{}, error) {
  29. return []byte(myKey), nil
  30. })
  31. if err == nil && token.Valid {
  32. fmt.Println("Your token is valid. I like your style.")
  33. } else {
  34. fmt.Println("This token is terrible! I cannot accept this.")
  35. }
  36. }

答案2

得分: 11

只是为了更新@massoud-afrashteh的答案。
在jwt-go的第3个版本中,设置声明应该是这样的:

  1. // 设置一些声明
  2. claims := make(jwt.MapClaims)
  3. claims["foo"] = "bar"
  4. claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
  5. token.Claims = claims
英文:

Just to make update of @massoud-afrashteh answer.
In version 3 of jwt-go setting clams should be

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

答案3

得分: 4

不要忘记运行命令 go get github.com/dgrijalva/jwt-go

另一种更简单的创建方式:

  1. token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
  2. "foo": "bar",
  3. "nbf": time.Date(2015, 10, 10, 12, 0, 0, 0, time.UTC).Unix(),
  4. })
  5. tokenString, err := token.SignedString([]byte("your key"))
  6. fmt.Println(tokenString, err)
英文:

Don't forget to run the command go get github.com/dgrijalva/jwt-go.

Another way to create more simple:

  1. token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
  2. "foo": "bar",
  3. "nbf": time.Date(2015, 10, 10, 12, 0, 0, 0, time.UTC).Unix(),
  4. })
  5. tokenString, err := token.SignedString([]byte("your key"))
  6. fmt.Println(tokenString, err)

答案4

得分: 1

func GenerateToken(mySigningKey []byte, username string) (string, error) {
// 创建令牌
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. func GenerateToken(mySigningKey []byte, username string) (string, error) {
  2. // Create the token
  3. token := jwt.New(jwt.SigningMethodRS512)
  4. claims := make(jwt.MapClaims)
  5. claims[collections.PARAM_USER_NAME] = username
  6. claims["exp"] = time.Now().Add(time.Hour * 72).Unix()
  7. token.Claims = claims
  8. return token.SignedString(mySigningKey)
  9. }

huangapple
  • 本文由 发表于 2016年3月26日 21:56:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/36236109.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定