Files
observer/server/biz/service/auth.go
T
2026-08-31 16:37:26 +08:00

99 lines
3.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package service
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"golang.org/x/crypto/bcrypt"
"observer-server/biz/dao"
"observer-server/biz/model/dto"
"observer-server/common"
)
// authService 账号业务:注册(license 表即账号表,注册即插行)、登录(bcrypt 校验 + 签发 token
type authService struct{}
var Auth = &authService{}
// Register 注册:已注册(有密码)报错;存在运营手动授权先建的占位行(无密码)时补写密码完成注册。
func (s *authService) Register(ctx context.Context, req *dto.RegisterReq) (*dto.RegisterRes, error) {
hash, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
if err != nil {
return nil, gerror.Wrap(err, "密码加密失败")
}
err = common.Serial().Submit(ctx, func() error {
return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
lic, err := dao.License.GetByPhoneInTx(ctx, tx, req.Phone)
if err != nil {
return err
}
if lic == nil {
return dao.License.Register(ctx, tx, req.Phone, string(hash))
}
if lic.Password == "" {
return dao.License.SetPasswordInTx(ctx, tx, req.Phone, string(hash))
}
return gerror.New("该手机号已注册")
})
})
if err != nil {
return nil, err
}
common.ClearCache(ctx, "license:"+req.Phone)
return &dto.RegisterRes{}, nil
}
// Login 登录(自动注册式):绕缓存查账号(密码变更即时生效)。
// 手机号不存在 → 以输入密码创建账号;存在但密码为空(运营发卡占位行)→ 补写输入密码;
// 仅已有密码才做 bcrypt 比对,失败报错。创建/补密码后即视为登录成功签发 token。
func (s *authService) Login(ctx context.Context, req *dto.LoginReq) (*dto.LoginRes, error) {
lic, err := dao.License.GetByPhoneNoCache(ctx, req.Phone)
if err != nil {
return nil, err
}
if lic == nil || lic.Password == "" {
hash, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
if err != nil {
return nil, gerror.Wrap(err, "密码加密失败")
}
err = common.Serial().Submit(ctx, func() error {
return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
cur, err := dao.License.GetByPhoneInTx(ctx, tx, req.Phone)
if err != nil {
return err
}
if cur == nil {
return dao.License.Register(ctx, tx, req.Phone, string(hash))
}
if cur.Password == "" {
return dao.License.SetPasswordInTx(ctx, tx, req.Phone, string(hash))
}
return nil
})
})
if err != nil {
return nil, err
}
common.ClearCache(ctx, "license:"+req.Phone)
// 并发下密码可能已被他人补写,重新读取后统一走比对
lic, err = dao.License.GetByPhoneNoCache(ctx, req.Phone)
if err != nil {
return nil, err
}
}
if lic == nil || lic.Password == "" {
return nil, gerror.New("账号或密码错误")
}
if err := bcrypt.CompareHashAndPassword([]byte(lic.Password), []byte(req.Password)); err != nil {
return nil, gerror.New("账号或密码错误")
}
token, err := common.SignToken(ctx, req.Phone)
if err != nil {
return nil, err
}
return &dto.LoginRes{Token: token}, nil
}