go-zero 实战 - User Userinfo
在上一篇文章中,我们介绍了如何搭建注册服务。本篇我们将介绍如何搭建获取用户信息服务。
做 iOS 或 Android 开发的小伙伴们应该都知道,userinfo 接口与 login 或 register 接口不同,此类接口一般都会要求传入 userId 和 token 来请求跟该用户相关的信息,我们一般称这个过程为 鉴权,接下来的服务实现也同样设计如此。
API Gateway 增加 Jwt 鉴权
编辑 api/etc 下的 user-api.yaml 文件,追加如下内容:
Auth:
AccessSecret: ad879037-d3fd-tghj-112d-6bfc35d54b7d
AccessExpire: 86400
注意:AccessSecret 和 AccessExpire 的值跟我们之前生成 token 时所配置的内容一致。因此这个时候你的 user-api.yaml 文件完整的内容应该是这样的:
Name: user-api
Host: 0.0.0.0
Port: 8888
DataSource: root:123456@tcp(127.0.0.1:9528)/foodguides?charset=utf8mb4&parseTime=True&loc=Local
AccessSecret: ad879037-d3fd-tghj-112d-6bfc35d54b7d
AccessExpire: 86400
Auth:
AccessSecret: ad879037-d3fd-tghj-112d-6bfc35d54b7d
AccessExpire: 86400
编辑 api/internal/config 下的 config.go 文件,新增 Auth 结构体的定义:
type Config struct {
rest.RestConf
DataSource string
AccessSecret string
AccessExpire int64
Auth struct { // JWT 认证需要的密钥和过期时间配置
AccessSecret string
AccessExpire int64
}
}
编辑 api 目录下的 user.api 文件, 修改如下:
syntax = "v1"
info (
title: "UserApi"
desc: "用户服务相关 API"
author: "DESKTOP-4T5UKHP/Owner"
email: "renpanpan1990@163.com"
)
type (
LoginRequest {
Email string `json:"email"`
Password string `json:"password"`
}
LoginResponse {
UserReply
}
)
type (
RegisterRequest {
Username string `json:"username"`
Email string `json:"email"`
Password string `json:"password"`
}
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 鉴权,于是,我们新增了
@server (
jwt: Auth
)
service user-api {
@handler UserInfo // 用户信息
post /users/userinfo returns(UserinfoResponse)
}
由于原来我们生成过 user-api 服务,userinfohandle.go 和 userinfologic.go 文件不符合我们现在的需求,需要删除掉这两个文件,重新生成 user-api 服务。
$ goctl api go -api user.api -dir .
我们再来查看 api/internal/handler 下的 routers.go 文件。 发现 userinfo 接口与 login register 接口分开处理了,并且增加了 rest.WithJwt(serverCtx.Config.Auth.AccessSecret) 鉴权处理。
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 文件,修改UserInfoHandler 方法如下所示:
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 方法如下:
func (l *UserInfoLogic) UserInfo() (*types.UserInfoResponse, error) {
// 获取 jwt 载体中 `payload` 信息,
// 我们在生成 jwt token 时,传的是字符串类型的 userId
payload, ok := l.ctx.Value("payload").(string)
if !ok {
return nil, errors.New("从 jwt 载体中获取 payload 失败")
}
userId, err := strconv.ParseInt(payload, 10, 64)
if err != nil {
return nil, err
}
user, err1 := l.svcCtx.Model.FindOne(l.ctx, userId)
if err1 != nil {
return nil, err1
}
response := types.UserReply{
Id: user.Id,
Username: user.Name,
Email: user.Email,
}
return &types.UserInfoResponse{UserReply: response}, nil
}
启动服务
启动 user api 服务, 运行成功后,user api 则运行在本机的 8888 端口
➜ FoodGuides:
$ go run usermanage/api/user.go -f usermanage/api/etc/user-api.yaml
Starting server at 0.0.0.0:8888...
我们用 Postman 尝试请求用户信息接口:
- 我们先测试不携带
Authorization的情况。其请求结果显示未授权(401 Unauthorized),如下图所示。

- 我们再测试携带
Authorization后的情况。在Postman的Authorization选项中选择Bearer Token,填写登录成功后Api返回的accessToken字段值。其请求结果如下图所示,说明用户信息服务运行正常。

注意:因为 jwt 载体中存在 userId 信息,所以只要 Authorization 不变,请求到的结果永远都是同一用户的信息。如果想请求其他用户信息,必须调用登录或注册接口,将返回的 accessToken 字段值设置到 Postman 的 Bearer Token 中,重新发起用户信息的请求。
至此,我们就完成了有关用户三个相关接口的搭建(登录,注册,用户信息)。从下一篇开始,我们将围绕 Food 开发相关接口,并与 user 关联起来。
转载自:https://juejin.cn/post/7287620609374945336