You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

179 lines
5.3 KiB

package biz
import (
"context"
"time"
pb "moredoc/api/v1"
"moredoc/middleware/auth"
"moredoc/model"
"moredoc/util"
"moredoc/util/validate"
"moredoc/util/captcha"
"github.com/alexandrevicenzi/unchained"
"go.uber.org/zap"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/peer"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/emptypb"
)
type UserAPIService struct {
pb.UnimplementedUserAPIServer
dbModel *model.DBModel
logger *zap.Logger
auth *auth.Auth
}
func NewUserAPIService(dbModel *model.DBModel, logger *zap.Logger, auth *auth.Auth) (service *UserAPIService) {
return &UserAPIService{dbModel: dbModel, logger: logger.Named("UserAPIService"), auth: auth}
}
func (s *UserAPIService) getValidFieldMap() map[string]string {
return map[string]string{"Username": "用户名", "Password": "密码"}
}
// Register 用户注册
func (s *UserAPIService) Register(ctx context.Context, req *pb.RegisterAndLoginRequest) (*emptypb.Empty, error) {
err := validate.ValidateStruct(req, s.getValidFieldMap())
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, err.Error())
}
cfg := s.dbModel.GetConfigOfSecurity(
model.ConfigSecurityEnableCaptchaRegister,
model.ConfigSecurityEnableRegister,
model.ConfigSecurityIsClose,
)
if !cfg.EnableRegister {
return nil, status.Errorf(codes.InvalidArgument, "系统未开放注册")
}
if cfg.IsClose {
return nil, status.Errorf(codes.InvalidArgument, "网站已关闭,占时不允许注册")
}
if cfg.EnableCaptchaRegister && !captcha.VerifyCaptcha(req.CaptchaId, req.Captcha) {
return nil, status.Errorf(codes.InvalidArgument, "验证码错误")
}
exist, _ := s.dbModel.GetUserByUsername(req.Username, "id")
if exist.Id > 0 {
return nil, status.Errorf(codes.AlreadyExists, "用户名已存在")
}
user := &model.User{Username: req.Username, Password: req.Password}
if p, ok := peer.FromContext(ctx); ok {
user.RegisterIp = p.Addr.String()
}
group, _ := s.dbModel.GetDefaultUserGroup()
if group.Id <= 0 {
return nil, status.Errorf(codes.Internal, "请联系管理员设置系统默认用户组")
}
if err = s.dbModel.CreateUser(user, group.Id); err != nil {
s.logger.Error("CreateUser", zap.Error(err))
return nil, status.Errorf(codes.Internal, err.Error())
}
return &emptypb.Empty{}, nil
}
// Login 用户登录
func (s *UserAPIService) Login(ctx context.Context, req *pb.RegisterAndLoginRequest) (*pb.LoginReply, error) {
errValidate := validate.ValidateStruct(req, s.getValidFieldMap())
if errValidate != nil {
return nil, status.Errorf(codes.InvalidArgument, errValidate.Error())
}
// 如果启用了验证码,则需要进行验证码验证
cfg := s.dbModel.GetConfigOfSecurity(model.ConfigSecurityEnableCaptchaLogin)
if cfg.EnableCaptchaLogin && !captcha.VerifyCaptcha(req.CaptchaId, req.Captcha) {
return nil, status.Errorf(codes.InvalidArgument, "验证码错误")
}
user, err := s.dbModel.GetUserByUsername(req.Username)
if err != nil {
return nil, status.Errorf(codes.Internal, err.Error())
}
if ok, err := unchained.CheckPassword(req.Password, user.Password); !ok || err != nil {
return nil, status.Errorf(codes.InvalidArgument, "用户名或密码错误")
}
token, err := s.auth.CreateJWTToken(user.Id)
if err != nil {
return nil, status.Errorf(codes.Internal, err.Error())
}
pbUser := &pb.User{}
util.CopyStruct(&user, pbUser)
ip := ""
if p, ok := peer.FromContext(ctx); ok {
ip = p.Addr.String()
}
if e := s.dbModel.UpdateUser(&model.User{Id: user.Id, LoginAt: time.Now(), LastLoginIp: ip}, "login_at", "last_login_ip"); e != nil {
s.logger.Error("UpdateUser", zap.Error(e))
}
return &pb.LoginReply{Token: token, User: pbUser}, nil
}
func (s *UserAPIService) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.User, error) {
return &pb.User{}, nil
}
func (s *UserAPIService) UpdateUser(ctx context.Context, req *pb.User) (*pb.User, error) {
return &pb.User{}, nil
}
func (s *UserAPIService) UpdateUserPassword(ctx context.Context, req *pb.UpdateUserRequest) (*pb.User, error) {
return &pb.User{}, nil
}
func (s *UserAPIService) DeleteUser(ctx context.Context, req *pb.DeleteUserRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, nil
}
func (s *UserAPIService) ListUser(ctx context.Context, req *pb.ListUserRequest) (*pb.ListUserReply, error) {
return &pb.ListUserReply{}, nil
}
// GetUserCaptcha 获取用户验证码
func (s *UserAPIService) GetUserCaptcha(ctx context.Context, req *pb.GetUserCaptchaRequest) (res *pb.GetUserCaptchaReply, err error) {
cfgCaptcha := s.dbModel.GetConfigOfCaptcha()
cfgSecurity := s.dbModel.GetConfigOfSecurity()
res = &pb.GetUserCaptchaReply{
Enable: false,
Type: cfgCaptcha.Type,
}
switch req.Type {
case "register":
res.Enable = cfgSecurity.EnableCaptchaRegister
case "login":
res.Enable = cfgSecurity.EnableCaptchaLogin
case "upload":
res.Enable = cfgSecurity.EnableCaptchaUpload
case "find_password":
res.Enable = cfgSecurity.EnableCaptchaFindPassword
case "comment":
res.Enable = cfgSecurity.EnableCaptchaComment
default:
return nil, status.Errorf(codes.InvalidArgument, "不支持的验证码类型")
}
if res.Enable {
res.Id, res.Captcha, err = captcha.GenerateCaptcha(cfgCaptcha.Type)
if err != nil {
return nil, status.Errorf(codes.Internal, err.Error())
}
}
return res, nil
}