从4开始,在后端系统中增加用户注册和登录功能
Posted BarryYan_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从4开始,在后端系统中增加用户注册和登录功能相关的知识,希望对你有一定的参考价值。
本次我们接着上四篇文章进行讲解《从0开始,用Go语言搭建一个简单的后端业务系统》、《从1开始,扩展Go语言后端业务系统的RPC功能》、《从2开始,在Go语言后端业务系统中引入缓存》以及《从3开始,在业务系统中增加分页功能》,这次是系统中比较核心的功能——用户登录&注册,这个功能其实本应该是最先实现的,但是由于不同因素的影响,放到了本次进行实现,不过也无伤大雅,后期我们都会不断的进行查漏补缺和优化来使我们的项目总体上更加优雅,话不多说,我们开始正文:
1 用户注册&登录流程
(1)注册流程
(2)登录流程
2 代码实现
user结构:
package model
import (
"encoding/json"
)
type User struct
Id int64 `json:"id"`
Name string `json:"name"`
LoginName string `json:"login_name"`
Role int64 `json:"role"`
Pwd string `json:"pwd"`
CreateTime string `json:"create_time"`
func (user User) TableName() string
return "user_info"
func (user User) MarshalJSON() ([]byte, error)
return json.Marshal(map[string]interface
"id": user.Id,
"name": user.Name,
"login_name": user.LoginName,
"role": user.Role,
"pwd": user.Pwd,
"create_time": user.CreateTime,
)
//Redis类似序列化操作
func (user User) MarshalBinary() ([]byte, error)
return json.Marshal(user)
func (user User) UnmarshalBinary(data []byte) error
return json.Unmarshal(data, &user)
dao层代码:
package dao
import (
"context"
"count_num/pkg/model"
)
type UserDao interface
// 添加一个
CreateUser(ctx context.Context, user model.User) bool
// 根据ID查找一个
GetUserByUid(ctx context.Context, uId int64) model.User
// 查找全部
GetAll(ctx context.Context, page int, limit int) []model.User
// 根据ID修改一个
UpdateUserById(ctx context.Context, user model.User) bool
// 根据登录名查找一个
GetUserByLoginName(ctx context.Context, loginName string) model.User
dao层实现:
package impl
import (
"context"
"count_num/pkg/cache"
"count_num/pkg/config"
"count_num/pkg/model"
"count_num/pkg/utils"
"gorm.io/gorm"
)
type UserDaoImpl struct
db *gorm.DB
cache *cache.CountNumCacheDAOImpl
func NewUserDaoImpl() *UserDaoImpl
return &UserDaoImpldb: config.DB, cache: cache.NewCountNumCacheDAOImpl()
func (impl *UserDaoImpl) CreateUser(ctx context.Context, user model.User) bool
var u model.User
impl.db.First(&u, "login_name", user.LoginName)
if u.LoginName == user.LoginName
return false
user.Pwd = utils.GetMd5Str(user.Pwd)
user.CreateTime = utils.NowTimeStr()
impl.db.Save(&user)
return true
func (impl *UserDaoImpl) GetUserByUid(ctx context.Context, uId int64) model.User
var user model.User
impl.db.First(&user, "id", uId)
return user
func (impl *UserDaoImpl) GetAll(ctx context.Context, page int, limit int) []model.User
users := make([]model.User, 0)
if page <= 0 || limit <= 0
impl.db.Find(&users)
else
impl.db.Limit(limit).Offset((page - 1) * limit).Find(&users)
return users
func (impl *UserDaoImpl) UpdateUserById(ctx context.Context, user model.User) bool
impl.db.Model(&model.User).Where("id = ?", user.Id).Updates(user)
return true
func (impl *UserDaoImpl) GetUserByLoginName(ctx context.Context, loginName string) model.User
var user model.User
impl.db.First(&user, "login_name", loginName)
return user
工具方法,用于生成token和MD5加密:
package utils
import (
"bytes"
"crypto/md5"
"encoding/gob"
"encoding/hex"
"math/rand"
"strings"
"time"
)
func GetMd5Str(str string) string
md5 := md5.New()
var buf bytes.Buffer
gob.NewEncoder(&buf).Encode(str)
md5.Write(buf.Bytes())
return hex.EncodeToString(md5.Sum(nil))
func GetTokenStr() string
char := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
charArr := strings.Split(char, "")
c := len(charArr)
ran := rand.New(rand.NewSource(time.Now().Unix()))
var str string = ""
for i := 1; i <= 18; i++
str = str + charArr[ran.Intn(c)]
return str
工具方法:
package utils
import (
"time"
)
// NowTimeStr return 2022-01-21 12:21:31
func NowTimeStr() string
return time.Unix(time.Now().Unix(), 0).Format("2006-01-02 15:04:05")
// NowTimeStamp return 1657255820
func NowTimeStamp() int64
return time.Now().Unix()
// TimeStamp2NowTimeStr 1657255820 -> 2022-01-21 12:21:31
func TimeStamp2NowTimeStr(stamp int64) string
format := time.Unix(stamp, 0).Format("2006-01-02 15:04:05")
return format
// NowTimeStr2TimeStamp 2022-01-21 12:21:31 -> 1657255820
func NowTimeStr2TimeStamp(str string) int64
var LOC, _ = time.LoadLocation("Asia/Shanghai")
tim, _ := time.ParseInLocation("2006-01-02 15:04:05", str, LOC)
return tim.Unix()
controller层:
package controller
import (
"count_num/pkg/dao/impl"
"count_num/pkg/model"
"count_num/pkg/utils"
"count_num/pkg/web/auth"
"encoding/json"
"github.com/gin-gonic/gin"
"io/ioutil"
)
type UserControllerImpl struct
dao *impl.UserDaoImpl
type UserController interface
CreateUser(c *gin.Context)
FindUserByLoginNameAndPwd(c *gin.Context)
Register(c *gin.Context)
func NewUserController() *UserControllerImpl
return &UserControllerImpldao: impl.NewUserDaoImpl()
func (impl UserControllerImpl) CreateUser(c *gin.Context)
body := c.Request.Body
bytes, err := ioutil.ReadAll(body)
user := model.User
json.Unmarshal(bytes, &user)
if err != nil
panic(err)
res := impl.dao.CreateUser(c, user)
c.JSON(200, map[string]interface"code": 0, "msg": "", "count": 0, "data": res)
func (impl UserControllerImpl) FindUserByLoginNameAndPwd(c *gin.Context)
body := c.Request.Body
bytes, err := ioutil.ReadAll(body)
user := model.User
json.Unmarshal(bytes, &user)
if err != nil
panic(err)
userByLoginName := impl.dao.GetUserByLoginName(c, user.LoginName)
//密码通过
if userByLoginName.Pwd == utils.GetMd5Str(user.Pwd)
setToken := auth.SetToken(c, utils.GetTokenStr(), user)
c.JSON(200, map[string]interface"code": 0, "msg": setToken, "count": 0, "data": utils.GetTokenStr())
else
if userByLoginName.Id == 0
c.JSON(200, map[string]interface"code": 0, "msg": "账号不存在", "count": 0, "data": "-1")
else
c.JSON(200, map[string]interface"code": 0, "msg": "密码错误", "count": 0, "data": "-1")
func (impl UserControllerImpl) Register(c *gin.Context)
body := c.Request.Body
bytes, err := ioutil.ReadAll(body)
user := model.User
json.Unmarshal(bytes, &user)
if err != nil
panic(err)
user.Role = 1
res := impl.dao.CreateUser(c, user)
c.JSON(200, map[string]interface"code": 0, "msg": "", "count": 0, "data": res)
router增加URL:
......
userInfo := r.Group("/user")
userInfo.POST("/save", controller.NewUserController().CreateUser)
userInfo.POST("/login", controller.NewUserController().FindUserByLoginNameAndPwd)
userInfo.POST("/register", controller.NewUserController().Register)
......
前端代码:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>登录/注册</title>
<link rel="stylesheet" href="./layui/css/layui.css">
<style>#form
width: 30%;
margin-left: 35%;
margin-top: 200px;
padding: 30px;
border: 3px solid #c5c5b0;
border-radius: 20px;
#form2
width: 30%;
margin-left: 35%;
margin-top: 200px;
padding: 30px;
border: 3px solid #c5c5b0;
border-radius: 20px;
.hidden
display: none;
.show
display: block;
</style>
</head>
<body>
<form class="layui-form" id="form">
<h3 style="font-size: 20px;text-align: center;margin-bottom: 30px;">登录</h3>
<div class="layui-form-item">
<label class="layui-form-label">账号</label>
<div class="layui-input-inline">
<input type="text" id="loginName" placeholder="请输入账号" autocomplete="off"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">密码</label>
<div class="layui-input-inline">
<input type="password" id="loginPwd" placeholder="请输入密码" autocomplete="off"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" type="button" onclick="login()">立即提交</button>
<button type="button" onclick="toRegister()" class="layui-btn layui-btn-primary">注册</button>
</div>
</div>
</form>
<form class="layui-form hidden" id="form2">
<h3 style="font-size: 20px;text-align: center;margin-bottom: 30px;">注册</h3>
<div class="layui-form-item">
<label class="layui-form-label">昵称</label>
<div class="layui-input-inline">
<input type="text" id="regName" placeholder="请输入昵称" autocomplete="off"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">账号</label>
<div class="layui-input-inline">
<input type="text" id="regLoginName" placeholder="请输入账号" autocomplete="off"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">密码</label>
<div class="layui-input-inline">
<input type="password" id="regPwd" placeholder="请输入密码" autocomplete="off"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">确认密码</label>
<div class="layui-input-inline">
<input type="password" id="regPwd2" placeholder="请再次输入密码"
autocomplete="off"
class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">身份</label>
<div class="layui-input-block">
<input type="radio" id="role" value="user" title="用户" checked>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" type="button" onclick="register()">立即提交</button>
<button type="button" onclick="toLogin()" class="layui-btn layui-btn-primary">登录</button>
</div>
</div>
</form>
</body>
<script src="./layui/layui.js"></script>
<script src="./layui/jquery.min.js"></script>
<script>var base_url = http://localhost:9888
function login()
var loginName = $("#loginName").val()
var loginPwd = $("#loginPwd").val()
var data =
login_name: loginName,
pwd: loginPwd
$.ajax(
url: base_url + "/user/login",
type: "POST",
data: JSON.stringify(data),
success: function (res)
if (res.data.length >= 10)
localStorage.setItem("token", res.data)
return;
alert(res.msg)
return
,
error: function (err)
alert(err)
return
)
function register()
var regName = $("#regName").val()
var regLoginName = $("#regLoginName").val()
var regPwd = $("#regPwd").val()
var regPwd2 = $("#regPwd2").val()
if (regPwd != regPwd2)
alert("密码不一致鸭")
return
var data =
name: regName,
login_name: regLoginName,
pwd: regPwd
$.ajax(
url: base_url + "/user/register",
type: "POST",
data: JSON.stringify(data),
success: function (res)
if (res.data)
alert("注册成功")
else
alert("注册失败")
,
error: function (err)
console.log(err)
)
function toLogin()
$("#form2").addClass("hidden")
$("#form").removeClass("hidden")
function toRegister()
$("#form").addClass(以上是关于从4开始,在后端系统中增加用户注册和登录功能的主要内容,如果未能解决你的问题,请参考以下文章Linux系统裁减之,制作一个极度精简的Linux-4-为精简的Linux 系统增加用户登录功能
五登录页倒计时制作《仿淘票票系统前后端完全制作(除支付外)》