1.简述
用于记录在go-zero的后端项目中如何添加jwt中间件鉴权
2.流程
配置api.yaml
Auth:
AccessSecret: "secret_key"
AccessExpire: 604800
config中添加Auth结构体
Auth struct {
AccessSecret string
AccessExpire int64
}
types定义jwt token的自定义数据结构,这里以用户登录信息的UserClaims做例子,在types中新建userclaims.go文件
type UserClaims struct {
UserUID int64 `json:"user_uid"`
Role string `json:"role"`
jwt.RegisteredClaims
}
中间件方法:在middleware文件夹下建立jwtmiddleware.go用来储存创立和返回jwt中间件
1.jwt中间件结构体,包含一个secret字段用来实现jwt验签
// jwt中间件结构体,包含一个secret字段,用于jwt验签
type JWTMiddleware struct {
Secret string
}
2.创建jwtmiddleware的实例
// 工厂方法,用于创建和返回JWTMiddleware实力
func NewJWTMiddleware(secret string) *JWTMiddleware {
return &JWTMiddleware{Secret: secret}
}
3.中间件签名,接收一个函数handler,获取请求头中的token并解析,然后送入另一个handler
// 中间件签名,接受一个下一个处理的函数,返回另一个处理函数
func (m *JWTMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
//获取请求头中的token
tokenStr := r.Header.Get("Authorization")
if tokenStr == "" {
http.Error(w, "Missing token", http.StatusUnauthorized)
return
}
//解析token并绑定自定义结构体UserClaims
token, err := jwt.ParseWithClaims(tokenStr, &types.UserClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(m.Secret), nil
})
//检查是否有效
if err != nil || !token.Valid {
http.Error(w, "Invalid token", http.StatusUnauthorized)
return
}
// 将解析结果保存进 context
if claims, ok := token.Claims.(*types.UserClaims); ok {
ctx := context.WithValue(r.Context(), "user_uid", claims.UserUID)
ctx = context.WithValue(ctx, "role", claims.Role)
r = r.WithContext(ctx)
}
next(w, r)
}
}
servicecontext中注册并初始化jwt中间件
type ServiceContext struct {
Config config.Config
DB *gorm.DB
UserModel model.IUserModel
JWTMiddleware *middleware.JWTMiddleware
}
func NewServiceContext(c config.Config) *ServiceContext {
db, err := gorm.Open(mysql.Open(c.Mysql.DataSource), &gorm.Config{})
if err != nil {
panic("connect failed : " + err.Error())
}
_ = db.AutoMigrate(
&model.User{},
&model.Post{},
&model.Comment{},
&model.Like{},
&model.Report{},
&model.Section{},
&model.SearchModel{},
&model.InstallationStatus{})
return &ServiceContext{
Config: c,
DB: db,
JWTMiddleware: middleware.NewJWTMiddleware(c.Auth.AccessSecret),
}
}
routes中给要使用jwt的api进行包装(这里还没写需要用的api,大概语法如下)
//初始化中间件
jwtMW := middleware.NewJWTMiddleware(secret_key)
//包装需要用的api
server.AddRoutes(
[]rest.Route{
{
Method: http.MethodPost,
Path: "/api/user_info",
Handler: jwtMW.Handle(GetUserInfo(user_uid)),
},
},
)