next-terminal/server/service/user.go
dushixiang 11daa8bd4e
修复若干问题 (#229)
* 优化图标和LOGO

* 修改登录页面动画的速度为3

* 增加对websocket的异常处理

* 修复了用户组和用户名唯一判断错误的问题

* 提示版本号
2022-03-05 16:19:32 +08:00

340 lines
8.5 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 (
"errors"
"fmt"
"strings"
"next-terminal/server/constant"
"next-terminal/server/dto"
"next-terminal/server/env"
"next-terminal/server/global/cache"
"next-terminal/server/log"
"next-terminal/server/model"
"next-terminal/server/repository"
"next-terminal/server/utils"
"golang.org/x/net/context"
"gorm.io/gorm"
)
type userService struct {
baseService
}
func (service userService) InitUser() (err error) {
users, err := repository.UserRepository.FindAll(context.TODO())
if err != nil {
return err
}
if len(users) == 0 {
initPassword := "admin"
var pass []byte
if pass, err = utils.Encoder.Encode([]byte(initPassword)); err != nil {
return err
}
user := model.User{
ID: utils.UUID(),
Username: "admin",
Password: string(pass),
Nickname: "超级管理员",
Type: constant.TypeAdmin,
Created: utils.NowJsonTime(),
Status: constant.StatusEnabled,
}
if err := repository.UserRepository.Create(context.TODO(), &user); err != nil {
return err
}
log.Infof("初始用户创建成功,账号:「%v」密码「%v」", user.Username, initPassword)
} else {
for i := range users {
// 修正默认用户类型为管理员
if users[i].Type == "" {
user := model.User{
Type: constant.TypeAdmin,
ID: users[i].ID,
}
if err := repository.UserRepository.Update(context.TODO(), &user); err != nil {
return err
}
log.Infof("自动修正用户「%v」ID「%v」类型为管理员", users[i].Nickname, users[i].ID)
}
}
}
return nil
}
func (service userService) FixUserOnlineState() error {
// 修正用户登录状态
onlineUsers, err := repository.UserRepository.FindOnlineUsers(context.TODO())
if err != nil {
return err
}
if len(onlineUsers) > 0 {
for i := range onlineUsers {
logs, err := repository.LoginLogRepository.FindAliveLoginLogsByUsername(context.TODO(), onlineUsers[i].Username)
if err != nil {
return err
}
if len(logs) == 0 {
if err := repository.UserRepository.UpdateOnlineByUsername(context.TODO(), onlineUsers[i].Username, false); err != nil {
return err
}
}
}
}
return nil
}
func (service userService) LogoutByToken(token string) (err error) {
return env.GetDB().Transaction(func(tx *gorm.DB) error {
c := service.Context(tx)
loginLog, err := repository.LoginLogRepository.FindById(c, token)
if err != nil {
return err
}
cache.TokenManager.Delete(token)
loginLogForUpdate := &model.LoginLog{LogoutTime: utils.NowJsonTime(), ID: token}
err = repository.LoginLogRepository.Update(c, loginLogForUpdate)
if err != nil {
return err
}
loginLogs, err := repository.LoginLogRepository.FindAliveLoginLogsByUsername(c, loginLog.Username)
if err != nil {
return err
}
if len(loginLogs) == 0 {
err = repository.UserRepository.UpdateOnlineByUsername(c, loginLog.Username, false)
}
return err
})
}
func (service userService) LogoutById(c context.Context, id string) error {
user, err := repository.UserRepository.FindById(c, id)
if err != nil {
return err
}
username := user.Username
loginLogs, err := repository.LoginLogRepository.FindAliveLoginLogsByUsername(c, username)
if err != nil {
return err
}
for j := range loginLogs {
token := loginLogs[j].ID
if err := service.LogoutByToken(token); err != nil {
return err
}
}
return nil
}
func (service userService) OnEvicted(token string, value interface{}) {
if strings.HasPrefix(token, "forever") {
log.Debugf("re gen forever token")
} else {
log.Debugf("用户Token「%v」过期", token)
err := service.LogoutByToken(token)
if err != nil {
log.Errorf("退出登录失败 %v", err)
}
}
}
func (service userService) UpdateStatusById(id string, status string) error {
return env.GetDB().Transaction(func(tx *gorm.DB) error {
c := service.Context(tx)
if c.Value(constant.DB) == nil {
c = context.WithValue(c, constant.DB, env.GetDB())
}
if constant.StatusDisabled == status {
// 将该用户下线
if err := service.LogoutById(c, id); err != nil {
return err
}
}
u := model.User{
ID: id,
Status: status,
}
return repository.UserRepository.Update(c, &u)
})
}
func (service userService) ReloadToken() error {
loginLogs, err := repository.LoginLogRepository.FindAliveLoginLogs(context.TODO())
if err != nil {
return err
}
for i := range loginLogs {
loginLog := loginLogs[i]
token := loginLog.ID
user, err := repository.UserRepository.FindByUsername(context.TODO(), loginLog.Username)
if err != nil {
if errors.Is(gorm.ErrRecordNotFound, err) {
_ = repository.LoginLogRepository.DeleteById(context.TODO(), token)
}
continue
}
authorization := dto.Authorization{
Token: token,
Type: constant.LoginToken,
Remember: loginLog.Remember,
User: &user,
}
if authorization.Remember {
// 记住登录有效期两周
cache.TokenManager.Set(token, authorization, cache.RememberMeExpiration)
} else {
cache.TokenManager.Set(token, authorization, cache.NotRememberExpiration)
}
log.Debugf("重新加载用户「%v」授权Token「%v」到缓存", user.Nickname, token)
}
return nil
}
func (service userService) CreateUser(user model.User) (err error) {
return env.GetDB().Transaction(func(tx *gorm.DB) error {
c := service.Context(tx)
exist, err := repository.UserRepository.ExistByUsername(c, user.Username)
if err != nil {
return err
}
if exist {
return fmt.Errorf("username %s is already used", user.Username)
}
password := user.Password
var pass []byte
if pass, err = utils.Encoder.Encode([]byte(password)); err != nil {
return err
}
user.Password = string(pass)
user.ID = utils.UUID()
user.Created = utils.NowJsonTime()
user.Status = constant.StatusEnabled
if err := repository.UserRepository.Create(c, &user); err != nil {
return err
}
err = StorageService.CreateStorageByUser(&user)
if err != nil {
return err
}
if user.Mail != "" {
go MailService.SendMail(user.Mail, "[Next Terminal] 注册通知", "你好,"+user.Nickname+"。管理员为你注册了账号:"+user.Username+" 密码:"+password)
}
return nil
})
}
func (service userService) DeleteUserById(userId string) error {
return env.GetDB().Transaction(func(tx *gorm.DB) error {
c := service.Context(tx)
// 下线该用户
if err := service.LogoutById(c, userId); err != nil {
return err
}
// 删除用户
if err := repository.UserRepository.DeleteById(c, userId); err != nil {
return err
}
// 删除用户与用户组的关系
if err := repository.UserGroupMemberRepository.DeleteByUserId(c, userId); err != nil {
return err
}
// 删除用户与资产的关系
if err := repository.ResourceSharerRepository.DeleteByUserId(c, userId); err != nil {
return err
}
// 删除用户的默认磁盘空间
if err := StorageService.DeleteStorageById(userId, true); err != nil {
return err
}
return nil
})
}
func (service userService) DeleteLoginLogs(tokens []string) error {
if len(tokens) > 0 {
for _, token := range tokens {
if err := service.LogoutByToken(token); err != nil {
return err
}
if err := repository.LoginLogRepository.DeleteById(context.TODO(), token); err != nil {
return err
}
}
}
return nil
}
func (service userService) SaveLoginLog(clientIP, clientUserAgent string, username string, success, remember bool, id, reason string) error {
loginLog := model.LoginLog{
Username: username,
ClientIP: clientIP,
ClientUserAgent: clientUserAgent,
LoginTime: utils.NowJsonTime(),
Reason: reason,
Remember: remember,
}
if success {
loginLog.State = "1"
loginLog.ID = id
} else {
loginLog.State = "0"
loginLog.ID = utils.LongUUID()
}
if err := repository.LoginLogRepository.Create(context.TODO(), &loginLog); err != nil {
return err
}
return nil
}
func (service userService) DeleteALlLdapUser(ctx context.Context) error {
return repository.UserRepository.DeleteBySource(ctx, constant.SourceLdap)
}
func (service userService) UpdateUser(id string, user model.User) error {
return env.GetDB().Transaction(func(tx *gorm.DB) error {
ctx := service.Context(tx)
dbUser, err := repository.UserRepository.FindById(ctx, id)
if err != nil {
return err
}
if dbUser.Username != user.Username {
// 修改了登录账号
exist, err := repository.UserRepository.ExistByUsername(ctx, user.Username)
if err != nil {
return err
}
if exist {
return fmt.Errorf("username %s is already used", user.Username)
}
}
return repository.UserRepository.Update(ctx, &user)
})
}