123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438 |
- package service
- import (
- "encoding/base64"
- "gadmin/config"
- "gadmin/internal/admin/consts"
- "gadmin/internal/admin/forms"
- "gadmin/internal/gorm/model"
- "gadmin/internal/gorm/query"
- "gadmin/utility/serializer"
- "gadmin/utility/token"
- jsoniter "github.com/json-iterator/go"
- "time"
- "github.com/gin-gonic/gin"
- "github.com/sirupsen/logrus"
- "golang.org/x/crypto/bcrypt"
- )
- // User 管理员服务
- var User = NewsUser()
- type LoginStats struct {
- FailNum int
- BanTs int64
- }
- type sUser struct {
- BanIps map[string]*LoginStats
- }
- func NewsUser() *sUser {
- user := new(sUser)
- user.BanIps = make(map[string]*LoginStats)
- return user
- }
- // 一次登录,清空错误次数
- func (s *sUser) AddSucessNum(ip string) {
- delete(s.BanIps, ip)
- }
- // 增加错误登录次数,超过10次,不再进行密码验证
- func (s *sUser) AddFailNum(ip string) {
- stats, ok := s.BanIps[ip]
- if !ok {
- stats = new(LoginStats)
- s.BanIps[ip] = stats
- }
- if stats.BanTs > 0 {
- return
- }
- if stats.FailNum > 10 {
- curTs := time.Now().Unix()
- stats.BanTs = curTs
- // 清理错误登录
- for k, v := range s.BanIps {
- if v.BanTs+24*60*60 < curTs {
- delete(s.BanIps, k)
- }
- }
- return
- }
- stats.FailNum += 1
- }
- // 检查是否允许登录
- func (s *sUser) CheckLoginAllow(ip string) bool {
- stats, ok := s.BanIps[ip]
- if !ok {
- return true
- }
- cur := time.Now().Unix()
- if stats.BanTs+1*60*60 > cur {
- return false
- }
- stats.BanTs = 0
- stats.FailNum = 0
- return true
- }
- // GetUser 用ID获取用户
- func (s *sUser) GetUser(ID interface{}) (u *model.AdminUser, err error) {
- result := config.DB.First(&u, ID)
- return u, result.Error
- }
- // SetPassword 设置密码
- func (s *sUser) SetPassword(password string) (string, error) {
- bytes, err := bcrypt.GenerateFromPassword([]byte(password), consts.PassWordCost)
- if err != nil {
- return "", err
- }
- return string(bytes), nil
- }
- // CheckPassword 校验密码
- func (s *sUser) CheckPasswordRight(passwordDigest, password string) bool {
- err := bcrypt.CompareHashAndPassword([]byte(passwordDigest), []byte(password))
- return err == nil
- }
- func (s *sUser) Login(req forms.UserLoginReq, ip string) serializer.Response {
- var (
- u model.AdminUser
- )
- if ok := s.CheckLoginAllow(ip); !ok {
- return serializer.ParamErr("账号已被禁止登录", nil)
- }
- if err := config.AdminDB.Where("user_name = ?", req.UserName).First(&u).Error; err != nil {
- s.AddFailNum(ip)
- logrus.Warnf("sUser %v Login req error %v.", req.UserName, ip)
- return serializer.ParamErr("账号错误或不存在,请检查", nil)
- }
- //p, _ := s.SetPassword(req.Password)
- //fmt.Println("pass:", p)
- if u.Status != 1 {
- return serializer.ParamErr("账号已被禁用", nil)
- }
- if s.CheckPasswordRight(u.PasswordDigest, req.Password) == false {
- s.AddFailNum(ip)
- logrus.Warnf("sUser %v Login req error. ip: %v.", req.UserName, ip)
- return serializer.ParamErr("密码不正确,如忘记了密码请联系管理员!", nil)
- }
- s.AddSucessNum(ip)
- //if os.Getenv("GIN_MODE") == "release" && u.UserName == "mojun" {
- // return serializer.ParamErr("该账号只允许在测试服登录!", nil)
- //}
- t := token.GenerateTokenUsingUUID()
- // 记录登录token
- key := config.GetUserTokenKey(u.ID)
- config.TokenRedis.HSet(key, t, time.Now().Unix())
- config.TokenRedis.Expire(key, config.TokenExpireTime)
- tokenKey := config.GetTokenKey(t)
- user := &token.UserClaims{
- ID: u.ID,
- UserName: u.UserName,
- RoleId: int64(u.RoleID),
- Avatar: u.Avatar,
- Nickname: u.Nickname,
- AccessToken: t,
- }
- userStr, err := jsoniter.MarshalToString(user)
- if err != nil {
- return serializer.Err(1, "", err)
- }
- config.TokenRedis.Set(tokenKey, userStr, config.TokenExpireTime)
- return serializer.Suc(forms.UserLoginRes{
- ID: u.ID,
- UserName: u.UserName,
- Nickname: u.Nickname,
- Status: u.Status,
- Avatar: u.Avatar,
- Token: base64.URLEncoding.EncodeToString([]byte(t)),
- })
- //t, err := token.GenerateToken(&token.UserClaims{
- // ID: u.ID,
- // UserName: u.UserName,
- // RoleId: int64(u.RoleID),
- // Avatar: u.Avatar,
- // Nickname: u.Nickname,
- //})
- //if err != nil {
- // return serializer.ParamErr(err.Error(), nil)
- //}
- //return serializer.Suc(forms.UserLoginRes{
- // ID: u.ID,
- // UserName: u.UserName,
- // Nickname: u.Nickname,
- // Status: u.Status,
- // Avatar: u.Avatar,
- // Token: t,
- //})
- }
- func (s *sUser) List(ctx *gin.Context, req forms.AdminUserListReq) serializer.Response {
- var (
- q = query.Use(config.AdminDB).AdminUser
- r = query.Use(config.AdminDB).AdminRole
- m = q.WithContext(ctx)
- offset int64 = 0
- models forms.UserAccountListRes
- lists []*forms.AdminUserListModel
- )
- m = m.Order(q.ID.Desc())
- req.Page, req.PerPage, offset = forms.CalculatePage(req.Page, req.PerPage)
- count, err := m.Count()
- if err != nil {
- return serializer.Err(consts.CodeParamErr, "查询出错 count", err)
- }
- if count > 0 {
- if err = m.Limit(int(req.PerPage)).Offset(int(offset)).Scan(&lists); err != nil {
- return serializer.Err(consts.CodeParamErr, "查询出错 lists", err)
- }
- }
- for _, v := range lists {
- role, err := r.WithContext(ctx).Where(r.ID.Eq(v.RoleID)).First()
- v.RoleName = "未绑定角色"
- if role != nil && err == nil {
- v.RoleName = role.Name
- }
- }
- models.List = lists
- models.Page = req.Page
- models.PerPage = req.PerPage
- models.PageCount = (count + req.PerPage - 1) / req.PerPage
- return serializer.Suc(models)
- }
- func (s *sUser) Edit(ctx *gin.Context, req forms.AdminUserEditReq) serializer.Response {
- q := query.Use(config.AdminDB).AdminUser
- logrus.Warnf("sUser Edit req:%+v", req)
- if req.RoleID <= 0 {
- return serializer.ParamErr("角色不能为空", nil)
- }
- if req.UserName == "" {
- return serializer.ParamErr("用户名不能为空", nil)
- }
- // 修改
- if req.ID > 0 {
- update := &model.AdminUser{
- UserName: req.UserName,
- RoleID: int32(req.RoleID),
- Nickname: req.Nickname,
- Status: req.Status,
- UpdatedAt: time.Now(),
- }
- _, err := q.WithContext(ctx).Where(q.ID.Eq(req.ID)).Updates(update)
- if err != nil {
- return serializer.Err(consts.CodeParamErr, "更新出错", err)
- }
- // 维护redis token
- config.TokenRedis.Del(config.GetUserTokenKey(req.ID))
- return serializer.Suc(nil)
- }
- if req.Password == "" {
- return serializer.ParamErr("密码不能为空", nil)
- }
- // 加密密码
- password, err := s.SetPassword(req.Password)
- if err != nil {
- return serializer.Err(
- consts.CodeEncryptError,
- "密码加密失败",
- err,
- )
- }
- // 新增
- create := &model.AdminUser{
- UserName: req.UserName,
- RoleID: int32(req.RoleID),
- Nickname: req.Nickname,
- PasswordDigest: password,
- Status: req.Status,
- UpdatedAt: time.Now(),
- CreatedAt: time.Now(),
- }
- if err = query.Use(config.AdminDB).AdminUser.WithContext(ctx).Create(create); err != nil {
- return serializer.DBErr(err.Error(), err)
- }
- return serializer.Suc(nil)
- }
- func (s *sUser) ResetPassword(ctx *gin.Context, req forms.AdminUserResetPasswordReq) serializer.Response {
- q := query.Use(config.AdminDB).AdminUser
- logrus.Warnf("sUser ResetPassword req:%+v", req)
- if req.ID <= 0 {
- return serializer.ParamErr("用于ID不能为空", nil)
- }
- if req.Password == "" {
- return serializer.ParamErr("密码不能为空", nil)
- }
- // 加密密码
- password, err := s.SetPassword(req.Password)
- if err != nil {
- return serializer.Err(
- consts.CodeEncryptError,
- "密码加密失败",
- err,
- )
- }
- update := &model.AdminUser{
- PasswordDigest: password,
- UpdatedAt: time.Now(),
- }
- _, err = q.WithContext(ctx).Where(q.ID.Eq(req.ID)).Updates(update)
- if err != nil {
- return serializer.Err(consts.CodeParamErr, "更新出错", err)
- }
- // 维护redis token
- config.TokenRedis.Del(config.GetUserTokenKey(req.ID))
- return serializer.Suc(nil)
- }
- func (s *sUser) UpdatePassword(ctx *gin.Context, req forms.AdminUserUpdatePasswordReq) serializer.Response {
- q := query.Use(config.AdminDB).AdminUser
- logrus.Warnf("sUser UpdatePassword req:%+v", req)
- userId := token.GetUID(ctx)
- if userId <= 0 {
- return serializer.ParamErr("用户信息获取失败", nil)
- }
- models, err := q.WithContext(ctx).Where(q.ID.Eq(userId)).First()
- if err != nil {
- return serializer.ParamErr(err.Error(), err)
- }
- if models == nil {
- return serializer.ParamErr("用户不存在", nil)
- }
- if !s.CheckPasswordRight(models.PasswordDigest, req.OldPassword) {
- return serializer.ParamErr("老密码不正确", nil)
- }
- // 加密密码
- password, err := s.SetPassword(req.NewPassword)
- if err != nil {
- return serializer.Err(
- consts.CodeEncryptError,
- "密码加密失败",
- err,
- )
- }
- update := &model.AdminUser{
- PasswordDigest: password,
- UpdatedAt: time.Now(),
- }
- _, err = q.WithContext(ctx).Where(q.ID.Eq(userId)).Updates(update)
- if err != nil {
- return serializer.Err(consts.CodeParamErr, "更新出错", err)
- }
- // 修改token状态
- config.TokenRedis.Del(config.GetUserTokenKey(userId))
- return serializer.Suc(nil)
- }
- func (s *sUser) GetUserInfo(c *gin.Context) (*model.AdminUser, error) {
- q := query.Use(config.AdminDB).AdminUser
- userId := token.GetUID(c)
- if userId <= 0 {
- c.JSON(200, serializer.Err(consts.CodeNoPermission, "用户信息获取失败", nil))
- c.Abort()
- }
- return q.WithContext(c).Where(q.ID.Eq(userId)).First()
- }
- func (s *sUser) GetUserRoleId(c *gin.Context) int64 {
- info, err := s.GetUserInfo(c)
- if err != nil {
- return 0
- }
- if info == nil {
- return 0
- }
- return int64(info.RoleID)
- }
- func (s *sUser) GetUserByUnionID(unionID string) (*model.AdminUser, error) {
- q := query.Use(config.AdminDB).AdminUser
- return q.Where(q.FeishuUnionID.Eq(unionID)).First()
- }
- func (s *sUser) GetUserRolePermission(c *gin.Context) (bool, error) {
- // 只有超管拥有角色管理权限
- roleId, _ := c.Get("admin_role_id")
- return config.IsSuperRole(roleId.(int64)), nil
- //res, ok := c.Get("user")
- //if !ok {
- // c.JSON(200, serializer.CheckLogin())
- // c.Abort()
- //}
- //user := res.(*token.UserClaims)
- //if user.RoleId == 1 { // 超管拥有权限
- // return true, nil
- //}
- //// 查询玩家是否拥有权限管理页面的入口
- //pageQ := query.Use(config.AdminDB).AdminMenu
- //pageIds := make([]int32, 0)
- //err := pageQ.WithContext(c).Where(pageQ.Path.Eq("/permission")).Pluck(pageQ.ID, &pageIds)
- //if err != nil {
- // logrus.WithField("from", "AdminMenu Pluck").Error(err)
- // return false, err
- //}
- //rmq := query.Use(config.AdminDB).AdminRoleMenu
- //count, err := rmq.WithContext(c).Where(rmq.RoleID.Eq(int32(user.RoleId)), rmq.PageID.In(pageIds...)).Count()
- //if err != nil {
- // logrus.WithField("from", "AdminRoleMenu Count").Error(err)
- // return false, err
- //}
- //if count > 0 {
- // return true, nil
- //} else {
- // return false, nil
- //}
- }
|