实例:登录注册

登陆注册

1.介绍

web中最基础的功能就是登陆注册,接下来我们利用gin实现一个简单的注册登陆功能。

1.1.注册

注册的流程大致为:

填写账号密码等信息->提交信息->服务端接收数据->参数校验->检查是否已经注册->密码加密->数据持久化到数据库->注册成功

1.2.登陆

登陆的流程大致为:

填写账号密码等信息->提交信息->服务端接收数据->参数校验->检查账号密码是否正确->登陆成功

2.编码实现

  • 新建模型,这里直接使用数据操作章节使用的User模型
type User struct {
	ID        uint `gorm:"primary_key"`
	Username string
	Password string
}
  • 新建一个UserDto,用于数据传输使用

dto/user_dto.go

package dto

type UserDto struct {
	ID        uint
	Username string
	Password string
}
  • 使用数据操作章节的user_repository.go作为数据操作

repositories/user/user_repository.go

package user

import (
	"cn.sockstack/gin_demo/dto"
	"cn.sockstack/gin_demo/models"
)

//CreateUser 创建用户
func CreateUser(dto dto.UserDto) error {
	user := models.User{}
	user.Username = dto.Username
	user.Password = dto.Password

	err := models.DB.Create(&user).Error

	return err
}

//GetUserByUsername 通过用户名查询用户
func GetUserByUsername(username string) models.User {
	user := models.User{}
	models.DB.Find(&user, models.DB.Where("username = ?",username))

	return user
}

//UpdateUser 更新用户信息
func UpdateUser(userDto dto.UserDto) error {
	user := models.User{}
	if userDto.Username != "" {
		user.Username = userDto.Username
	}

	if userDto.Password != "" {
		user.Password = userDto.Password
	}

	err := models.DB.Model(&user).Update(&user).Error

	return err
}

//DeleteUserById 通过Id删除用户
func DeleteUserById(id uint) error {
	err := models.DB.Delete(&models.User{ID: id}).Error
	return err
}
  • 用户接口

services/user/user_contract.go

package user

import "cn.sockstack/gin_demo/dto"

type UserContract interface {
	Register(dto dto.UserDto) error
	Login(dto dto.UserDto) error
}

  • 用户服务

services/user/user_service.go

package user

import (
	"cn.sockstack/gin_demo/dto"
	"cn.sockstack/gin_demo/pkg/hash"
	user2 "cn.sockstack/gin_demo/repositories/user"
	"errors"
)

type UserService struct {
}

//Register 注册
func (user UserService) Register(userDto dto.UserDto) error {
	//密码加密
	bytes, err := hash.NewHash().Make([]byte(userDto.Password))
	if err != nil {
		return errors.New(err.Error())
	}
	userDto.Password = string(bytes)
	return user2.CreateUser(userDto)
}

//Login 登陆
func (user UserService)Login(userDto dto.UserDto) error {
	model := user2.GetUserByUsername(userDto.Username)
	if model.ID == 0 {
		return errors.New("账号不存在")
	}

	err := hash.NewHash().Check([]byte(model.Password), []byte(userDto.Password))
	if err != nil {
		return errors.New("密码错误")
	}

	return nil
}
  • 登陆注册入参定义

requests/v1/user.go

package v1

//RegisterRequest 注册入参
type RegisterRequest struct {
	Username string `form:"username" binding:"required"`
	Password string `form:"password" binding:"required"`
}

//LoginRequest 登陆入参
type LoginRequest struct {
	Username string `form:"username" binding:"required"`
	Password string `form:"password" binding:"required"`
}
  • 用户控制器

api/user/v1/user.go

package v1

import (
	"cn.sockstack/gin_demo/dto"
	"cn.sockstack/gin_demo/pkg/e"
	v1 "cn.sockstack/gin_demo/requests/v1"
	"cn.sockstack/gin_demo/services/user"
	"github.com/gin-gonic/gin"
)

//RegisterHandle 注册
func RegisterHandle(c *gin.Context) (interface{}, error) {
	request := v1.RegisterRequest{}

	err := c.ShouldBind(&request)
	if err != nil {
		return nil, e.ApiError{
			Status:  422,
			Code:    40004,
			Message: "参数校验失败",
			Data: err,
		}
	}

	userDto := dto.UserDto{
		Username: request.Username,
		Password: request.Password,
	}

	service := user.UserService{}
	err = service.Register(userDto)
	if err != nil {
		return nil, e.ApiError{
			Status:  422,
			Code:    40005,
			Message: err.Error(),
		}
	}

	return "注册成功", nil
}

//LoginHandle 登陆
func LoginHandle(c *gin.Context) (interface{}, error) {
	request := v1.LoginRequest{}

	err := c.ShouldBind(&request)
	if err != nil {
		return nil, e.ApiError{
			Status:  422,
			Code:    40004,
			Message: "参数校验失败",
			Data: err,
		}
	}

	userDto := dto.UserDto{
		Username: request.Username,
		Password: request.Password,
	}

	service := user.UserService{}
	err = service.Login(userDto)

	if err != nil {
		return nil, e.ApiError{
			Status:  422,
			Code:    40005,
			Message: err.Error(),
		}
	}

	return "登陆成功", nil
}
  • 定义路由

routers/v1/user.go

package v1

import (
	v1 "cn.sockstack/gin_demo/api/v1"
	"cn.sockstack/gin_demo/pkg/e"
	"github.com/gin-gonic/gin"
)

func UserRouter(r *gin.Engine)  {
	//注册
	r.POST("/register", e.ErrorWrapper(v1.RegisterHandle))

	//登陆
	r.POST("/login", e.ErrorWrapper(v1.LoginHandle))
}

3.总结

这个简单的例子中,使用了前面学到的所有知识点,比较简单,但是可以基于该例子整合其他功能,类型:验证码,限流,jwt等。