package internal import ( "context" "strings" "yx-dataset-server/app/bll" "yx-dataset-server/app/errors" "yx-dataset-server/app/model" "yx-dataset-server/app/schema" "yx-dataset-server/library/auth" "yx-dataset-server/library/utils" "github.com/LyricTian/captcha" "net/http" ) // NewLogin 创建Login func NewLogin( Auth auth.Auther, user model.IUser, verifyCode bll.IVerifyCode, mTransModel model.ITrans, mLoginHis model.ILoginHistory, ) *Login { return &Login{ auth: Auth, userModel: user, verifyCodeBll: verifyCode, transModel: mTransModel, loginHisModel: mLoginHis, } } // Login 创建Login对象 type Login struct { auth auth.Auther userModel model.IUser verifyCodeBll bll.IVerifyCode transModel model.ITrans loginHisModel model.ILoginHistory } // GetCaptchaID 获取图形验证码信息 func (a *Login) GetCaptchaID(ctx context.Context, length int) (*schema.LoginCaptcha, error) { captchaID := captcha.NewLen(length) item := &schema.LoginCaptcha{ CaptchaID: captchaID, } return item, nil } // ResCaptcha 生成并响应图形验证码 func (a *Login) ResCaptcha(ctx context.Context, w http.ResponseWriter, captchaID string, width, height int) error { err := captcha.WriteImage(w, captchaID, width, height) if err != nil { return err } w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") w.Header().Set("Pragma", "no-cache") w.Header().Set("Expires", "0") w.Header().Set("Content-Type", "image/png") return nil } // GenerateToken 生成令牌 func (a *Login) GenerateToken(ctx context.Context, userID string) (*schema.LoginTokenInfo, error) { tokenInfo, err := a.auth.GenerateToken(userID) if err != nil { return nil, errors.New400Response("生成令牌发生错误") } item := &schema.LoginTokenInfo{ AccessToken: tokenInfo.GetAccessToken(), TokenType: tokenInfo.GetTokenType(), ExpiresAt: tokenInfo.GetExpiresAt(), } return item, nil } // DestroyToken 销毁令牌 func (a *Login) DestroyToken(ctx context.Context, tokenString string) error { err := a.auth.DestroyToken(tokenString) if err != nil { return errors.WithStack(err) } return nil } // RefreshToken 刷新令牌 func (a *Login) RefreshToken(ctx context.Context) (*schema.LoginTokenInfo, error) { userid := GetUserID(ctx) if userid == "" { return nil, errors.ErrInvalidToken } token, err := a.GenerateToken(ctx, userid) if err != nil { return nil, errors.New400Response("刷新令牌发生错误") } return token, nil } // Verify 登录验证 func (a *Login) Verify(ctx context.Context, userName, password string) (*schema.User, error) { // 检查是否是超级用户 root := GetRootUser() if userName == root.UserName && root.Password == password { return root, nil } result, err := a.userModel.Query(ctx, schema.UserQueryParam{ UserName: userName, }) if err != nil { return nil, err } else if len(result.Data) == 0 { return nil, errors.ErrInvalidUserName } item := result.Data[0] if item.Password != utils.SHA1HashString(strings.ToUpper(password)) { return nil, errors.ErrInvalidPassword } else if !item.Status { return nil, errors.ErrInvalidUser } return item, nil } // GetUserInfo 获取当前用户登录信息 func (a *Login) GetUserInfo(ctx context.Context) (*schema.UserLoginInfo, error) { userID := GetUserID(ctx) if isRoot := CheckIsRootUser(ctx); isRoot { root := GetRootUser() loginInfo := &schema.UserLoginInfo{ UserName: root.UserName, RealName: root.RealName, Photo: root.Photo, } return loginInfo, nil } user, err := a.userModel.Get(ctx, userID) if err != nil { return nil, err } else if user == nil { return nil, errors.ErrInvalidUser } else if user.Status { return nil, errors.ErrUserDisable } loginInfo := &schema.UserLoginInfo{ UserName: user.UserName, RealName: user.RealName, } return loginInfo, nil } func (a *Login) getAndCheckUser(ctx context.Context, userID string, opts ...schema.UserOptions) (*schema.User, error) { user, err := a.userModel.Get(ctx, userID, opts...) if err != nil { return nil, err } else if user == nil { return nil, errors.ErrInvalidUser } else if user.Status { return nil, errors.ErrUserDisable } return user, nil } // UpdatePassword 更新当前用户登录密码 func (a *Login) UpdatePassword(ctx context.Context, params schema.UpdatePasswordParam) error { userID := GetUserID(ctx) if CheckIsRootUser(ctx) { return errors.New400Response("超级管理员密码只能通过配置文件修改") } if params.OldPassword == "" { return errors.ErrUserNotEmptyPwd } user, err := a.getAndCheckUser(ctx, userID) if err != nil { return err } else if utils.SHA1HashString(strings.ToUpper(params.OldPassword)) != user.Password { return errors.ErrLoginInvalidOldPwd } params.NewPassword = utils.SHA1HashString(strings.ToUpper(params.NewPassword)) return a.userModel.UpdatePassword(ctx, userID, params.NewPassword) } // Unsubscribe 用户注销 func (a *Login) Unsubscribe(ctx context.Context, userId, tokenStr string) error { err := ExecTrans(ctx, a.transModel, func(ctx context.Context) error { err := a.userModel.Delete(ctx, userId) if err != nil { return err } return a.DestroyToken(ctx, tokenStr) }) return err } // LoginBySms 通过短信验证码登录 func (a *Login) LoginBySms(ctx context.Context, params schema.SmsLoginParam) error { checkResult, err := a.verifyCodeBll.Check(ctx, schema.VerifyCodeCheck{ Tel: params.Phone, BusinessType: params.BusinessType, Code: params.Code, }) if err != nil { return err } if !checkResult { return errors.ErrSmsCode } return nil }