如何在 Golang 中检索经过身份验证的用户
How to retrieve the authenticated user in Golang
func Login(c echo.Context) error {
user := &users.User{}
if err := c.Bind(&user); err != nil {
return err
}
return token.SigIn(c, user.Email, user.Password)
}
这是我的登录函数,用于在用户发送请求时检索令牌。
处理令牌的登录函数
func SigIn(c echo.Context, email, password string) error {
user := users.User{}
db := database.SetUp()
if err := db.Where("email = ?", email).First(&user).Error; gorm.IsRecordNotFoundError(err) {
restErr := errors.NewBadRequestError("Invalid credentials")
return c.JSON(http.StatusBadRequest, restErr)
}
if user.VerifyPassword(password) != nil {
restErr := errors.NewUnauthorizedError("Couldn't log you in with these credentials")
return c.JSON(http.StatusUnauthorized, restErr)
}
//user is successfull
return CreateToken(c)
}
CreateToken函数如下
type TokenJWT struct {
Token string `json:"token"`
}
func CreateToken(c echo.Context) error {
token := jwt.New(jwt.SigningMethodHS256)
claims := token.Claims.(jwt.MapClaims)
claims["authorized"] = true
claims["name"] = "Pascal Gaetan"
claims["exp"] = time.Now().Add(time.Hour * 1).Unix()
// Generate encoded token and send it as response.
t, err := token.SignedString([]byte("my_secret_key"))
if err != nil {
return err
}
return c.JSON(http.StatusOK, TokenJWT{
Token: t,
})
}
当一切都成功时,我想通过调用 Me 函数的 URL /api/me 获得经过身份验证的用户
这是一种相当常见的设计模式,用于创建经过身份验证的客户端,然后在其上调用各种操作方法。您可以执行以下操作:
type Client struct {
... // other members
token string // unexported unless there is a special reason to do otherwise
}
func NewClient(c echo.Context, email, password string) (*Client, error) {
user := users.User{}
cl := Client{}
... // your original method
cl.token = token
return &cl, nil
}
func (c *Client) DoSomething(...) ... { ... }
让我将您的问题分为两部分:第一部分是如何轻松地在 JWT 令牌中或从 JWT 令牌中对用户进行编码和解码,第二部分是如何编写可以从任何地方检索用户的通用代码。
在您的示例中,我提到您创建了一个 MapClaims,但为了降低解析的复杂性,最好使用自定义声明类型创建一个令牌。如果您使用的是 dgrijalva/jwt-go,那么根据文档,您可以执行类似的操作
type UserClaims struct {
Name string `json:"name"`
jwt.StandardClaims
}
// encode it as before, but with your created type
t := jwt.New(signer)
userClaims := &UserClaims{Name: "Burmese"}
t.Claims = userClaims
tokenString, err = t.SignedString(]byte("my_secret_key"))
然后您可以使用
在您的 router/framework 中间件中解析您的用户
tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c"
token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte("my_secret_key"), nil
})
if claims, ok := token.Claims.(*UserClaims); ok && token.Valid {
fmt.Printf("%v %v", claims.Name, claims.StandardClaims.ExpiresAt)
} else {
fmt.Println(err)
}
本例取自官方文档here
现在您知道了如何轻松解析经过身份验证的用户结构,下一步逻辑是将其包装到您的中间件中。是否有很多实现细节,比如你可以从 cookie、header 或查询中检索 JWT,还在它们上定义一些顺序,要点如下:你应该将上述代码包装到你的中间件中,在解析结构后你可以传递它通过您的请求上下文。我不使用 echo 和其他框架,但是对于纯 net/http 你可以使用
从中间件传递你解析的结构
context.WithValue(ctx, UserCtxKey, claims)
希望对您有所帮助!
func Login(c echo.Context) error {
user := &users.User{}
if err := c.Bind(&user); err != nil {
return err
}
return token.SigIn(c, user.Email, user.Password)
}
这是我的登录函数,用于在用户发送请求时检索令牌。
处理令牌的登录函数
func SigIn(c echo.Context, email, password string) error {
user := users.User{}
db := database.SetUp()
if err := db.Where("email = ?", email).First(&user).Error; gorm.IsRecordNotFoundError(err) {
restErr := errors.NewBadRequestError("Invalid credentials")
return c.JSON(http.StatusBadRequest, restErr)
}
if user.VerifyPassword(password) != nil {
restErr := errors.NewUnauthorizedError("Couldn't log you in with these credentials")
return c.JSON(http.StatusUnauthorized, restErr)
}
//user is successfull
return CreateToken(c)
}
CreateToken函数如下
type TokenJWT struct {
Token string `json:"token"`
}
func CreateToken(c echo.Context) error {
token := jwt.New(jwt.SigningMethodHS256)
claims := token.Claims.(jwt.MapClaims)
claims["authorized"] = true
claims["name"] = "Pascal Gaetan"
claims["exp"] = time.Now().Add(time.Hour * 1).Unix()
// Generate encoded token and send it as response.
t, err := token.SignedString([]byte("my_secret_key"))
if err != nil {
return err
}
return c.JSON(http.StatusOK, TokenJWT{
Token: t,
})
}
当一切都成功时,我想通过调用 Me 函数的 URL /api/me 获得经过身份验证的用户
这是一种相当常见的设计模式,用于创建经过身份验证的客户端,然后在其上调用各种操作方法。您可以执行以下操作:
type Client struct {
... // other members
token string // unexported unless there is a special reason to do otherwise
}
func NewClient(c echo.Context, email, password string) (*Client, error) {
user := users.User{}
cl := Client{}
... // your original method
cl.token = token
return &cl, nil
}
func (c *Client) DoSomething(...) ... { ... }
让我将您的问题分为两部分:第一部分是如何轻松地在 JWT 令牌中或从 JWT 令牌中对用户进行编码和解码,第二部分是如何编写可以从任何地方检索用户的通用代码。
在您的示例中,我提到您创建了一个 MapClaims,但为了降低解析的复杂性,最好使用自定义声明类型创建一个令牌。如果您使用的是 dgrijalva/jwt-go,那么根据文档,您可以执行类似的操作
type UserClaims struct {
Name string `json:"name"`
jwt.StandardClaims
}
// encode it as before, but with your created type
t := jwt.New(signer)
userClaims := &UserClaims{Name: "Burmese"}
t.Claims = userClaims
tokenString, err = t.SignedString(]byte("my_secret_key"))
然后您可以使用
在您的 router/framework 中间件中解析您的用户tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c"
token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte("my_secret_key"), nil
})
if claims, ok := token.Claims.(*UserClaims); ok && token.Valid {
fmt.Printf("%v %v", claims.Name, claims.StandardClaims.ExpiresAt)
} else {
fmt.Println(err)
}
本例取自官方文档here
现在您知道了如何轻松解析经过身份验证的用户结构,下一步逻辑是将其包装到您的中间件中。是否有很多实现细节,比如你可以从 cookie、header 或查询中检索 JWT,还在它们上定义一些顺序,要点如下:你应该将上述代码包装到你的中间件中,在解析结构后你可以传递它通过您的请求上下文。我不使用 echo 和其他框架,但是对于纯 net/http 你可以使用
从中间件传递你解析的结构context.WithValue(ctx, UserCtxKey, claims)
希望对您有所帮助!