项目1 登录功能 day6(事务控制,实现登录注册功能,接口文档)

203 阅读8分钟

接口文档:

www.apifox.cn/apidoc/shared-7bff1720-a9e6-4bae-8fe8-abf60694ebc4

功能实现

  1. 图片验证码接口实现
  2. 登录接口实现
  3. 注册接口实现
  4. 改密接口完善
  5. 事务操作中间件
// 事务中间件,如果用户响应出错,则数据库回滚到响应之前的状态
func DBMid(db *sql.DB) gee7.HandlerFunc {
	return func(ctx *gee7.Context) {

		// 开始事务
		tx, err := db.Begin()
		if err != nil {
			ctx.FailJson(401, err.Error())
			return
		}

		// 调用下一个处理器
		ctx.Next()

		// 如果响应出现错误,回滚事务
		if ctx.StatusCode >= 400 {
			tx.Rollback()
			return
		}
		// 提交事务
		tx.Commit()
	}
}

接口实现:

log/main.go

//获取图片验证码
	r.GET("/verifypic", funcmod.Picverfi(db))
	//注册1,1. 图片验证,;2. 发送邮件验证码
	r.POST("/login1", func(ctx *gee7.Context) {
		data := funcmod.Login1data{}
		//读取用户传入的json数据
		err = ctx.Getjson(&data)
		if err != nil {
			ctx.FailJson(410, "解析数据错误"+err.Error())
			return
		}
		if funcmod.Validatedata(data.Email) {
			ctx.FailJson(402, "email不合理,请规范填写数据")
		}
		//验证图片验证码是否正确
		err = funcmod.Verifypiccode(db, data.PicID, data.PicCode)
		if err != nil {
			ctx.FailJson(401, "验证码错误"+err.Error())
			return
		}
		_, err = funcmod.GetuserId(db, data.Email)
		if err == nil {
			ctx.FailJson(410, "账号已经注册了")
			return
		}
		rand.Seed(time.Now().UnixNano())
		// 生成100000到999999之间的随机数,作为验证码
		verification := rand.Intn(899999) + 100000
		//储存验证码到数据库
		err = funcmod.InsertVerification(db, &funcmod.EmailVerificationCode{
			Email:        data.Email,
			Verification: verification})
		if err != nil {
			ctx.FailJson(401, "发送失败,稍后再试"+err.Error())
			return
		}
		//发送验证码
		err = funcmod.SendEmail(dailer, data.Email, verification)
		if err != nil {
			ctx.FailJson(401, "发送失败"+err.Error())
			return
		}

		ctx.JSON(200, gee7.H{
			"msg": "ok",
		})
	})
	//login2:1.验证验证码,;2. 向用户列表插入数据
	r.POST("/login2", func(ctx *gee7.Context) {
		data := funcmod.Logindata{}
		//读取用户传入的json数据
		err = ctx.Getjson(&data)
		if err != nil {
			ctx.FailJson(410, "解析数据错误"+err.Error())
			return
		}
		if funcmod.Validatedata(data.Name) {
			ctx.FailJson(402, "name不合理,请规范填写数据")
			return
		}
		if funcmod.Validatedata(data.Password) {
			ctx.FailJson(402, "password不合理,请规范填写数据")
			return
		}
		//验证用户验证码是否正确
		err = funcmod.Verify(db, data.Email, data.Verification)
		if err != nil {
			ctx.FailJson(401, "验证码错误"+err.Error())
			return
		}
		//插入用户数据
		id, err := funcmod.AddLogindata(db, &data)
		if err != nil {
			ctx.FailJson(401, err.Error())
		} else {
			// 添加操作信息
			err = funcmod.Addoperation(db, id, "注册成功")
			if err != nil {
				ctx.JSON(401, gee7.H{
					"msg": err.Error(),
				})
			} else {
				ctx.JSON(200, gee7.H{
					"msg": "成功",
				})
			}
		}
	})
	r.POST("/signuppsw", signup.SigninBypassword(db))
	r.POST("/signupemail1", signup.SigninByEmail1(db, dailer))
	r.POST("/signupemail2", signup.SigninByEmail2(db))
	//修改密码
	//密码改密
	r.POST("/resetpaswbypasw", funcmod.ResetpaswBypassword(db))
	//验证码改密
	r.POST("/resetpaswbyemail1", funcmod.ResetpaswByEmail1(db, dailer))
	r.POST("/resetpaswbyemail2", funcmod.ResetpaswByEmail2(db))

登录功能封装:

funcmod/signin.go

func SigninBypassword(db *sql.DB) gee7.HandlerFunc {
	return func(ctx *gee7.Context) {
		var data funcmod.Signupbypasw
		err := ctx.Getjson(&data)
		if err != nil {
			ctx.Fail(401, err.Error())
		}
		// 验证图片验证码是否正确
		err = funcmod.Verifypiccode(db, data.PicID, data.PicCode)
		if err != nil {
			ctx.FailJson(401, "验证码错误"+err.Error())
			return
		}
		//验证成功,获取id信息
		id, err := funcmod.GetuserId(db, data.Email)
		if err != nil {
			ctx.Fail(401, err.Error())
			return
		}
		// 验证登录密码
		err = funcmod.Verifypassword(db, id, data.Password)
		if err != nil {
			ctx.Fail(401, "密码错误:"+err.Error())
			return
		}
		//密码验证成功:
		idcode := uuid.New().String() //随机生成唯一标识符,作为身份码
		signindata := funcmod.SignInData{
			ID:     id,
			IDCode: idcode,
		}
		// 插入用户登录信息,登陆成功
		if err = funcmod.InsertSignInData(db, &signindata); err != nil {
			ctx.Fail(401, err.Error())
			funcmod.Addoperation(db, signindata.ID, "signin失败"+err.Error())
		} else {
			funcmod.Addoperation(db, signindata.ID, "signin成功")
			//登录成功返回id与身份码
			ctx.JSON(200, gee7.H{
				"signindata": signindata,
				"msg":        "ok",
			})
		}
	}
}

// 登录第一步:1. 图片验证,;2. 发送邮件验证码
func SigninByEmail1(db *sql.DB, dialer *gomail.Dialer) gee7.HandlerFunc {
	return func(ctx *gee7.Context) {
		data := funcmod.Signupbyemail1{}
		//读取用户传入的json数据
		err := ctx.Getjson(&data)
		if err != nil {
			ctx.FailJson(410, "解析数据错误"+err.Error())
			return
		}
		if funcmod.Validatedata(data.Email) {
			ctx.FailJson(402, "email不合理,请规范填写数据")
		}
		//验证图片验证码是否正确
		err = funcmod.Verifypiccode(db, data.PicID, data.PicCode)
		if err != nil {
			ctx.FailJson(401, "验证码错误"+err.Error())
			return
		}
		_, err = funcmod.GetuserId(db, data.Email)
		if err != nil {
			ctx.FailJson(410, "账号未注册注册,请先注册")
			return
		}
		rand.Seed(time.Now().UnixNano())
		// 生成100000到999999之间的随机数,作为验证码
		verification := rand.Intn(899999) + 100000
		//储存验证码到数据库
		err = funcmod.InsertVerification(db, &funcmod.EmailVerificationCode{
			Email:        data.Email,
			Verification: verification})
		if err != nil {
			ctx.FailJson(401, "发送失败,稍后再试"+err.Error())
			return
		}
		//发送验证码
		err = funcmod.SendEmail(dialer, data.Email, verification)
		if err != nil {
			ctx.FailJson(401, "邮箱错误"+err.Error())
			return
		}
		ctx.JSON(200, gee7.H{
			"msg": "ok",
		})
	}
}

// 完成验证码登录功能:验证验证码是否正确,插入数据
func SigninByEmail2(db *sql.DB) gee7.HandlerFunc {
	return func(ctx *gee7.Context) {
		var data funcmod.Signupbyemail2
		err := ctx.Getjson(&data)
		if err != nil {
			ctx.Fail(401, err.Error())
		}
		// 验证用户邮箱验证码是否正确
		err = funcmod.Verify(db, data.Email, data.Verification)
		if err != nil {
			ctx.FailJson(401, "验证码错误"+err.Error())
			return
		}
		//验证成功,获取id信息
		id, err := funcmod.GetuserId(db, data.Email)
		if err != nil {
			ctx.Fail(401, err.Error())
			return
		}
		idcode := uuid.New().String() //随机生成唯一标识符,作为身份码
		signindata := funcmod.SignInData{
			ID:     id,
			IDCode: idcode,
		}
		// 插入用户登录信息,登陆成功
		if err = funcmod.InsertSignInData(db, &signindata); err != nil {
			ctx.Fail(401, err.Error())
			funcmod.Addoperation(db, signindata.ID, "signin失败"+err.Error())
		} else {
			funcmod.Addoperation(db, signindata.ID, "signin成功")
			//登录成功返回id与身份码
			ctx.JSON(200, gee7.H{
				"signindata": signindata,
				"msg":        "ok",
			})
		}
	}
}

改密功能封装:+数据校验

 // 用于检验用户传入的数据是否合理
// 正则表达式,匹配长度为 8-50 的 ASCII 字符串
// 合理为false不合理为true
func Validatedata(password string) bool {
	regex := regexp.MustCompile(`^[[:ascii:]]{3,40}$`)
	return !regex.MatchString(password)
}
func ResetpaswBypassword(db *sql.DB) gee7.HandlerFunc {
	return func(ctx *gee7.Context) {
		data := ResetpaswData{}
		//读取用户传入的json数据
		err := ctx.Getjson(&data)
		if err != nil {
			ctx.FailJson(410, "解析数据错误"+err.Error())
			return
		}
		if Validatedata(data.Password) {
			ctx.FailJson(402, "password不合理,请规范填写数据")
			return
		}
		if Validatedata(data.Newpassword) {
			ctx.FailJson(402, "newpassword不合理,请规范填写数据")
			return
		}
		//身份验证
		err = SignInVerification(db, &data.SignInData)
		if err != nil {
			ctx.FailJson(401, err.Error())
			return
		}
		//验证密码
		err = Verifypassword(db, data.SignInData.ID, data.Password)
		if err != nil {
			ctx.FailJson(401, err.Error())
			return
		}
		//修改密码
		err = Changepassword(db, data.ID, data.Newpassword)
		if err != nil {
			ctx.FailJson(401, err.Error())
			return
		}
		// 添加操作信息
		err = Addoperation(db, data.ID, "改密成功")
		if err != nil {
			ctx.JSON(401, gee7.H{
				"msg": err.Error(),
			})
		}
		ctx.JSON(200, gee7.H{
			"msg": "ok",
		})
	}
}

// 验证改密第一步:1. 图片验证,;2. 发送邮件验证码
func ResetpaswByEmail1(db *sql.DB, dialer *gomail.Dialer) gee7.HandlerFunc {
	return func(ctx *gee7.Context) {
		data := ResetpaswbyemailData1{}
		//读取用户传入的json数据
		err := ctx.Getjson(&data)
		if err != nil {
			ctx.FailJson(410, err.Error())
		}

		//验证图片验证码是否正确
		err = Verifypiccode(db, data.PicID, data.PicCode)
		if err != nil {
			ctx.FailJson(401, "图片验证码错误"+err.Error())
			return
		}
		// 验证成功:获取用户邮箱
		emial, err := GetuserEmail(db, data.ID)
		if err != nil {
			ctx.FailJson(410, "未找到邮箱信息,请联系管理员"+err.Error())
		}
		rand.Seed(time.Now().UnixNano())
		// 生成100000到999999之间的随机数,作为验证码
		verification := rand.Intn(899999) + 100000
		//储存验证码到数据库
		err = InsertVerification(db, &EmailVerificationCode{
			Email:        emial,
			Verification: verification})
		if err != nil {
			ctx.FailJson(401, "发送失败,稍后再试"+err.Error())
			return
		}
		//发送验证码
		err = SendEmail(dialer, emial, verification)
		if err != nil {
			ctx.FailJson(401, "邮箱错误"+err.Error())
			return
		}
		ctx.JSON(200, gee7.H{
			"msg": "ok",
		})
	}
}

// 完成验证码改密功能:验证验证码是否正确,插入数据
func ResetpaswByEmail2(db *sql.DB) gee7.HandlerFunc {
	return func(ctx *gee7.Context) {
		var data ResetpaswbyemailData2
		err := ctx.Getjson(&data)
		if err != nil {
			ctx.Fail(401, err.Error())
		}
		if Validatedata(data.Newpassword) {
			ctx.FailJson(402, "password不合理,请规范填写数据")
			return
		}
		// 验证用户邮箱验证码是否正确
		err = Verify(db, data.Email, data.Verification)
		if err != nil {
			ctx.FailJson(401, "验证码错误"+err.Error())
			return
		}
		//验证成功,获取id信息
		id, err := GetuserId(db, data.Email)
		if err != nil {
			ctx.Fail(401, err.Error())
			return
		}
		//修改密码
		err = Changepassword(db, id, data.Newpassword)
		if err != nil {
			ctx.FailJson(401, err.Error())
			return
		}
		// 添加操作信息
		err = Addoperation(db, id, "改密成功")
		if err != nil {
			ctx.JSON(401, gee7.H{
				"msg": err.Error(),
			})
		}
		ctx.JSON(200, gee7.H{
			"msg": "ok",
		})
	}
}

所有文件代码

funcmod/data.go

封装请求与响应需要的数据类型

package funcmod

import "time"

// 邮箱验证码信息(验证码需要真人验证之后再发送)(登录时可以直接使用)
type EmailVerificationCode struct {
	Email        string `json:"email"`
	Verification int    `json:"verification"`
}

// 注册传入信息2,邮箱验证码信息+用户基本信息
type Logindata struct {
	EmailVerificationCode `json:"emailverificationcode"`
	Name                  string `json:"name"`
	Password              string `json:"password"`
}

// 注册传入信息1,id为图片的唯一标识符,code为用户传入 的图片验证码, Email为需要发送验证邮件的邮箱
type Login1data struct {
	PicID   string `json:"picid"`
	PicCode []byte `json:"piccode"`
	Email   string `json:"email"`
}

// 身份验证信息(id+身份码)
type SignInData struct {
	ID     int    `json:"id"`
	IDCode string `json:"idcode"`
}

// 操作信息列表
type OperationRecord struct {
	ID       int    `json:"id"`
	Behavior string `json:"behavior"`
	Time     int    `json:"time"`
}

// 改密接受信息
type ResetpaswData struct {
	SignInData  `json:"signindata"`
	Password    string `json:"password"`
	Newpassword string `json:"newpassword"`
}

// 改密接受信息1:图片验证+身份验证
type ResetpaswbyemailData1 struct {
	SignInData `json:"signindata"`
	PicID      string `json:"picid"`
	PicCode    []byte `json:"piccode"`
}

// 验证码验证+新密码
type ResetpaswbyemailData2 struct {
	EmailVerificationCode `json:"emailverificationcode"`
	Newpassword           string `json:"newpassword"`
}

// 验证码数据模型
type VerificationCode struct {
	PicID     string    `json:"picid"`
	PicCode   []byte    `json:"piccode"`
	Image     string    `json:"image"`
	CreatedAt time.Time `json:"created_at"`
}

// 密码登录信息(图片验证信息+邮箱+密码)
type Signupbypasw struct {
	PicID    string `json:"picid"`
	PicCode  []byte `json:"piccode"`
	Email    string `json:"email"`
	Password string `json:"password"`
}

// 发送验证码时上传的信息(图片验证信息+身份验证信息)
type Signupbyemail1 struct {
	PicID   string `json:"picid"`
	PicCode []byte `json:"piccode"`
	Email   string `json:"email"`
}

// 使用邮箱验证码登录时上传的信息(图片验证信息+身份验证信息)
type Signupbyemail2 struct {
	EmailVerificationCode
}

funcmod/sqloperate.go

封装所有的数据库操作

package funcmod

//对数据库操作的所有函数
import (
	"database/sql"
	"fmt"
	"time"
)

// 添加操作信息,向表OperationRecord(操作列表)添加
func Addoperation(db *sql.DB, id int, operation string) error {

	_, err := db.Exec("insert into OperationRecord (id,behavior,time) VALUES (?, ?, ?)", id, operation, time.Now().Unix())
	if err != nil {
		return err
	}
	return nil
}

// 获取:表OperationRecord(操作列表)的数据
func Getoperations(db *sql.DB, id int) ([]OperationRecord, error) {

	rows, err := db.Query("SELECT behavior, time FROM OperationRecord WHERE id = ?", id)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	result := []OperationRecord{}
	for rows.Next() {
		p := &OperationRecord{ID: id}
		err = rows.Scan(&p.Behavior, &p.Time)
		if err != nil {
			return result, err
		}
		result = append(result, *p)
	}
	if err := rows.Err(); err != nil {
		return result, err
	}
	return result, nil
}

// user表------------------------------------------------------------------

// add:向user(注册列表)添加元素
func AddLogindata(db *sql.DB, logindata *Logindata) (int, error) {

	r, err := db.Exec("insert into user (name,password,Email) VALUES (?, ?, ?)", logindata.Name, encryptPassword(logindata.Password), logindata.Email)
	if err != nil {
		return 0, err
	}
	id, err := r.LastInsertId()
	return int(id), err
}

// ((id是操作用的,不是给用户登录用的))
// get:获取:向user(注册列表)获取id,登陆成功,获取id
func GetuserId(db *sql.DB, email string) (int, error) {

	id := -1
	err := db.QueryRow("SELECT id FROM user WHERE Email = ?", email).Scan(&id)
	if err != nil {
		return -1, err
	}
	return id, nil
}

// get:获取:向user(注册列表)获取email(改密时查Email,不能由用户传入Email,)
func GetuserEmail(db *sql.DB, id int) (string, error) {

	Email := ""
	err := db.QueryRow("SELECT Email FROM user WHERE id = ?", id).Scan(&Email)
	if err != nil {
		return "", err
	}
	return Email, nil
}

// 查:验证user(注册列表)密码
func Verifypassword(db *sql.DB, id int, password string) error {

	count := 0
	err := db.QueryRow("SELECT COUNT(*) FROM user WHERE id = ? AND password = ? ", id, encryptPassword(password)).Scan(&count)
	if err != nil {
		return err
	}
	return nil
}

// 改:修改:user(注册列表)密码
func Changepassword(db *sql.DB, id int, newpassword string) error {

	_, err := db.Exec("UPDATE user SET password = ? WHERE id = ?", newpassword, id)
	if err != nil {
		return err
	}
	return nil
}

// -SignInlist--------------------------------------------------------------------

// 查:SignIn查询身份验证功能:传入SignInData
func SignInVerification(db *sql.DB, signInData *SignInData) error {

	// 查询身份认证码是否正确
	var expirationTime int64 //储存过期时间
	err := db.QueryRow("SELECT ExpirationTime FROM SignInList WHERE id = ? AND IDcode = ?", signInData.ID, signInData.IDCode).Scan(&expirationTime)
	if err != nil {
		return fmt.Errorf("非法访问")
	}

	// 验证身份认证码是否过期
	if time.Now().Unix() > expirationTime {
		return fmt.Errorf("身份验证过期,请重新登陆")
	}

	// 验证成功.更新身份认证码的过期时间
	_, err = db.Exec("UPDATE SignInList SET ExpirationTime = ? WHERE id = ? AND IDcode = ?", time.Now().Unix()+30*60, signInData.ID, signInData.IDCode)
	if err != nil {
		return err
	}
	return nil
}

// 增:向登录列表插入信息
func InsertSignInData(db *sql.DB, data *SignInData) error {

	// 准备SQL语句
	stmt, err := db.Prepare("REPLACE INTO SignInList (id, IDcode, ExpirationTime) VALUES (?, ?, ?)")
	if err != nil {
		return err
	}
	defer stmt.Close()

	// 执行插入操作
	result, err := stmt.Exec(data.ID, data.IDCode, time.Now().Unix()+30*60)
	if err != nil {
		return err
	}

	// 输出插入结果
	_, err = result.RowsAffected()
	if err != nil {
		return err
	}
	return nil
}

// delete:删除登录信息; 登出删除登录列表元素
func Deletesignindata(db *sql.DB, id int) error {
	_, err := db.Exec("DELETE FROM SignInList WHERE id = ?", id)
	if err != nil {
		return err
	}
	return nil
}

// VerificationCode(验证码储存库)----------------------------------------------------------

// 查: 验证验证码
func Verify(db *sql.DB, email string, verification int) error {

	// 查询验证码是否正确
	var expirationTime int64 //储存过期时间
	//代表已经验证过
	db.Exec("UPDATE VerificationCode SET password = ? WHERE Email = ?", 1, email)

	err := db.QueryRow("SELECT ExpirationTime FROM VerificationCode WHERE Email = ? AND Verification = ?", email, verification).Scan(&expirationTime)
	if err != nil {
		return fmt.Errorf("验证码错误" + err.Error())
	}

	// 验证身份认证码是否过期
	if time.Now().Unix() > expirationTime {
		return fmt.Errorf("过期")
	}
	return nil
}

// 增:验证码了列表插入信息
func InsertVerification(db *sql.DB, data *EmailVerificationCode) error {

	// 准备SQL语句

	stmt, err := db.Prepare("REPLACE INTO VerificationCode (Email, Verification, ExpirationTime, time) VALUES (?, ?, ?, ?)")
	if err != nil {
		return err
	}
	defer stmt.Close()

	// 执行插入操作
	_, err = stmt.Exec(data.Email, data.Verification, time.Now().Unix()+5*60, 0)
	if err != nil {
		return err
	}
	return nil
}

// get:获取:验证次数,重发验证码0无,1有
func GetuVerificationtime(db *sql.DB, email string) (int, error) {
	t := -1
	err := db.QueryRow("SELECT time FROM user WHERE Email = ?", email).Scan(&t)
	if err != nil {
		return -1, err
	}
	return t, nil
}

// // ----------------------------------------------------------
// func Insertuserdata(db *sql.DB, data Logindata) error {

// 	// 准备SQL语句

// 	stmt, err := db.Prepare("INSERT INTO user (Email, name, password) VALUES (?, ?, ?)")
// 	if err != nil {
// 		return err
// 	}
// 	defer stmt.Close()

//		// 执行插入操作
//		_, err = stmt.Exec(data.Email, data.Name, encryptPassword(data.Password))
//		if err != nil {
//			return err
//		}
//		return nil
//	}
//
// 图片验证码验证操作:用户传入图片id(唯一标识符发送图片信息时给的),+验证码
func Verifypiccode(db *sql.DB, id string, code []byte) error {
	var createdAt []uint8
	err := db.QueryRow("SELECT created_at FROM verification_codes WHERE id = ? AND code = ?", id, code).Scan(&createdAt)
	if err != nil {
		return err
	}
	created_ats := string(createdAt)
	created_at, err := time.Parse("2006-01-02 15:04:05", created_ats)
	if err != nil {
		return err
	}
	// 删除验证码
	db.Exec("DELETE FROM verification_codes WHERE id = ?", id)
	if time.Now().Unix() > created_at.Unix()+5*60 { //时效5分钟
		return fmt.Errorf("验证码过期")
	}
	return nil
}

func scanTime(v interface{}) (t time.Time, err error) {
	switch u := v.(type) {
	case time.Time:
		return u, nil
	case []byte:
		return time.Parse("2006-01-02 15:04:05", string(u))
	case string:
		return time.Parse("2006-01-02 15:04:05", u)
	default:
		return t, fmt.Errorf("unable to parse time: %v", v)
	}
}

opensql.go

打开数据库操作

package funcmod

import "database/sql"

// 打开数据库
func Opensql() (*sql.DB, error) {
	// 打开数据库连接
	return sql.Open("mysql", "xxx:xxxxx@tcp(127.0.0.1:3306)/login")
}

密码加密储存于查询

package funcmod

import (
	"crypto/sha256"
	"encoding/hex"
)

func encryptPassword(password string) string {
	// 将字符串类型的密码转换为字节类型
	passwordBytes := []byte(password)
	// 创建SHA-256哈希对象
	sha256Hash := sha256.New()
	// 将密码字节数据传入哈希对象
	sha256Hash.Write(passwordBytes)
	// 获取哈希值的字节数据
	hashBytes := sha256Hash.Sum(nil)
	// 将字节数据转换为十六进制字符串
	hashString := hex.EncodeToString(hashBytes)
	// 返回十六进制字符串类型的哈希值
	return hashString
}

定义部分中间件函数于操作函数(改密,检验用户输入,图片发送,登录状态检验)

package funcmod

import (
	"bytes"
	"database/sql"
	"encoding/base64"
	"fmt"
	"goweb/day7/gee7"
	"math/rand"
	"net/http"
	"regexp"
	"time"

	"github.com/dchest/captcha"
	"github.com/google/uuid"
	"gopkg.in/gomail.v2"
)

// 身份验证中间件(是否处于登录状态)
func Authentication(db *sql.DB) gee7.HandlerFunc {
	return func(ctx *gee7.Context) {

		var signInData SignInData
		err := ctx.Getjson(&signInData)
		if err != nil {
			ctx.Fail(401, err.Error())
		}
		if err = SignInVerification(db, &signInData); err != nil {
			ctx.Fail(401, "失败:"+err.Error())
		} else {
			ctx.String(200, "成功")
		}
	}
}

// 发送图片验证码图片中间件(用户提交请求时)
func Picverfi(db *sql.DB) gee7.HandlerFunc {
	return func(ctx *gee7.Context) {

		// 生成验证码
		id := uuid.New().String() //生成唯一标识符
		code := captcha.RandomDigits(4)
		img := captcha.NewImage(id, code, captcha.StdWidth, captcha.StdHeight)
		// 生成验证码
		var buf bytes.Buffer
		_, err := img.WriteTo(&buf)
		if err != nil {
			ctx.FailJson(401, "出错了,点击重试")
		}

		// 将验证码和图片存储到数据库中
		encodedImage := base64.StdEncoding.EncodeToString(buf.Bytes())
		verificationCode := VerificationCode{PicCode: code, Image: encodedImage, CreatedAt: time.Now()}
		_, err = db.Exec("INSERT INTO verification_codes (id, code, image, created_at) VALUES (?, ?, ?, ?)", id, verificationCode.PicCode, verificationCode.Image, verificationCode.CreatedAt)
		if err != nil {
			ctx.FailJson(http.StatusInternalServerError, "Internal Server Error:"+err.Error())
			return
		}

		// 返回图片与唯一标识符
		ctx.JSON(200, gee7.H{
			"picid": id,
			"png":   verificationCode.Image,
		})

		fmt.Printf("id=%#v\ncode=%d", id, code)
	}
}

// 用于检验用户传入的数据是否合理
// 正则表达式,匹配长度为 8-50 的 ASCII 字符串
// 合理为false不合理为true
func Validatedata(password string) bool {
	regex := regexp.MustCompile(`^[[:ascii:]]{3,40}$`)
	return !regex.MatchString(password)
}
func ResetpaswBypassword(db *sql.DB) gee7.HandlerFunc {
	return func(ctx *gee7.Context) {
		data := ResetpaswData{}
		//读取用户传入的json数据
		err := ctx.Getjson(&data)
		if err != nil {
			ctx.FailJson(410, "解析数据错误"+err.Error())
			return
		}
		if Validatedata(data.Password) {
			ctx.FailJson(402, "password不合理,请规范填写数据")
			return
		}
		if Validatedata(data.Newpassword) {
			ctx.FailJson(402, "newpassword不合理,请规范填写数据")
			return
		}
		//身份验证
		err = SignInVerification(db, &data.SignInData)
		if err != nil {
			ctx.FailJson(401, err.Error())
			return
		}
		//验证密码
		err = Verifypassword(db, data.SignInData.ID, data.Password)
		if err != nil {
			ctx.FailJson(401, err.Error())
			return
		}
		//修改密码
		err = Changepassword(db, data.ID, data.Newpassword)
		if err != nil {
			ctx.FailJson(401, err.Error())
			return
		}
		// 添加操作信息
		err = Addoperation(db, data.ID, "改密成功")
		if err != nil {
			ctx.JSON(401, gee7.H{
				"msg": err.Error(),
			})
		}
		ctx.JSON(200, gee7.H{
			"msg": "ok",
		})
	}
}

// 验证改密第一步:1. 图片验证,;2. 发送邮件验证码
func ResetpaswByEmail1(db *sql.DB, dialer *gomail.Dialer) gee7.HandlerFunc {
	return func(ctx *gee7.Context) {
		data := ResetpaswbyemailData1{}
		//读取用户传入的json数据
		err := ctx.Getjson(&data)
		if err != nil {
			ctx.FailJson(410, err.Error())
		}

		//验证图片验证码是否正确
		err = Verifypiccode(db, data.PicID, data.PicCode)
		if err != nil {
			ctx.FailJson(401, "图片验证码错误"+err.Error())
			return
		}
		// 验证成功:获取用户邮箱
		emial, err := GetuserEmail(db, data.ID)
		if err != nil {
			ctx.FailJson(410, "未找到邮箱信息,请联系管理员"+err.Error())
		}
		rand.Seed(time.Now().UnixNano())
		// 生成100000到999999之间的随机数,作为验证码
		verification := rand.Intn(899999) + 100000
		//储存验证码到数据库
		err = InsertVerification(db, &EmailVerificationCode{
			Email:        emial,
			Verification: verification})
		if err != nil {
			ctx.FailJson(401, "发送失败,稍后再试"+err.Error())
			return
		}
		//发送验证码
		err = SendEmail(dialer, emial, verification)
		if err != nil {
			ctx.FailJson(401, "邮箱错误"+err.Error())
			return
		}
		ctx.JSON(200, gee7.H{
			"msg": "ok",
		})
	}
}

// 完成验证码改密功能:验证验证码是否正确,插入数据
func ResetpaswByEmail2(db *sql.DB) gee7.HandlerFunc {
	return func(ctx *gee7.Context) {
		var data ResetpaswbyemailData2
		err := ctx.Getjson(&data)
		if err != nil {
			ctx.Fail(401, err.Error())
		}
		if Validatedata(data.Newpassword) {
			ctx.FailJson(402, "password不合理,请规范填写数据")
			return
		}
		// 验证用户邮箱验证码是否正确
		err = Verify(db, data.Email, data.Verification)
		if err != nil {
			ctx.FailJson(401, "验证码错误"+err.Error())
			return
		}
		//验证成功,获取id信息
		id, err := GetuserId(db, data.Email)
		if err != nil {
			ctx.Fail(401, err.Error())
			return
		}
		//修改密码
		err = Changepassword(db, id, data.Newpassword)
		if err != nil {
			ctx.FailJson(401, err.Error())
			return
		}
		// 添加操作信息
		err = Addoperation(db, id, "改密成功")
		if err != nil {
			ctx.JSON(401, gee7.H{
				"msg": err.Error(),
			})
		}
		ctx.JSON(200, gee7.H{
			"msg": "ok",
		})
	}
}

发送邮件功能

package funcmod

import (
	"fmt"

	"gopkg.in/gomail.v2"
)

// 使用gomail库创建SMTP客户端
func CreatDialer() *gomail.Dialer {
	return gomail.NewDialer("smtp.qq.com", 465, "xxxxxxxxx", "xxxxxxx") //AuthCode为邮箱的授权码
}

func SendEmail(dialer *gomail.Dialer, to string, verification int) error {
	// 发送邮件的QQ邮箱地址
	qqEmail := "xxxxxxxxxxxxx"

	// 创建邮件消息
	message := gomail.NewMessage()
	message.SetHeader("From", qqEmail)
	message.SetHeader("To", to)
	message.SetHeader("Subject", "验证码")
	message.SetBody("text/plain", fmt.Sprintf("验证码:%d", verification))

	// 发送邮件消息
	err := dialer.DialAndSend(message)
	if err != nil {
		panic(err)
	}
	return nil
}

main.go

所有功能接口实现

package main

import (
	"fmt"
	"goweb/day7/gee7"
	"goweb/logindata/funcmod"
	"goweb/logindata/signup"
	"math/rand"
	"time"
)

func main() {
	r := gee7.New()
	db, err := funcmod.Opensql()
	if err != nil {
		fmt.Printf("数据库出错=%#v\n", err)
		return
	}
	defer db.Close()
	r.Use(funcmod.DBMid(db))
	//连接邮箱
	dailer := funcmod.CreatDialer()
	//获取图片验证码
	r.GET("/verifypic", funcmod.Picverfi(db))
	//注册1,1. 图片验证,;2. 发送邮件验证码
	r.POST("/login1", func(ctx *gee7.Context) {
		data := funcmod.Login1data{}
		//读取用户传入的json数据
		err = ctx.Getjson(&data)
		if err != nil {
			ctx.FailJson(410, "解析数据错误"+err.Error())
			return
		}
		if funcmod.Validatedata(data.Email) {
			ctx.FailJson(402, "email不合理,请规范填写数据")
		}
		//验证图片验证码是否正确
		err = funcmod.Verifypiccode(db, data.PicID, data.PicCode)
		if err != nil {
			ctx.FailJson(401, "验证码错误"+err.Error())
			return
		}
		_, err = funcmod.GetuserId(db, data.Email)
		if err == nil {
			ctx.FailJson(410, "账号已经注册了")
			return
		}
		rand.Seed(time.Now().UnixNano())
		// 生成100000到999999之间的随机数,作为验证码
		verification := rand.Intn(899999) + 100000
		//储存验证码到数据库
		err = funcmod.InsertVerification(db, &funcmod.EmailVerificationCode{
			Email:        data.Email,
			Verification: verification})
		if err != nil {
			ctx.FailJson(401, "发送失败,稍后再试"+err.Error())
			return
		}
		//发送验证码
		err = funcmod.SendEmail(dailer, data.Email, verification)
		if err != nil {
			ctx.FailJson(401, "发送失败"+err.Error())
			return
		}

		ctx.JSON(200, gee7.H{
			"msg": "ok",
		})
	})
	//login2:1.验证验证码,;2. 向用户列表插入数据
	r.POST("/login2", func(ctx *gee7.Context) {
		data := funcmod.Logindata{}
		//读取用户传入的json数据
		err = ctx.Getjson(&data)
		if err != nil {
			ctx.FailJson(410, "解析数据错误"+err.Error())
			return
		}
		if funcmod.Validatedata(data.Name) {
			ctx.FailJson(402, "name不合理,请规范填写数据")
			return
		}
		if funcmod.Validatedata(data.Password) {
			ctx.FailJson(402, "password不合理,请规范填写数据")
			return
		}
		//验证用户验证码是否正确
		err = funcmod.Verify(db, data.Email, data.Verification)
		if err != nil {
			ctx.FailJson(401, "验证码错误"+err.Error())
			return
		}
		//插入用户数据
		id, err := funcmod.AddLogindata(db, &data)
		if err != nil {
			ctx.FailJson(401, err.Error())
		} else {
			// 添加操作信息
			err = funcmod.Addoperation(db, id, "注册成功")
			if err != nil {
				ctx.JSON(401, gee7.H{
					"msg": err.Error(),
				})
			} else {
				ctx.JSON(200, gee7.H{
					"msg": "成功",
				})
			}
		}
	})
	r.POST("/signuppsw", signup.SigninBypassword(db))
	r.POST("/signupemail1", signup.SigninByEmail1(db, dailer))
	r.POST("/signupemail2", signup.SigninByEmail2(db))
	//修改密码
	//密码改密
	r.POST("/resetpaswbypasw", funcmod.ResetpaswBypassword(db))
	//验证码改密
	r.POST("/resetpaswbyemail1", funcmod.ResetpaswByEmail1(db, dailer))
	r.POST("/resetpaswbyemail2", funcmod.ResetpaswByEmail2(db))
	// 登出
	r.POST("/signout", func(ctx *gee7.Context) {
		data := funcmod.SignInData{}
		//读取用户传入的json数据
		err = ctx.Getjson(&data)
		if err != nil {
			ctx.FailJson(410, "解析数据错误"+err.Error())
			return
		}
		//身份验证
		err = funcmod.SignInVerification(db, &data)
		if err != nil {
			ctx.FailJson(401, err.Error())
			return
		}
		//删除登录列表信息
		err = funcmod.Deletesignindata(db, data.ID)
		if err != nil {
			ctx.JSON(401, gee7.H{
				"msg": err.Error(),
			})
		}
		err = funcmod.Addoperation(db, data.ID, "登出成功")
		if err != nil {
			ctx.JSON(401, gee7.H{
				"msg": err.Error(),
			})
		} else {
			ctx.JSON(200, gee7.H{
				"msg": "ok",
			})
		}
	})
	// 获取操作信息
	r.POST("/getoperations", func(ctx *gee7.Context) {
		data := funcmod.SignInData{}
		//读取用户传入的json数据
		err = ctx.Getjson(&data)
		if err != nil {
			ctx.FailJson(410, "解析数据错误"+err.Error())
			return
		}

		err = funcmod.SignInVerification(db, &data)
		if err != nil {
			ctx.FailJson(401, err.Error())
			return
		}
		r, err := funcmod.Getoperations(db, data.ID)
		if err != nil {
			ctx.FailJson(401, err.Error())
			return
		}
		ctx.JSON(200, gee7.H{
			"operations": r,
			"msg":        "ok",
		})
	})

	
	r.Run(":8888")
}

本文由mdnice多平台发布