{"record":{"id":"e72e2ef196b20786","repo":"flipped-aurora/gin-vue-admin","slug":"error-e72e2e","errorCode":null,"errorMessage":"用户名已注册","messagePattern":"用户名已注册","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/service/system/sys_user.go","lineNumber":33,"sourceCode":"\t\"github.com/flipped-aurora/gin-vue-admin/server/utils/logger\"\n\t\"github.com/google/uuid\"\n\t\"gorm.io/gorm\"\n)\n\n//@author: [piexlmax](https://github.com/piexlmax)\n//@function: Register\n//@description: 用户注册\n//@param: u model.SysUser\n//@return: userInter system.SysUser, err error\n\ntype UserService struct{}\n\nvar UserServiceApp = new(UserService)\n\nfunc (userService *UserService) Register(ctx context.Context, u system.SysUser) (userInter system.SysUser, err error) {\n\tvar user system.SysUser\n\tif !errors.Is(global.GVA_DB.WithContext(ctx).Where(\"username = ?\", u.Username).First(&user).Error, gorm.ErrRecordNotFound) { // 判断用户名是否注册\n\t\treturn userInter, errors.New(\"用户名已注册\")\n\t}\n\t// 否则 附加uuid 密码hash加密 注册\n\tcfg := (&SecurityConfigService{}).Current(ctx)\n\tu.MustChangePassword = cfg.ForceNewUserChangePassword\n\tu.Password = utils.BcryptHash(u.Password)\n\tu.UUID = uuid.New()\n\tnow := time.Now()\n\tu.PasswordUpdatedAt = &now\n\terr = global.GVA_DB.WithContext(ctx).Create(&u).Error\n\treturn u, err\n}\n\n//@author: [piexlmax](https://github.com/piexlmax)\n//@author: [SliverHorn](https://github.com/SliverHorn)\n//@function: Login\n//@description: 用户登录\n//@param: u *model.SysUser\n//@return: err error, userInter *model.SysUser","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/service/system/sys_user.go#L15-L51","documentation":"Register in UserService throws \"用户名已注册\" when a First() query on username does NOT return gorm.ErrRecordNotFound, i.e. a user with that username already exists. It prevents duplicate accounts before hashing the password and creating the record.","triggerScenarios":"Calling the register API with a username already present in sys_user; double-submitting a registration form; a soft-deleted user row still matching the unique username (if not excluded by GORM soft-delete).","commonSituations":"Users re-registering with an existing name; concurrent race where two requests pass the check nearly simultaneously; test fixtures leaving a user with the same name in the DB; username case/whitespace differences not normalized.","solutions":["Choose a different username or instruct the user to log in instead of registering.","Check the user table (including soft-deleted rows) for the conflicting name and clean up if appropriate.","Trim/normalize the username client-side before submitting.","Add a unique constraint on username as a backstop against registration races."],"exampleFix":"// before\nu.Username = rawForm.Username // \" alice \" vs existing \"alice\"\n\n// after\nu.Username = strings.TrimSpace(rawForm.Username)\nif err := svc.Register(ctx, u); err != nil && strings.Contains(err.Error(), \"用户名已注册\") {\n    return fmt.Errorf(\"该用户名已被占用，请直接登录或更换用户名\")\n}","handlingStrategy":"try-catch","validationCode":"var existing system.SysUser\nif err := db.Where(\"username = ?\", username).First(&existing).Error; err == nil {\n    return errors.New(\"username already taken; choose another or log in\")\n}","typeGuard":null,"tryCatchPattern":"user, err := userService.Register(ctx, u)\nif err != nil {\n    if strings.Contains(err.Error(), \"用户名已注册\") {\n        http.Error(w, \"username already registered\", http.StatusConflict)\n        return\n    }\n    http.Error(w, err.Error(), http.StatusInternalServerError)\n}","preventionTips":["Check username availability in the UI before submission","Disable the submit button after the first click to prevent double posts","Trim and normalize usernames at registration","Add a DB unique constraint on username as a race backstop"],"tags":["duplicate","user-registration","validation","go"],"backgroundTag":"username-already-taken","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}