Files
bl/modules/base/service/base_sys_login.go
昔念 b049e129c5
All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful
1
2026-02-03 22:44:13 +08:00

257 lines
7.5 KiB
Go

package service
import (
"context"
"fmt"
"log"
"strings"
"time"
"github.com/golang-jwt/jwt/v4"
"blazing/cool"
v1 "blazing/modules/base/api/v1"
"blazing/modules/base/config"
"blazing/modules/base/model"
"github.com/gogf/gf/v2/crypto/gmd5"
"github.com/gogf/gf/v2/encoding/gbase64"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/grand"
"github.com/gogf/gf/v2/util/guid"
)
type BaseSysLoginService struct {
*cool.Service
}
type TokenResult struct {
Expire uint `json:"expire"`
Token string `json:"token"`
RefreshExpire uint `json:"refreshExpire"`
RefreshToken string `json:"refreshToken"`
}
// Login 登录
func (s *BaseSysLoginService) Login(ctx context.Context, req *v1.BaseOpenLoginReq) (result *TokenResult, err error) {
var (
captchaId = req.CaptchaId
verifyCode = req.VerifyCode
password = req.Password
username = req.Username
baseSysUser = model.NewBaseSysUser()
)
username = strings.ToLower(username)
vcode, _ := cool.CacheManager.Get(ctx, "login:"+captchaId)
if vcode.String() != verifyCode {
err = gerror.New("验证码错误")
return
}
// 调用方法
userInfo, err := GetUserInfo(username, password)
if err != nil {
err = gerror.New("用户系统错误")
return
}
// // 输出结果
// fmt.Printf("用户名: %s\n", userInfo.Data.Attributes.Username)
// fmt.Printf("显示名: %s\n", userInfo.Data.Attributes.DisplayName)
// fmt.Printf("头像: %s\n", userInfo.Data.Attributes.AvatarUrl)
// fmt.Printf("加入时间: %s\n", userInfo.Data.Attributes.JoinTime)
// fmt.Printf("金钱: %.2f\n", userInfo.Data.Attributes.Money)
// fmt.Printf("用户组: %s\n", userInfo.Included[0].Attributes.NameSingular)
md5password, _ := gmd5.Encrypt(password)
var user *model.BaseSysUser
if !strings.EqualFold(userInfo.Data.Attributes.Username, username) { //说明没查找到用户
//后端添加的账户
cool.DBM(baseSysUser).Where("username=?", username).Where("password=?", md5password).Where("status=?", 1).Scan(&user)
if user == nil {
err = gerror.New("账户或密码不正确~")
return
}
} else {
m := cool.DBM(baseSysUser).Where("username=?", username)
m.Scan(&user)
if user == nil {
//这里实现注册用户
//err = gerror.New("账户或密码不正确~")
// return
NewBaseSysUserService().Gen(userInfo.Data.Attributes)
m := cool.DBM(baseSysUser).Where("username=?", username)
m.Scan(&user)
} else {
if *user.Status == 0 {
err = gerror.New("账户被封禁~")
return
}
user.HeadImg = &userInfo.Data.Attributes.AvatarUrl
var ttt = *user.PasswordV + 1
user.PasswordV = &ttt
_, err := m.Save(user)
if err != nil {
log.Fatal(err)
}
cool.CacheManager.Set(ctx, fmt.Sprintf("admin:passwordVersion:%d", user.ID), ttt, 0)
}
}
result, err = s.generateTokenByUser(ctx, user)
if err != nil {
return
}
return
}
// Captcha 图形验证码
func (*BaseSysLoginService) Captcha(req *v1.BaseOpenCaptchaReq) (interface{}, error) {
type capchaInfo struct {
CaptchaId string `json:"captchaId"`
Data string `json:"data"`
}
var (
ctx g.Ctx
err error
result = &capchaInfo{}
)
captchaText := grand.Digits(4)
svg := `<svg width="150" height="50" xmlns="http://www.w3.org/2000/svg"><text x="75" y="25" text-anchor="middle" font-size="25" fill="#fff">` + captchaText + `</text></svg>`
svgbase64 := gbase64.EncodeString(svg)
result.Data = `data:image/svg+xml;base64,` + svgbase64
result.CaptchaId = guid.S()
cool.CacheManager.Set(ctx, "login:"+result.CaptchaId, captchaText, 1800*time.Second)
return result, err
}
// Logout 退出登录
func (*BaseSysLoginService) Logout(ctx context.Context) (err error) {
userId := cool.GetAdmin(ctx).UserId
cool.CacheManager.Remove(ctx, "admin:department:"+gconv.String(userId))
cool.CacheManager.Remove(ctx, "admin:perms:"+gconv.String(userId))
cool.CacheManager.Remove(ctx, "admin:token:"+gconv.String(userId))
cool.CacheManager.Remove(ctx, "admin:token:refresh:"+gconv.String(userId))
return
}
// RefreshToken 刷新token
func (s *BaseSysLoginService) RefreshToken(ctx context.Context, token string) (result *TokenResult, err error) {
tokenClaims, err := jwt.ParseWithClaims(token, &cool.Claims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(config.Config.Jwt.Secret), nil
})
if err != nil {
return
}
claims, ok := tokenClaims.Claims.(*cool.Claims)
if !ok {
err = gerror.New("tokenClaims.Claims.(*Claims) error")
return
}
if !tokenClaims.Valid {
err = gerror.New("tokenClaims.Valid error")
return
}
if !claims.IsRefresh {
err = gerror.New("claims.IsRefresh error")
return
}
if !(claims.UserId > 0) {
err = gerror.New("claims.UserId error")
return
}
var (
user *model.BaseSysUser
baseSysUser = model.NewBaseSysUser()
)
cool.DBM(baseSysUser).Where("id=?", claims.UserId).Where("status=?", 1).Scan(&user)
if user == nil {
err = gerror.New("用户不存在")
return
}
result, err = s.generateTokenByUser(ctx, user)
return
}
// generateToken 生成token
func (*BaseSysLoginService) generateToken(ctx context.Context, user *model.BaseSysUser, roleIds []string, exprire uint, isRefresh bool) (token string) {
err := cool.CacheManager.Set(ctx, "admin:passwordVersion:"+gconv.String(user.ID), gconv.String(user.PasswordV), 0)
if err != nil {
cool.Logger.Error(ctx, "生成token失败", err)
}
claims := &cool.Claims{
IsRefresh: isRefresh,
RoleIds: roleIds,
Username: user.Username,
UserId: user.ID,
PasswordVersion: user.PasswordV,
RegisteredClaims: jwt.RegisteredClaims{
IssuedAt: jwt.NewNumericDate(time.Now()),
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(exprire) * time.Second)),
},
}
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
token, err = tokenClaims.SignedString([]byte(config.Config.Jwt.Secret))
if err != nil {
cool.Logger.Error(ctx, "生成token失败", err)
}
return
}
// 根据用户生成前端需要的Token信息
func (s *BaseSysLoginService) generateTokenByUser(ctx context.Context, user *model.BaseSysUser) (result *TokenResult, err error) {
var (
baseSysRoleService = NewBaseSysRoleService()
baseSysMenuService = NewBaseSysMenuService()
baseSysDepartmentService = NewBaseSysDepartmentService()
)
// 获取用户角色
roleIds := baseSysRoleService.GetByUser(user.ID)
// 如果没有角色,则报错
if len(roleIds) == 0 {
err = gerror.New("该用户未设置任何角色,无法登录~")
return
}
// 生成token
result = &TokenResult{}
result.Expire = config.Config.Jwt.Token.Expire
result.RefreshExpire = config.Config.Jwt.Token.RefreshExpire
result.Token = s.generateToken(ctx, user, roleIds, result.Expire, false)
result.RefreshToken = s.generateToken(ctx, user, roleIds, result.RefreshExpire, true)
// 将用户相关信息保存到缓存
perms := baseSysMenuService.GetPerms(roleIds)
departments := baseSysDepartmentService.GetByRoleIds(roleIds, user.Username == "admin")
cool.CacheManager.Set(ctx, "admin:department:"+gconv.String(user.ID), departments, 0)
cool.CacheManager.Set(ctx, "admin:perms:"+gconv.String(user.ID), perms, 0)
cool.CacheManager.Set(ctx, "admin:token:"+gconv.String(user.ID), result.Token, 0)
cool.CacheManager.Set(ctx, "admin:token:refresh:"+gconv.String(user.ID), result.RefreshToken, 0)
return
}
// NewBaseSysLoginService 创建一个新的BaseSysLoginService
func NewBaseSysLoginService() *BaseSysLoginService {
return &BaseSysLoginService{}
}