gin投票项目4

对应视频v2版本

gin项目投票系统4

1.增加一个注册账号的功能

增加接口

参数校验:(需求)

  1. 确认密码需要一致,不为空
  2. 用户名必须唯一, 不为空
  3. 用户名大于8小于16位
  4. 密码大于8小于16位,并且不能为纯数字
正则表达式

必须知道这东西的存在!!!和知道怎么用,不一定能自己写出来,可以靠软件或gpt但一定要了解用法。

要增加注册账号功能需要在login.go中新建一个结构体

// 新创建一个结构体
type CUser struct {Name      string `json:"name"`Password  string `json:"password"`Password2 string `json:"password_2"`
}

因为账号密码是隐私信息,不敢随便放到请求中

先写处理用户注册的各个逻辑

//判断两次输入密码是否相同
if user.Password != user.Password2 {context.JSON(200, tools.ECode{Code:    10003,Message: "两次密码不同",})return
}
//会有风险,并发安全,判断用户是否已经存在
if oldUser := model.GetUser(user.Name); oldUser.Id > 0 {context.JSON(200, tools.ECode{Code:    10004,Message: "用户名已存在!",})return
}//判断账号密码是否符合长度要求。
nameLen := len(user.Name)
passwordLen := len(user.Password)
if nameLen > 16 || nameLen < 8 || passwordLen > 16 || passwordLen < 8 {context.JSON(200, tools.ECode{Code:    10005,Message: "账号或密码要大于8位小于16位!",})return
}

正则最好用自动生成正则的工具或者gpt来实现;

这里需要正则来表示:密码中至少包括数字,小写字母,大写字母;

regex := regexp.MustCompile(`^[0-9]+$`)
if regex.MatchString(user.Password) {context.JSON(http.StatusOK, tools.ECode{Code:    10006,Message: "密码不能为纯数字", // 这里有风险})return
}

下一步

增加密码加密

为什么要加密?防止被黑客sql注入,如果明文存储,整个数据库就会被盗走;

介绍三种

// 数据加密:第一种方式,直接用md5加密,很容易被装库试出来
func encrypt(pwd string) string {hash := md5.New()hash.Write([]byte(pwd))hashBytes := hash.Sum(nil)hashString := hex.EncodeToString(hashBytes)fmt.Printf("加密后的密码: %s\n", hashString)return hashString
}// 数据加密:第二种方式,在第一种基础上进行操作,具体来说是把传过来的密码使用
func encryptV1(pwd string) string {secretString := "香香编程喵喵喵"newPwd := pwd + secretString // Concatenate the secret string to the passwordhash := md5.New()hash.Write([]byte(newPwd))hashBytes := hash.Sum(nil)hashString := hex.EncodeToString(hashBytes)fmt.Printf("加密后的密码: %s\n", hashString)return hashString
}//第三种方式加密。使用不同的加密方式:
func encryptV2(pwd string) string {// 基于Blowfish实现加密。简单快速,但有安全风险// golang.org/x/crypto/中有大量的加密算法newPwd, err := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost)if err != nil {fmt.Println("密码加密失败:", err)return ""}newPwdStr := string(newPwd)fmt.Printf("加密后的密码: %s\n", newPwdStr)return newPwdStr
}

2.增加验证码功能

使用base64实现将2进制文件转化成图片;

package tools
import ("github.com/mojocn/base64Captcha"
)
type CaptchaData struct {CaptchaId string `json:"captcha_id"`Data      string `json:"data"`
}
type driverString struct {Id            stringCaptchaType   stringVerifyValue   stringDriverString  *base64Captcha.DriverString  // 字符串DriverChinese *base64Captcha.DriverChinese // 中文DriverMath    *base64Captcha.DriverMath    // 数学DriverDigit   *base64Captcha.DriverDigit   // 数字
}
// 数字驱动
var digitDriver = base64Captcha.DriverDigit{Height:   50,  // 生成图片高度Width:    150, // 生成图片宽度Length:   5,   // 验证码长度MaxSkew:  1,   // 文字的倾斜度越大倾斜越狠,越不容易看懂DotCount: 1,   // 背景的点数,越大,字体越模糊
}
var store = base64Captcha.DefaultMemStore
func CaptchaGenerate() (CaptchaData, error) {var ret CaptchaData// 注意,这里直接使用digitDriver会报错。必须传一个指针。原因参考接口实现课程中的内容c := base64Captcha.NewCaptcha(&digitDriver, store)id, b64s, err := c.Generate()if err != nil {return ret, err}ret.CaptchaId = idret.Data = b64sreturn ret, nil
}
func CaptchaVerify(data CaptchaData) bool {return store.Verify(data.CaptchaId, data.Data, true)
}// Other driver initialization here...
为登陆接口添加验证码接口

1.验证码的作用:判断用户行为是脚本还是人工

2.常见验证码有哪些:图片验证码,拖动验证码,按照顺序点击,9张图里选择有红绿灯的,邮箱验证码,手机验证码

3.调用的验证码包是怎么工作的:a.验证码如何生成:其实里边是使用了go的math包,三角函数

b.生成的验证码是以什么形式存在的:用bas64直接存在内存中,

c.base64传给前端,渲染到页面上,

d.输入验证码,以及验证码的id,服务端进行校验

注意这个验证码接口存在很严重的安全隐患

当点击验证码时,可以重新生成新的验证码。

DDOS攻击和CC攻击。

常见的后端攻击手段:SQL注入,CSRF/XSS(伪造跨站攻击),DDOS,CC攻击

方法:WAF花钱,买一个高防服务器;

3.增加校验,防止刷票

增加是否投票的校验,防止刷票

第一种方式,在事务中查询是否投过票,增加了事务的逻辑,成本非常高

var oldVoteUser VoteOptUser
err = tx.Table("vote_opt_user").Where("vote_id=? ans", voteId).First(&oldVoteUser).Error
if err != nil {fmt.Printf("err:%s")tx.Rollback()
}
if oldVoteUser.Id > 0 {fmt.Printf("用户已投票")tx.Rollback()
}

第二种方式,前置查询,直接先查询一下是否投过,如果投过直接返回

old := model.GetVoteHistory(userId, voteId)
if len(old) >= 1 {context.JSON(200, tools.ECode{Code:    10010,Message: "您已投过票",})
}

当同时有一个人同时发起100个请求投票,会出现重复投票现象吗?

以上两种方式都无法完美解决这个问题,肯定会出现

需要学习,悲观锁,乐观锁,分布式锁(较好用)。

最好用的是消息队列,很重要,以后学到。

4.增加一个定时器,到期自动关闭

多种定时器,不同的能解决不同的问题。

以后是需要学习不同环境中定时器的作用的

具体代码还是比较重要的,具体实现的功能

package schedule//增加定时器功能
import ("fmt""time""toupiao/application/model"
)func Start() {//Start 函数启动一个 goroutine,在这个 goroutine中调用了 voteEnd 函数。go func() { //使用 go 关键字创建 goroutine 表示这个函数是异步执行的,不会阻塞当前程序的执行。EndVote()}()return
}func EndVote() {t := time.NewTicker(5 * time.Second)//每秒触发一次defer t.Stop() //最后运行关闭定时器for {select { //监听定时器的触发事件,case <-t.C:fmt.Printf("定时器voteEnd启动")//执行函数model.EndVote()fmt.Println("EndVote 运行完毕")}}
}

设定时间5秒,即5秒后自动关闭投表

引入日志包

官方包

log.Printf("[print]ret:%+v", ret)
log.Panicf("[fatal]ret:%+v", ret)

很不好用,除非花时间二次封装

logrus

日志级别

PanicLevel:记录日志,panic
FatalLevel:记录日志,程序exit线上: (
ErrorLevel:错误级别日志
WarnLevel:警告级别日志     ) Infolevel:关键信 息级别日志开发时通常用:(
DebugLevel:调试级别
TraceLevel:追踪级别       )

测试:

新建tools中logger文件:

package toolsimport ("fmt""github.com/sirupsen/logrus""io""os"
)
var Logger *logrus.Logger
func NewLogger() {Logger = logrus.New()Logger.SetLevel(logrus.DebugLevel)// 同时写到多个输出w1 := os.Stdout // 写到控制台w2, err := os.OpenFile("./vote.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)//写到文件中;if err != nil {// 错误处理,例如打印错误并退出程序fmt.Println("Error opening log file:", err)os.Exit(1)}Logger.SetOutput(io.MultiWriter(w1, w2)) // io.MultiWriter 返回一个 io.Writer 对象}

效果:
image-20231128162101149

可在控制台和文件中都生成日志;

拓展:日志可以生成不同类型的:

比如JSON,在日志中再添加字段

logStore.SetFormatter(&logrus.JSONFormatter{}) 
//生成json格式的日志
Logger = logStore.WithFields(logrus.Fields{"name": "香香编程喵喵喵","app":  "voteV2",
})//添加两个字段

image-20231128164443846

Hook函数(钩子函数)是什么:

Hook 函数是一种编程技术,其作用是在特定事件发生时插入自定义的代码,以便执行额外的逻辑或修改程序的行为。这样的插入点通常称为 “hook points”,而插入自定义代码的函数就是 “hook 函数”。

主要作用和用途包括:

  1. 扩展功能: Hook 函数可以用于在程序运行时动态地添加或修改功能。通过在特定事件上挂钩,可以在不修改源代码的情况下扩展应用程序的行为。
  2. 调试和日志: Hook 函数常常用于记录日志、跟踪程序执行流程,或在特定条件下触发调试信息。这对于排查问题、性能优化以及了解程序行为非常有用。
  3. 事件通知: Hook 函数还可以用于向其他部分发送通知,让它们在特定事件发生时执行相应的操作。这种方式用于实现观察者模式等。
  4. 修改数据: 有时 Hook 函数也用于修改或过滤数据。例如,在数据保存到数据库之前执行某些处理。
  5. 安全性: 在安全领域,Hook 函数可以用于拦截和处理潜在的安全威胁,比如输入验证或访问控制。

在实际编程中,Hook 函数通常通过回调函数或事件监听机制来实现。编程框架和库通常提供了一些预定义的 hook points,同时也允许开发者定义自己的 hook points。

ZAP

logruszap 都是 Go 语言中流行的日志库,它们各自有自己的特点和适用场景。下面是对它们的一些比较:

logrus:

  • 易用性: logrus 相对于 zap 来说,更容易上手,其 API 设计更为简单直观。
  • 社区支持: 由于 logrus 的存在时间较长,因此在社区中有更多的用户和资源,相应的社区支持更丰富。
  • 扩展性: logrus 支持很多的插件和扩展,可以很容易地集成到各种不同的环境和系统中。
  • 灵活性: 可以通过 Hook 的方式灵活扩展 logrus 的功能。

zap:

  • 性能: zap 以高性能为目标,被设计成尽可能地快,具有更低的内存分配和更高的吞吐量。适用于高并发和性能敏感的应用。
  • 结构化日志: zap 倡导结构化日志,即将日志信息存储为结构体,使日志更容易分析和查询。
  • 零分配: zap 设计了零分配(zero-allocation)的原则,以减少垃圾回收的影响。
  • Sugar API: zap 提供了一个 Sugar API,用于简化常用日志操作的调用。

如何选择:

  • 如果你更看重易用性、社区支持和扩展性,可以选择 logrus
  • 如果你的应用对性能要求很高,且你希望采用结构化日志,那么 zap 可能更适合。

最终的选择取决于你的具体需求和项目的特点。如果不确定,可以先使用其中一个,后期根据实际情况进行评估和切换。

日志既然这么麻烦又为什么要引入日志呢?

  1. 故障排查和调试: 在应用程序出现问题时,日志是排查错误和调试的关键工具。通过查看日志,开发人员可以追踪代码的执行路径、发现异常行为,并更容易地定位问题。
  2. 性能监控: 日志也是性能监控的一部分。通过记录关键操作的执行时间、资源使用情况等信息,开发人员可以了解应用程序的性能状况,并进行优化。
  3. 安全审计: 在一些敏感的系统中,日志记录也用于安全审计。记录用户的操作、访问尝试以及其他安全相关事件,以便进行审计和追踪。
  4. 业务分析: 日志还可以用于业务分析。通过记录用户的行为、交易记录等信息,可以为业务决策提供数据支持。
  5. 运维监控: 运维团队通过监控日志可以实时掌握系统运行状态,及时发现和处理潜在问题。
  6. 历史记录: 日志可以作为系统的历史记录,帮助了解系统的演变和变更历史。

虽然引入日志可能增加了代码的复杂性,但日志对于维护和监控大型应用是至关重要的。它为开发者提供了一种实时的、非侵入式的了解应用运行状况的手段。在生产环境中,日志往往是排查问题的最主要工具之一。

将验证码功能加入到前端,并加入点击验证码更新的操作

<!doctype html>
<html lang="en">
<head><meta charset="utf-8"><title>香香编程-投票项目</title><script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
</head>
<body>
<main class="main"><input type="text" name="name" id="name" placeholder="Your name"><input type="password" name="password" id="password" placeholder="Password"><input type="hidden" name="captcha_id" id="captcha_id" ><input type="text" name="captcha_value" id ="captcha_value"><button type="submit" id="login_sub">Sign in</button><div id="img_captcha"></div>
</main>
<script>$(document).ready(function(){loadCaptcha()//确保在页面完全加载后才执行内部的代码。$("#login_sub").on("click",function () {//事件监听器,它绑定了一个点击事件到sign in按钮$.ajax({//ajax函数内部,用于异步发送请求参数//请求资源路径url:"/login",//请求参数data:{name:$("#name").val(),password:$("#password").val(),captcha_id:$("#captcha_id").val(),captcha_value:$("#captcha_value").val(),},//请求方式type:"post",//数据形式dataType:"json",//请求成功后调用的回调函数success:function (data) {console.log(data)if (data.code !== 0){alert(data.message)}else{alert("已登录")setTimeout("pageRedirect()", 3000);//三秒后调转}},//请求失败后调用的回调函数error:function () {alert("请求失败!")}});});$("#img_captcha").on("click", function(){loadCaptcha()})});//实现跳转的函数function pageRedirect() {window.location.replace("/index");}function loadCaptcha() {$.ajax({url:"/captcha",type:"get",dataType:"json",success:function (data) {console.log(data)$("#img_captcha").empty()var img=new Image()img.onload=function (){//图片加载到页面上$("#img_captcha").append(img)}img.src=data.data.data$("#captcha_id").val(data.data.captcha_id)},error:function () {alert("请求失败!")}});}
</script>
</body>
</html>

ZAP

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

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

相关文章

我对迁移学习的一点理解(系列2)

文章目录 我对迁移学习的一点理解 我对迁移学习的一点理解 源域和目标域是相对的概念&#xff0c;指的是在迁移学习任务中涉及到的两个不同的数据集或领域。 源域&#xff08;Source Domain&#xff09;通常指的是已经进行过训练和学习的数据集&#xff0c;它被用来提取特征、…

Nginx缓存及HTTPS配置小记

缓存基础 缓存分类 某些场景下&#xff0c;Nginx需要通过worker到上有服务中获取数据并将结果响应给客户端&#xff0c;在高并发场景下&#xff0c;我们完全可以将这些数据视为热点数据&#xff0c;并将其缓存到Nginx服务上。 客户端缓存&#xff1a;将缓存数据放到客户端。 …

yolov8与yolov5网络对比

回顾一下YOLOv5&#xff0c;不然没机会了 这里粗略回顾一下&#xff0c;这里直接提供YOLOv5的整理的结构图吧&#xff1a; Backbone&#xff1a;CSPDarkNet结构&#xff0c;主要结构思想的体现在C3模块&#xff0c;这里也是梯度分流的主要思想所在的地方&#xff1b;PAN-FPN&…

OFDM模糊函数仿真

文章目录 前言一、OFDM 信号及模糊函数1、OFDM 信号表达式2、模糊函数表达式 二、MATLAB 仿真1、MATLAB 核心源码2、仿真结果①、OFDM 模糊函数②、OFDM 距离模糊函数③、OFDM 速度模糊函数 前言 本文进行 OFDM 的仿真&#xff0c;首先看一下 OFDM 的模糊函数仿真效果&#xf…

【vim】常用操作

用的时候看看&#xff0c;记太多也没用&#xff0c;下面都是最常用的&#xff0c;更多去查文档vim指令集。 以下均为正常模式下面操作&#xff0c;正在编辑的&#xff0c;先etc一下. 1/拷贝当前行 yy&#xff0c;5yy为拷贝包含当前行往下五行 2/p将拷贝的东西粘贴到当前行下…

Java、JDK、JRE、JVM

Java、JDK、JRE、JVM 一、 Java 广义上看&#xff0c;Kotlin、JRuby等运行于Java虚拟机上的编程语言以及相关的程序都属于Java体系的一员。从传统意义上看&#xff0c;Java社区规定的Java技术体系包括以下几个部分&#xff1a; Java程序设计语言各种硬件平台上的Java虚拟机实…

【力扣】移除链表元素203

目录 1.前言2. 题目描述3. 题目分析3.1 不带哨兵位3.2 带哨兵位 4. 附代码4.1 不带哨兵位4.2 带哨兵位 1.前言 这里开始介绍从网上一些刷题网站上的题目&#xff0c;在这里做一些分享&#xff0c;和学习记录。 先来介绍一些力扣的OJ题目。 这里的OJ就是我们不需要写主函数&…

数据表记录的操作

一、数据添加 1、打开SSMS&#xff0c;附加数据库&#xff08;数据库文件在自己的文件夹下面&#xff09;&#xff0c;并进行下面的设置&#xff1a; &#xff08;1&#xff09;设置“部门信息”表中的“编号”为主键&#xff08;SSMS&#xff09; 首先建立好所需的数据库库…

华为OD机试 - 生成哈夫曼树(Java JS Python C)

题目描述 给定长度为 n 的无序的数字数组,每个数字代表二叉树的叶子节点的权值,数字数组的值均大于等于1。 请完成一个函数,根据输入的数字数组,生成哈夫曼树,并将哈夫曼树按照中序遍历输出。 为了保证输出的二叉树中序遍历结果统一,增加以下限制: 二叉树节点中,左节…

为 Compose MultiPlatform 添加 C/C++ 支持(3):实战 Desktop、Android、iOS 调用同一个 C/C++ 代码

theme: serene-rose 前言 在本系列的前两篇文章中我们已经学会了如何在 kotlin native 平台&#xff08;iOS&#xff09;使用 cinterop 调用 C/C 代码。以及在 jvm 平台&#xff08;Android、Desktop&#xff09;使用 jni 调用 C/C 代码&#xff0c;并且知道了如何自动编译 A…

Git 五分钟教程速度入门

Git 五分钟教程速度入门 分类 编程技术 许多人认为 Git 太混乱&#xff0c;或认为它是一种复杂的版本控制系统&#xff0c;其实不然&#xff0c;这篇文章有助于大家快速上手使用 Git。 入门 使用Git前&#xff0c;需要先建立一个仓库(repository)。您可以使用一个已经存在的…

Win10操作系统安装Python

1 Python解释器下载 1.1 安装环境 Windows 10 专业工作站版22H2 python-3.9.6-amd64.exe 1.2 下载地址 Python官网&#xff1a;Welcome to Python.org Python镜像&#xff1a;CNPM Binaries Mirror 2 Python解释器安装 2.1 Install Python 3.9.6 (64-bit)界面 双击运行下…

【数据结构】面试OJ题———栈|队列|互相实现|循环队列|括号匹配

目录 1. 有效的括号 思路&#xff1a; 2.用队列实现栈 思路&#xff1a; 3.用栈实现队列 思路&#xff1a; 4.设计循环队列 思路&#xff1a; 1. 有效的括号 20. 有效的括号 - 力扣&#xff08;LeetCode&#xff09; 给定一个只包括 (&#xff0c;)&#xff0c;{&…

Hive SQL间隔连续问题

问题引入 下面是某游戏公司记录的用户每日登录数据, 计算每个用户最大的连续登录天数&#xff0c;定义连续登录时可以间隔一天。举例&#xff1a;如果一个用户在 1,3,5,6,9 登录了游戏&#xff0c;则视为连续 6 天登录。 id dt1001 2021-12-121002 2021-12-12…

visual studio code 好用的插件

vscode-icons Better comments 该插件对不同类型的注释会附加了不同的颜色&#xff0c;更加方便区分&#xff0c;帮助我们在代码中创建更人性化的注释。 Error Lens Error Lens插件是一款可以检测你编写的代码的语法错误&#xff0c;并且会显示出对语法错误的诊断信息…

RCNN 学习

RCNN算法流程 RCNN算法流程可分为4个步骤 一张图像生成1K~2K个候选区域&#xff08;使用Selective Search方法&#xff09;对每个候选区域&#xff0c;使用深度网络图特征特征送入每一类的SVM分类器&#xff0c;判别是否属于该类使用回归期器细修正候选框位置 1.候选区域的生…

ChatGPT是科学还是艺术?

OpenAI最近谈到GPT4变懒的问题&#xff0c;说“它更像是多人共同参与的艺术创作”&#xff0c;那到底大模型是科学还是艺术&#xff1f;

公式识别任务各个链条全部打通

目录 引言公式识别任务是什么&#xff1f;公式识别任务解决方案初探使用建议写在最后 引言 随着LaTeX-OCR模型转换问题的解决&#xff0c;公式识别任务中各个链条已经全部打通。小伙伴们可以放开膀子干了。 解决业界问题的方案&#xff0c;并不是单独训练一个模型就完事了&am…

如何确认网站是否有漏洞,如何找出网站存在的漏洞,找到漏洞该如何处理

如何确认网站或者服务器是否有漏洞 判断一个网站是否是存在漏洞的方法&#xff1a; 1.可以借助德迅云安全漏洞扫描功能来检查漏洞。 2.打开德迅云安全首页&#xff0c;点击最上面导航栏中的“安全产品”。 3.滑到“漏洞扫描”&#xff0c;选择“产品价格”服务。 4.选择您需…

【力扣】141和142环形链表

141.环形链表 法一&#xff1a;快慢指针 思路&#xff1a; 用两个指针slow,fast,后者能比前者多走一步路&#xff0c;那判断是不是有环&#xff0c;只需要判断是否会相遇。 就是有一个能比乌龟跑2倍快的兔子&#xff0c;两小只都在有环的路上跑&#xff0c;那是不是肯定会相…