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.pswp.cn/news/211468.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/211468.shtml
英文地址,請注明出處:http://en.pswp.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將拷貝的東西粘貼到當前行下…

Nmap腳本的應用場景

網絡安全檢測和漏洞掃描 Nmap腳本是一種強大的工具&#xff0c;可以用于網絡安全檢測和漏洞掃描。在滲透測試工程師的角度下&#xff0c;本文將詳細闡述Nmap腳本的應用場景&#xff0c;以及如何使用Nmap腳本進行網絡安全檢測和漏洞掃描。 一、Nmap腳本的應用場景 Nmap腳本在滲…

Java、JDK、JRE、JVM

Java、JDK、JRE、JVM 一、 Java 廣義上看&#xff0c;Kotlin、JRuby等運行于Java虛擬機上的編程語言以及相關的程序都屬于Java體系的一員。從傳統意義上看&#xff0c;Java社區規定的Java技術體系包括以下幾個部分&#xff1a; Java程序設計語言各種硬件平臺上的Java虛擬機實…

vue的知識點

Vue.js是一個漸進式JavaScript框架&#xff0c;用于簡化Web應用程序開發和管理。下面是Vue.js的一些核心知識點&#xff1a; 1. 數據綁定&#xff1a;Vue.js通過指令和模板語法實現了雙向數據綁定&#xff0c;可以實時更新視圖和模型之間的數據。 2. 組件化開發&#xff1a;V…

【力扣】移除鏈表元素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。 請完成一個函數,根據輸入的數字數組,生成哈夫曼樹,并將哈夫曼樹按照中序遍歷輸出。 為了保證輸出的二叉樹中序遍歷結果統一,增加以下限制: 二叉樹節點中,左節…

java中什么是線程池?

線程池&#xff08;Thread Pool&#xff09;是一種線程管理的機制&#xff0c;它主要解決了線程生命周期的開銷和資源消耗問題。線程池在程序中創建一些預先定義數量的線程&#xff0c;將任務分配給這些線程&#xff0c;從而提高了線程的重用性和性能。線程池的核心思想是將創建…

為 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)界面 雙擊運行下…

鴻蒙開發組件之list

1、鴻蒙中的list作為可滑動列表功能&#xff0c;初始化方式是 List({space: 10}){ForEach(arr, item > {ListItem() {//列表單個Item組件}})} 其中&#xff0c;List中的space可以設置兩個ListItem組件的間距 List中是一個ForEach&#xff0c;需要注意的是item要返回的是L…

【數據結構】面試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;并且會顯示出對語法錯誤的診斷信息…

USB的高速速率是如何確定的?

從全局說起。先說host對dev的插入檢測。由于dev插入到host&#xff0c;導致為0的D和D-線突然有了電平變化&#xff0c;有且只有一根線的電平會變。在高速和全速模式下&#xff0c;D線會被拉高&#xff1b;在低速模式下D-線會被拉高。同時&#xff0c;host會對插入的dev進行消抖…