【问题标题】:go-restful + JWT authenticationgo-restful + JWT 认证
【发布时间】:2017-02-08 07:22:27
【问题描述】:

我正在尝试将 JWT 身份验证插入使用 go-restful 编写的非常简单的 go 服务中。

代码非常类似于:

package main

import (
    "github.com/emicklei/go-restful"
    "log"
    "net/http"
)

type User struct {
    Id, Name string
}

type UserList struct {
    Users []User
}

func getAllUsers(request *restful.Request, response *restful.Response) {
    log.Printf("getAllUsers")
    response.WriteEntity(UserList{[]User{{"42", "Gandalf"}, {"3.14", "Pi"}}})
}

func NewUserService() *restful.WebService {
    ws := new(restful.WebService)
    ws.
        Path("/users").
        Consumes(restful.MIME_XML, restful.MIME_JSON).
        Produces(restful.MIME_JSON, restful.MIME_XML)

    ws.Route(ws.GET("").To(getAllUsers))

    return ws
}


func main() {
    restful.Add(NewUserService())
    log.Printf("start listening on localhost:8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

其中restful.Requesthttp.Request 的包装器。

话虽如此,也许可以使用Auth0 jwt middleware

但作为一个 golang 新手,我在管道过程中有点迷失。我看到我必须使用像

这样的Filter 函数
ws.Filter(jwtAuthentication)

在哪里

func jwtAuthentication(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
    // Jwt Magic goes here \o
    chain.ProcessFilter(req, resp)
}

但我不知道应该如何以及在哪里实例化 JWT 中间件。

【问题讨论】:

    标签: rest go jwt jwt-go go-restful


    【解决方案1】:

    这是使用auth0/go-jwt-middleware 实现过滤器的示例。在现实生活中,您可能希望避免每次都创建 jwtMiddleware 的新实例。

    func jwtAuthentication(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
        jwtMiddleware := jwtmiddleware.New(jwtmiddleware.Options{
            ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
                return []byte("My Secret"), nil
            },
            SigningMethod: jwt.SigningMethodHS256,
        })
    
        if err := jwtMiddleware.CheckJWT(resp.ResponseWriter, req.Request); err != nil {
            logger.Errorf("Authentication error: %v", err)
        }
        chain.ProcessFilter(req, resp)
    }
    

    在过滤器之后,解析的令牌将在上下文中(auth0/go-jwt-middleware 使用 gorilla/context)。默认上下文键是user

    注意:当设置JWTMiddleware.SigningMethod 时,中间件会验证令牌是否使用特定的签名算法进行签名。

    如果签名方法不是常量,可以使用ValidationKeyGetter回调来实现额外的检查。

    避免here描述的安全问题很重要。

    【讨论】:

      【解决方案2】:

      这里是生成 Token 的登录 API 示例,以及用于检查身份验证的 JWT 身份验证过滤器

      import (
        "os"
        "strings"
        "github.com/dgrijalva/jwt-go"
        "golang.org/x/crypto/bcrypt"
      )
      
      type Token struct {
        UserId   uint
        Username string
        jwt.StandardClaims
      }
      
      type Account struct {
        ID       uint
        Email    string
        Password string
        Token    string
      }
      
      func Login(request *restful.Request, response *restful.Response) {
        account := &Account{ID: 1, Email: "test@email.com" }
        // TODO - account should be pulled from database
      
        tk := &Token{ UserId: account.ID }
        token := jwt.NewWithClaims(jwt.GetSigningMethod("HS256"), tk)
        tokenString, _ := token.SignedString([]byte("JWT-SECRET-GOES-RIGHT-HERE"))
        account.Token = tokenString
        account.Password = ''
        response.WriteEntity(account)
      }
      
      func JwtAuthentication(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
          tokenHeader := req.Request.HeaderParameter("Authorization")
      
          if tokenHeader == "" {
            resp.WriteErrorString(http.StatusForbidden, "Not Authorized")
            return
          }
      
          splitted := strings.Split(tokenHeader, " ")
          if len(splitted) != 2 {
            resp.WriteErrorString(http.StatusForbidden, "Not Authorized")
            return
          }
      
          tokenPart := splitted[1]
          tk := &Token{}
      
          token, err := jwt.ParseWithClaims(tokenPart, tk, func(token *jwt.Token) (interface{}, error) {
            return []byte("JWT-SECRET-GOES-RIGHT-HERE"), nil
          })
      
          if err != nil { //Malformed token, returns with http code 403 as usual
            resp.WriteErrorString(http.StatusForbidden, "Not Authorized")
            return
          }
      
          if !token.Valid { //Token is invalid, maybe not signed on this server
            resp.WriteErrorString(http.StatusForbidden, "Not Authorized")
            return
          }
      
          chain.ProcessFilter(req, resp)
      }
      

      然后应用过滤器

      ws.Filter(JwtAuthentication)
      

      【讨论】:

        猜你喜欢
        • 2021-03-05
        • 2021-10-03
        • 2011-12-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-24
        • 2014-10-13
        • 2021-05-11
        相关资源
        最近更新 更多