go-zero docker-compose 搭建课件服务(六):完善jwt鉴权和返回结构

0、索引

go-zero docker-compose 搭建课件服务(六):完善 jwt 鉴权和返回结构

0.1 源码地址

https://github.com/liuyuede123/go-zero-courseware

1、用户服务登录接口生成 jwt token

user/api/etc/user.yaml 中增加用于生成 jwt 的 secret 和过期时间

...

Auth:
  AccessSecret: 38f9c7af24ff11edb92900163e30ef81
  AccessExpire: 86400

user/api/internal/config/config.go 增加配置参数

...

Auth struct {
		AccessSecret string
		AccessExpire int64
}

在之前编写的登录逻辑中增加获取 token 的方法,并修改登录逻辑

...

func (l *UserLoginLogic) UserLogin(req *types.LoginRequest) (resp *types.LoginResponse, err error) {
	login, err := l.svcCtx.UserRpc.Login(l.ctx, &userclient.LoginRequest{
		LoginName: req.LoginName,
		Password:  req.Password,
	})
	if err != nil {
		return nil, err
	}

	now := time.Now().Unix()
	login.Token, err = l.getJwtToken(l.svcCtx.Config.Auth.AccessSecret, now, l.svcCtx.Config.Auth.AccessExpire, int64(login.Id))
	if err != nil {
		return nil, status.Error(5000, err.Error())
	}
	return &types.LoginResponse{
		Id:    login.Id,
		Token: login.Token,
	}, nil
}

func (l *UserLoginLogic) getJwtToken(secretKey string, iat, seconds, userId int64) (string, error) {
	claims := make(jwt.MapClaims)
	claims["exp"] = iat + seconds
	claims["iat"] = iat
	claims["userId"] = userId
	token := jwt.New(jwt.SigningMethodHS256)
	token.Claims = claims
	return token.SignedString([]byte(secretKey))
}

2、用户密码加密

user/rpc/internal/logic/registerlogic.go 修改代码加密密码

...

func (l *RegisterLogic) Register(in *user.RegisterRequest) (*user.RegisterResponse, error) {
	_, err := l.svcCtx.UserModel.FindOneByLoginName(l.ctx, in.LoginName)
	if err == nil {
		return nil, status.Error(5000, "登录名已存在")
	}

	if err != model.ErrNotFound {
		return nil, status.Error(500, err.Error())
	}

	pwd, err := bcrypt.GenerateFromPassword([]byte(in.Password), bcrypt.DefaultCost)
	if err != nil {
		return nil, status.Error(500, err.Error())
	}
	newUser := model.User{
		LoginName: in.LoginName,
		Username:  in.Username,
		Sex:       in.Sex,
		Password:  string(pwd),
	}
	_, err = l.svcCtx.UserModel.Insert(l.ctx, &newUser)
	if err != nil {
		return nil, status.Error(500, err.Error())
	}

	return &user.RegisterResponse{}, nil
}

user/rpc/internal/logic/loginlogic.go 登录逻辑修改密码验证

...

func (l *LoginLogic) Login(in *user.LoginRequest) (*user.LoginResponse, error) {
	userInfo, err := l.svcCtx.UserModel.FindOneByLoginName(l.ctx, in.LoginName)
	if err == model.ErrNotFound {
		return nil, status.Error(5000, "用户不存在")
	}
	if err != nil {
		return nil, status.Error(500, err.Error())
	}

	err = bcrypt.CompareHashAndPassword([]byte(userInfo.Password), []byte(in.Password))
	if err != nil {
		return nil, status.Error(5000, "密码错误")
	}

	return &user.LoginResponse{
		Id:    userInfo.Id,
		Token: "a.b.c",
	}, nil
}

3、其他接口增加鉴权中间件

修改 courseware/api/courseware.api 增加鉴权中间件

...

@server (
	jwt : Auth
)
service courseware {
	@handler coursewareAdd
	post /api/courseware/add (AddRequest) returns (AddResponse)

	@handler coursewareUpdate
	post /api/courseware/update (UpdateRequest) returns (UpdateResponse)

	@handler coursewareGet
	post /api/courseware/get (GetRequest) returns (GetResponse)

	@handler coursewareDelete
	post /api/courseware/delete (DeleteRequest) returns (DeleteResponse)

courseware/api/etc/courseware.yaml 课件 API 增加 auth 配置

...

Auth:
  AccessSecret: 38f9c7af24ff11edb92900163e30ef81
  AccessExpire: 86400

courseware/api/internal/config/config.go 增加 auth 配置

Auth struct {
		AccessSecret string
		AccessExpire int64
}

到 courseware/api/目录下重新生成路由文件

goctl api go -api courseware.api -dir . -style gozero

用户服务获取用户信息接口需要增加权限校验

修改 user/api/user.api 增加鉴权中间件

...

service user {
	@handler userLogin
	post /api/user/login (LoginRequest) returns (LoginResponse)

	@handler userRegister
	post /api/user/register (RegisterRequest) returns (RegisterResponse)
}

@server (
	jwt : Auth
)
service user {

	@handler userInfo
	post /api/user/userInfo (UserInfoRequest) returns (UserInfoResponse)
}

第一步已经生成 auth 相关配置不需要重新设置,到 user/api/目录下更新路由

goctl api go -api user.api -dir . -style gozero

4、返回结构优化

课件 API 层新增 courseware/api/response/response.go

package response

import (
	"github.com/zeromicro/go-zero/rest/httpx"
	"net/http"
)

type Body struct {
	Code    int         `json:"code"`
	Message string      `json:"message"`
	Data    interface{} `json:"data,omitempty"`
}

func Response(w http.ResponseWriter, resp interface{}, err error) {
	var body Body
	if err != nil {
		body.Code = 5000
		body.Message = err.Error()
		body.Data = nil
	} else {
		body.Code = 0
		body.Message = "OK"
		body.Data = resp
	}
	httpx.OkJson(w, body)
}

handler 中修改返回结构

修改前

...

if err != nil {
			httpx.Error(w, err)
		} else {
			httpx.OkJson(w, resp)
		}

修改后

response.Response(w, resp, err)

用户 API 服务重复上面的步骤...