go-zero 实战 - User Userinfo

API Gateway 增加 Jwt 鉴权

userinfo 接口与 loginregister 接口不同,在接口调用的时候,需要做鉴权。

编辑 api/etc 下的 user-api.yaml 文件,新增如下

yaml 复制代码
Auth:
  AccessSecret: ad879037-d3fd-tghj-112d-6bfc35d54b7d
  AccessExpire: 86400

编辑 api/internal/config 下的 config.go 文件,新增如下

go 复制代码
type Config struct {
    rest.RestConf
    DataSource   string
    AccessSecret string
    AccessExpire int64
    Salt         string
    Auth         struct { // JWT 认证需要的密钥和过期时间配置
       AccessSecret string
       AccessExpire int64
    }
}

编辑 api 下的 user.api 文件, 修改为如下

api 复制代码
info(
    title: "UserApi"
    desc: "用户服务相关 API"
    author: "DESKTOP-4T5UKHP/Owner"
    email: "renpanpan1990@163.com"
)

type LoginRequest {
    Email    string `json:"email"`
    Password string `json:"password"`
}

type LoginResponse {
    UserReply
}

type RegisterRequest {
    Username string `json:"username"`
    Email    string `json:"email"`
    Password string `json:"password"`
}

type RegisterResponse {
    UserReply
}

type UserinfoResponse {
    UserReply
}

type UserReply {
    Id       int64  `json:"id"`
    Username string `json:"username"`
    Email    string `json:"email"`
    JwtToken
}

type JwtToken {
    AccessToken  string `json:"accessToken,omitempty"`
    AccessExpire int64  `json:"accessExpire,omitempty"`
    RefreshAfter int64  `json:"refreshAfter,omitempty"`
}

service user-api {
    @handler Login    // 用户登录
    post /users/login(LoginRequest) returns(LoginResponse)

    @handler Register // 用户注册
    post /users/register(RegisterRequest) returns(RegisterResponse)
}

@server (
    jwt: Auth
)
service user-api {
    @handler UserInfo // 用户信息
    post /users/userinfo() returns(UserinfoResponse)
}

UserInfo 接口的调用需要 jwt 鉴权,于是,我们新增了

api 复制代码
@server (
    jwt: Auth
)
service user-api {
    @handler UserInfo // 用户信息
    post /users/userinfo() returns(UserinfoResponse)
}

由于原来我们生成过 user-api 服务,userinfohandle.gouserinfologic.go 文件不符合我们现在的需求,需要删除掉这两个文件重新生成。

重新生成 user-api 服务

bash 复制代码
$ goctl api go -api user.api -dir .

查看 api/internal/handler 下的 routers.go 文件。 userinfo 接口与 login register 接口分开处理了,并且增加了 rest.WithJwt(serverCtx.Config.Auth.AccessSecret) 鉴权处理。

go 复制代码
func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
    server.AddRoutes(
       []rest.Route{
          {
             Method:  http.MethodPost,
             Path:    "/users/login",
             Handler: LoginHandler(serverCtx),
          },
          {
             Method:  http.MethodPost,
             Path:    "/users/register",
             Handler: RegisterHandler(serverCtx),
          },
       },
    )

    server.AddRoutes(
       []rest.Route{
          {
             Method:  http.MethodPost,
             Path:    "/users/userinfo",
             Handler: UserInfoHandler(serverCtx),
          },
       },
       rest.WithJwt(serverCtx.Config.Auth.AccessSecret),
    )
}

编辑 api/internal/handler 下的 userinfohandler.go 文件,新增如下代码

go 复制代码
func UserInfoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
       l := logic.NewUserInfoLogic(r.Context(), svcCtx)
       resp, err := l.UserInfo()
       if err != nil {
          // httpx.ErrorCtx(r.Context(), w, err)
          httpx.OkJson(w, renpanpan.FailureResponse(nil, err.Error(), 1000))
       } else {
          // httpx.OkJsonCtx(r.Context(), w, resp)
          httpx.OkJson(w, renpanpan.SuccessResponse(resp, "获取成功"))
       }
    }
}

api/internal/logic 下的 userinfologic.go 文件中, 修改 UserInfo 方法如下:

go 复制代码
func (l *UserInfoLogic) UserInfo() (*types.UserinfoResponse, error) {
    // 获取 jwt 载体中 `userId` 信息
    userId, err := l.ctx.Value("userId").(json.Number).Int64()
    if err != nil {
       return nil, err
    }

    user, err := l.svcCtx.Model.FindOne(l.ctx, userId)
    if err != nil {
       return nil, err
    }

    response := types.UserReply{
       Id:       user.Id,
       Username: user.Name,
       Email:    user.Email,
    }

    return &types.UserinfoResponse{UserReply: response}, nil
}

启动服务

启动 user api 服务, 运行成功后,user api 则运行在本机的 8888 端口

bash 复制代码
➜  FoodGuides:
$ go run usermanage/api/user.go -f usermanage/api/etc/user-api.yaml
Starting server at 0.0.0.0:8888...

我们用 Postman 尝试请求用户信息接口:

  1. 我们先测试不携带 Authorization 的情况。其请求结果显示未授权(401 Unauthorized),如下图所示。
  1. 我们再测试携带 Authorization 后的情况。在 PostmanAuthorization 选项中选择 Bearer Token,填写登录成功后 Api 返回的 accessToken 字段值。其请求结果如下图所示,说明用户信息服务运行正常。

注意:因为 jwt 载体中存在 userId 信息,所以只要 Authorization 不变,请求到的结果永远都是同一用户的信息。如果想请求其他用户信息,必须调用登录或注册接口,将返回的 accessToken 字段值设置到 PostmanBearer Token 中,重新发起请求用户信息的请求。

上一篇《go-zero 实战 - User Register》

下一篇《go-zero 实战 - Food API Gateway

相关推荐
郝同学的测开笔记18 小时前
云原生探索系列(十二):Go 语言接口详解
后端·云原生·go
一点一木1 天前
WebAssembly:Go 如何优化前端性能
前端·go·webassembly
千羽的编程时光2 天前
【CloudWeGo】字节跳动 Golang 微服务框架 Hertz 集成 Gorm-Gen 实战
go
27669582923 天前
阿里1688 阿里滑块 231滑块 x5sec分析
java·python·go·验证码·1688·阿里滑块·231滑块
Moment4 天前
在 NodeJs 中如何通过子进程与 Golang 进行 IPC 通信 🙄🙄🙄
前端·后端·go
唐僧洗头爱飘柔95275 天前
(Go基础)变量与常量?字面量与变量的较量!
开发语言·后端·golang·go·go语言初上手
黑心萝卜三条杠5 天前
【Go语言】深入理解Go语言:并发、内存管理和垃圾回收
google·程序员·go
不喝水的鱼儿5 天前
【LuatOS】基于WebSocket的同步请求框架
网络·websocket·网络协议·go·luatos·lua5.4
微刻时光5 天前
程序员开发速查表
java·开发语言·python·docker·go·php·编程语言
lidenger6 天前
服务认证-来者何人
后端·go