在应用开发中,使用令牌(Token)是一种常见的身份验证和授权机制。以下是一些使用令牌的主要原因:
JSON Web Token(JWT)是一种用于在网络上安全传输声明的一种开放标准(RFC 7519)。它由一串经过 Base64 编码的 JSON 对象组成,可以包含用户的一些身份信息,以便在不同系统之间安全传输。
JWT 主要由三个部分组成:
alg
表示签名算法(HMAC SHA256、RSA等),typ
表示令牌类型,这两部分会被 Base64 编码。iss
表示令牌的发行者,sub
表示令牌的主题,exp
表示令牌的过期时间等。JWT 的主要用途是在用户和服务器之间传递安全的身份信息。由于其轻量且易于使用,它已成为许多身份验证和授权协议的标准。
由于 JWT 的载荷(Payload)信息是 Base64 编码的,所以不应该在 JWT 中放置敏感信息,例如密码等。
对接第三方 API 通常涉及到以下几个步骤:获取访问令牌(token)、使用令牌进行 API 请求、处理 API 响应,以及在需要时刷新令牌。下面是一个简单的示例,演示如何使用github.com/golang-jwt/jwt/v5
库在 Go 中实现请求token
、刷新token
以及封装请求:
package main
import (
"context"
"fmt"
"net/http"
"time"
"github.com/golang-jwt/jwt/v5"
"github.com/pkg/errors"
)
// SecretKey 用于签名和验证的密钥
var SecretKey = []byte("your-secret-key")
var expire = 30 * time.Minute
// GenerateToken 生成 JWT
func GenerateToken() (string, error) {
claims := &jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(expire)),
Issuer: "example",
Subject: "example",
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
signedToken, err := token.SignedString(SecretKey)
if err != nil {
return "", err
}
return signedToken, nil
}
// RefreshToken 刷新 JWT
func RefreshToken(tokenString string) (string, error) {
// 解析 token
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
return SecretKey, nil
})
if err != nil || !token.Valid {
return "", fmt.Errorf("invalid token")
}
// 验证 token 是否有效
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
return "", fmt.Errorf("invalid claims")
}
exp, err := claims.GetExpirationTime()
if err != nil {
return "", errors.Wrap(err, "GetExpirationTime from token error")
}
if time.Until(exp.Time) < 0 {
return "", errors.New("the token expires")
}
return GenerateToken()
}
// AuthMiddleware 中间件,用于验证请求中的 token
func AuthMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
tokenString := r.Header.Get("Authorization")
if tokenString == "" {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// 解析 token
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
return SecretKey, nil
})
if err != nil || !token.Valid {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// 将解析后的用户信息存储在上下文中,以便后续处理函数使用
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
ctx := context.WithValue(r.Context(), "user", claims["sub"])
r = r.WithContext(ctx)
next.ServeHTTP(w, r)
})
}
// ExampleHandler 示例处理程序,需要通过 AuthMiddleware 进行身份验证
func ExampleHandler(w http.ResponseWriter, r *http.Request) {
user := r.Context().Value("user")
w.Write([]byte(fmt.Sprintf("Hello, %s!", user)))
}
func main() {
// 示例代码中使用的路由是伪代码,请根据你的实际项目使用适当的路由设置
mux := http.NewServeMux()
// 处理 /login 路径,生成 token
mux.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
token, err := GenerateToken()
if err != nil {
http.Error(w, "Failed to generate token", http.StatusInternalServerError)
return
}
w.Write([]byte(token))
})
// 处理 /refresh 路径,刷新 token
mux.HandleFunc("/refresh", func(w http.ResponseWriter, r *http.Request) {
tokenString := r.Header.Get("Authorization")
newToken, err := RefreshToken(tokenString)
if err != nil {
http.Error(w, "Failed to refresh token", http.StatusInternalServerError)
return
}
w.Write([]byte(newToken))
})
// 处理其他路径,需要通过 AuthMiddleware 进行身份验证
mux.Handle("/example", AuthMiddleware(http.HandlerFunc(ExampleHandler)))
fmt.Println("service start")
http.ListenAndServe(":8080", mux)
}
我正在参与2023腾讯技术创作特训营第四期有奖征文,快来和我瓜分大奖!
声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。