(三)登录和注册(handle_auto.go)

登录和注册(handle_auto.go)

在这里插入图片描述

文章目录

  • 登录和注册(handle_auto.go)
    • 一、所需要的结构体信息
    • 二、注册
    • 三、登录
    • 四、退出

一、所需要的结构体信息

type UserAuth struct{}type LoginReq struct {Username string `json:"username" binding:"required"`Password string `json:"password" binding:"required"`
}type RegisterReq struct {Username string `json:"username" binding:"required"`Password string `json:"password" binding:"required,min=4,max=20"`Code     string `json:"code" binding:"required"`
}type LoginVO struct {model.UserInfo// 点赞 Set: 用于记录用户点赞过的文章, 评论ArticleLikeSet []string `json:"article_like_set"`CommentLikeSet []string `json:"comment_like_set"`Token          string   `json:"token"`
}

二、注册

因为原本的作者没有写注册的功能,我就自己写了一个简单的注册功能。

1.注册的路由

base.POST("/register", userAuthAPI.Register)    // 注册

2.验证码的功能函数

handler层的函数

  • 使用qq邮箱发送验证
  • 限制发送时间
  • 使用redis存储验证码,时间1分钟
func (*UserAuth) SendCode(c *gin.Context) {// 发送验证码限制于1分钟发一次elapsedTime := time.Since(lastEmailSent)remaingTime := time.Minute - elapsedTimeif elapsedTime < time.Minute {c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("发送验证码过于频繁,请稍后再试,剩余时间:%d秒", int(remaingTime.Seconds()))})return}// 从请求参数中获取邮箱地址email := c.Query("email")if email == "" {c.JSON(http.StatusBadRequest, gin.H{"error": "未提供邮箱地址"})return}// 发送邮件验证码err := SendEmail(email, c)if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": "发送邮件失败"})return}// 发送邮件成功,返回成功响应给前端lastEmailSent = time.Now()ReturnSuccess(c, "验证码发送成功")
}// 发送邮件到指定邮箱
func SendEmail(email string, c *gin.Context) error {// 邮箱配置信息config := gomail.NewDialer("smtp.qq.com", 465, "xxx@qq.com", "自己的授权码")//config.TLSConfig.ServerName = "smtp.qq.com"//config.TLSConfig.InsecureSkipVerify = false// 创建邮件内容message := gomail.NewMessage()message.SetHeader("From", "xxx@qq.com")message.SetHeader("To", email)message.SetHeader("Subject", "验证码")// 获取随机验证码computing := utils2.GetRandNums(6)message.SetBody("text/html", fmt.Sprintf("欢迎使用席万里的博客系统,这是您的注册验证码:%s", computing))// 连接并发送邮件dialer, err := config.Dial()if err != nil {return err}defer dialer.Close()if err = gomail.Send(dialer, message); err != nil {return err}// 将验证码存到redis中,确保输入的是正确的rdb := GetRDB(c)// 以email为key,mima为val存入redis,只存在1分钟rdb.Set(rctx, email, computing, time.Minute)return nil
}

3.注册的主功能函数

  • 用到了密码加密
  • 随机验证码的生成
  • 数据的写入
func (*UserAuth) Register(c *gin.Context) {var req RegisterReqif err := c.ShouldBindJSON(&req); err != nil {ReturnError(c, g2.ErrRequest, err)return}db := GetDB(c)rdb := GetRDB(c)// 检查邮箱是否已经被注册_, err := model.GetUserAuthInfoByName(db, req.Username)if err != nil {if !errors.Is(err, gorm.ErrRecordNotFound) {ReturnError(c, g2.ErrDbOp, err)return}} else {ReturnError(c, g2.ErrMailAleradyUsed, "邮箱已经被使用")return}// 取出来验证码码做判断 看是否正确computing, err := rdb.Get(rctx, req.Username).Result()if err != nil {// 处理获取验证码失败的情况ReturnError(c, g2.FailResult, err)return}// 如果验证码不正确,则返回错误信息if computing != req.Code {ReturnError(c, g2.ErrVerificationCode, "验证码错误")return}// 将密码加密hashpassword, _ := utils2.BcryptHash(req.Password)err = model.RegisterDB(db, req.Username, hashpassword)if err != nil {ReturnError(c, g2.ErrDbOp, "注册失败")}ReturnSuccess(c, "注册成功")
}

4.数据库层的邮箱查重函数

func GetUserAuthInfoByName(db *gorm.DB, name string) (*UserAuth, error) {var userAuth UserAuthresult := db.Where(&UserAuth{Username: name}).First(&userAuth)return &userAuth, result.Error
}

5.数据查入、生成随机验证码、mimajiammi

// 数据查入
// 用户注册 用户名,密码
func RegisterDB(db *gorm.DB, username, hashpassword string) error {// 创建新用户认证信息newUserAuth := &UserAuth{Model: Model{CreatedAt: time.Now(),UpdatedAt: time.Now(),},Username: username,Password: hashpassword,}// 保存新用户认证信息到数据库if err := db.Create(newUserAuth).Error; err != nil {return err}return nil
}
// 生成随机验证码
func GetRandNums(digits int) string {rand.Seed(time.Now().UnixNano())numeric := [10]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}var sb strings.Builderfor i := 0; i < digits; i++ {fmt.Fprintf(&sb, "%d", numeric[rand.Intn(len(numeric))])}return sb.String()
}// 密码加密
func BcryptHash(str string) (string, error) {bytes, err := bcrypt.GenerateFromPassword([]byte(str), bcrypt.DefaultCost)return string(bytes), err
}

三、登录

登录功能也用到了查重,校验密码hash等功能,这里不在讲述。

  • 生成jwt token
  • 使用MD5加密
  • 使用Session存储认证ID
  • 使用Redis存储在线信息
func (*UserAuth) Login(c *gin.Context) {var req LoginReqif err := c.ShouldBindJSON(&req); err != nil {ReturnError(c, g2.ErrRequest, err)return}db := GetDB(c)rdb := GetRDB(c)userAuth, err := model.GetUserAuthInfoByName(db, req.Username)if err != nil {if errors.Is(err, gorm.ErrRecordNotFound) {ReturnError(c, g2.ErrUserNotExist, nil)return}ReturnError(c, g2.ErrDbOp, err)return}// 检查密码是否正确if !utils2.BcryptCheck(req.Password, userAuth.Password) {ReturnError(c, g2.ErrPassword, nil)return// 获取 IP 相关信息 FIXME: 好像无法读取到 ip 信息ipAddress := utils2.IP.GetIpAddress(c)ipSource := utils2.IP.GetIpSourceSimpleIdle(ipAddress)userInfo, err := model.GetUserInfoById(db, userAuth.UserInfoId)if err != nil {if errors.Is(err, gorm.ErrRecordNotFound) {ReturnError(c, g2.ErrUserNotExist, nil)return}ReturnError(c, g2.ErrDbOp, err)return}roleIds, err := model.GetRoleIdsByUserId(db, userAuth.ID)if err != nil {ReturnError(c, g2.ErrDbOp, err)return}articleLikeSet, err := rdb.SMembers(rctx, g2.ARTICLE_USER_LIKE_SET+strconv.Itoa(userAuth.ID)).Result()if err != nil {ReturnError(c, g2.ErrDbOp, err)return}commentLikeSet, err := rdb.SMembers(rctx, g2.COMMENT_USER_LIKE_SET+strconv.Itoa(userAuth.ID)).Result()if err != nil {ReturnError(c, g2.ErrDbOp, err)return}// 登录信息正确, 生成 Token// UUID 生成方法: ip + 浏览器信息 + 操作系统信息// uuid := utils.MD5(ipAddress + browser + os)conf := g.Conf.JWTtoken, err := jwt.GenToken(conf.Secret, conf.Issuer, int(conf.Expire), userAuth.ID, roleIds)if err != nil {ReturnError(c, g2.ErrTokenCreate, err)return}// 更新用户验证信息: ip 信息 + 上次登录时间err = model.UpdateUserLoginInfo(db, userAuth.ID, ipAddress, ipSource)if err != nil {ReturnError(c, g2.ErrDbOp, err)return}slog.Info("用户登录成功: " + userAuth.Username)session := sessions.Default(c)session.Set(g2.CTX_USER_AUTH, userAuth.ID)session.Save()// 删除 Redis 中的离线状态offlineKey := g2.OFFLINE_USER + strconv.Itoa(userAuth.ID)rdb.Del(rctx, offlineKey).Result()ReturnSuccess(c, LoginVO{UserInfo: *userInfo,ArticleLikeSet: articleLikeSet,CommentLikeSet: commentLikeSet,Token:          token,})
}

1.use Redis 缓存用户收藏和喜欢的文章

	articleLikeSet, err := rdb.SMembers(rctx, g2.ARTICLE_USER_LIKE_SET+strconv.Itoa(userAuth.ID)).Result()if err != nil {ReturnError(c, g2.ErrDbOp, err)return}commentLikeSet, err := rdb.SMembers(rctx, g2.COMMENT_USER_LIKE_SET+strconv.Itoa(userAuth.ID)).Result()if err != nil {ReturnError(c, g2.ErrDbOp, err)return}

四、退出

func (*UserAuth) Logout(c *gin.Context) {c.Set(g2.CTX_USER_AUTH, nil)// 已经退出登录auth, _ := CurrentUserAuth(c)if auth == nil {ReturnSuccess(c, nil)return}session := sessions.Default(c)session.Delete(g2.CTX_USER_AUTH)session.Save()// 删除 Redis 中的在线状态rdb := GetRDB(c)onlineKey := g2.ONLINE_USER + strconv.Itoa(auth.ID)rdb.Del(rctx, onlineKey)ReturnSuccess(c, nil)
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/651104.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

三维图形学知识分享---求平面与模型相交线

在CGAL&#xff08;Computational Geometry Algorithms Library&#xff09;中&#xff0c;Polygon_mesh_processing模块提供了用于处理多边形网格数据结构的功能。其中&#xff0c;surface_intersection函数是用来计算模型的表面相交线的工具。 CGAL_Mesh mesh_orcl;std::vect…

AI大模型探索之路-训练篇1:大语言模型微调基础认知

文章目录 前言一、微调技术概述二、微调的必要性三、大模型的微调方法四、微调过程中的技术细节五、微调后的模型评估与应用总结 前言 在人工智能的广阔研究领域内&#xff0c;大型预训练语言模型&#xff08;Large Language Models, LLMs&#xff09;已经成为推动技术革新的关…

Linux网络—DNS域名解析服务

目录 一、BIND域名服务基础 1、DNS系统的作用及类型 DNS系统的作用 DNS系统类型 DNS域名解析工作原理&#xff1a; DNS域名解析查询方式&#xff1a; 2、BIND服务 二、使用BIND构建域名服务器 1、构建主、从域名服务器 1&#xff09;主服务器配置&#xff1a; 2&…

竞赛课第九周(埃式筛法,矩阵乘法)

1.埃式筛法:求区间[2, n]内所有的素数对 【参考代码】 #include <bits/stdc.h> using namespace std;const int N 1e5; vector<int> prime; bool visit[N];int main() {int n;cin>>n;memset(visit, false, sizeof(visit));for(int i2; i<sqrt(n); i){i…

Datasophon1.2.1集成Dinky1.0.1

Dinky 下载地址: https://github.com/DataLinkDC/dinky/releases/tag/v1.0.1 Dinky 官网&#xff1a;https://www.dinky.org.cn/ 1.下载Dinky wget https://github.com/DataLinkDC/dinky/releases/download/v1.0.1/dinky-release-1.16-1.0.1.tar.gz mv dinky-release-1.16-1.…

分享8款安全监控/日志记录工具

安全监控工具的作用是实时监控和分析系统的安全状态&#xff0c;而日志记录工具的作用主要是记录系统的运行过程及异常信息。 关于安全监控工具&#xff0c;它通过对计算机系统、网络、应用程序和数据进行实时监控和分析&#xff0c;帮助发现和防止安全威胁和攻击。这种监控不…

tcp inflight 守恒算法背后的哲学

tcp inflight 守恒拥塞控制的正确性 很久以前我开始纠结 tcp 锯齿&#xff0c;很多年后我知道这叫 capacity-seeking&#xff0c;甚至说 tcp 属于 capacity-seeking protocol 的原因就是它早已深入人心的 aimd 行为&#xff0c;而该行为生成了 tcp 锯齿。 在消除锯齿&#xf…

您的计算机已被rmallox勒索病毒感染?恢复您的数据的方法在这里!

引言&#xff1a; 在当今数字化时代&#xff0c;网络安全问题日益突出&#xff0c;其中勒索病毒作为一种新型的网络威胁&#xff0c;正逐渐引起人们的广泛关注。其中&#xff0c;.rmallox勒索病毒作为近期出现的一种新型恶意软件&#xff0c;给个人和企业带来了巨大的经济损失…

Open CASCADE学习|一个点的坐标变换

gp_Trsf 类是 Open CASCADE Technology (OCCT) 软件库中的一个核心类&#xff0c;用于表示和操作三维空间中的变换。以下是该类的一些关键成员和方法的介绍&#xff1a; 成员变量&#xff1a; scale: Standard_Real 类型&#xff0c;表示变换的缩放因子。 shape: gp_TrsfFor…

利用Spring Boot后端与Vue前端技术构建现代化电商平台

作者介绍&#xff1a;✌️大厂全栈码农|毕设实战开发&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。 &#x1f345;获取源码联系方式请查看文末&#x1f345; 推荐订阅精彩专栏 &#x1f447;&#x1f3fb; 避免错过下次更新 Springboot项目精选实战案例 更多项目…

【程序分享1】LAMMPS + OVITO + 晶体缺陷识别 + 点缺陷 + 分子动力学模拟

分享2个分子动力学模拟相关的程序。 1. 一种识别体心立方晶体缺陷的新方法。 2. 无后处理的分子动力学模拟中的并行点缺陷识别: lammps的计算和转储方式 。 感谢论文的原作者&#xff01; 第1个程序 关键词&#xff1a; 1. Atomistic simulations, 2. Molecular dynamics…

JSON六种值类型的写法

JSON&#xff08;JavaScript Object Notation&#xff09;是一种人类可读的文本数据格式。它源于JavaScript&#xff0c;标准开放&#xff0c;格式要求更为严格&#xff0c;独立于具体编程语言&#xff0c;常用于数据交换。 列举一段JSON数据&#xff0c;解释JSON六种值类型的…