使用 Gin 框架实现谷歌动态验证码登录

动态验证码简介

动态验证码(通常称为 TOTP,即 Time-based One-Time Password)是一种基于时间的一次性密码技术,用于增强用户身份验证的安全性。TOTP 是二步验证(2FA)的一种形式,广泛用于保护用户账户免受未经授权访问。

动态验证码的工作原理

  1. 生成密钥:在用户设置动态验证码时,系统会生成一个密钥,并将该密钥提供给用户的身份验证器应用(如 Google Authenticator、Authy 等)。这个密钥是用户身份验证的核心部分。

  2. 同步时间:动态验证码依赖于时间同步。系统和身份验证器应用都基于当前的时间来生成验证码。验证码的有效期通常为 30 秒,因此验证码会随着时间的推移而更换。

  3. 生成验证码:身份验证器应用和服务器使用相同的密钥和时间来生成验证码。用户在登录时提供的验证码必须与服务器生成的验证码匹配才能通过身份验证。

  4. 验证:当用户输入验证码时,服务器会使用相同的密钥和时间戳来生成验证码,并与用户输入的验证码进行比较。如果匹配,用户验证成功。

实现动态验证码的步骤

以下是如何使用 Gin 框架和 google-authenticator 库来实现一个简单的动态验证码登录系统的步骤。

1. 安装必要的库

首先,确保你已经安装了 gingoogle-authenticator 库。打开终端并运行以下命令:

go get github.com/gin-gonic/gin
go get github.com/pquerna/otp/totp
go get github.com/skip2/go-qrcode

2. 编写 main.go 文件

创建一个名为 main.go 的文件,并添加以下代码:

package main

import (
    "github.com/gin-gonic/gin"
    "github.com/pquerna/otp/totp"
    "net/http"
    "log"
)

// 生成 TOTP 密钥的路由处理器
func generateHandler(c *gin.Context) {
    key, err := totp.Generate(totp.GenerateOpts{
        Issuer:      "MyApp", //你的应用名称
        AccountName: "user@example.com", //账号
    })
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        return
    }
    //一下代码1、2,二选一即可
    //1、返回秘钥及url数据
    c.JSON(http.StatusOK, gin.H{
        "secret": key.Secret(),
        "url":    key.URL(),
    })
    //2、或者你可以只直接返回二维码给前端
    //qrCode, err := qrcode.Encode(key.URL(), qrcode.Medium, 256)
    //if err != nil {
    //    c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
    //    return
    //}
    // 设置响应头
	//c.Header("Content-Type", "image/png")
	//c.Header("Content-Disposition", "inline; filename=qr.png")
	//c.Data(http.StatusOK, "image/png", qrCode)
}

// 验证 TOTP 码的路由处理器
func verifyHandler(c *gin.Context) {
    var params struct {
        Secret string `json:"secret"`//一般将秘钥存入数据库,根据账号查询秘钥,取出来校验
        Code   string `json:"code"`
    }

    if err := c.BindJSON(&params); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    valid := totp.Validate(params.Code, params.Secret)
    if valid {
        c.JSON(http.StatusOK, gin.H{"status": "success"})
    } else {
        c.JSON(http.StatusUnauthorized, gin.H{"status": "failure"})
    }
}

func main() {
    router := gin.Default()

    router.GET("/generate", generateHandler)
    router.POST("/verify", verifyHandler)

    log.Fatal(router.Run(":8080"))
}

3. 启动应用并测试

  1. 生成 TOTP 密钥:启动你的应用程序,访问 http://localhost:8080/generate。你将获得一个 JSON 响应,其中包含一个密钥和一个用于设置身份验证器的 URL。

    示例响应:

    {
        "secret": "JBSWY3DPEHPK3PXP",
        "url": "otpauth://totp/MyApp:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=MyApp"
    }
    
  2. 配置身份验证器:使用 url 中的链接配置你的身份验证器应用(如 Google Authenticator)。你将看到一个与密钥相关联的验证码。

  3. 验证 TOTP 码:使用你的身份验证器生成的验证码,发送一个 POST 请求到 http://localhost:8080/verify,包含 secretcode

    示例 curl 请求:

    curl -X POST http://localhost:8080/verify \
    -H "Content-Type: application/json" \
    -d '{"secret": "JBSWY3DPEHPK3PXP", "code": "123456"}'
    

    如果验证码正确,你会收到 {"status": "success"} 响应,否则会收到 {"status": "failure"} 响应。

总结

动态验证码(TOTP)是一个强大的工具,用于提升应用程序的安全性。通过结合时间和密钥,它提供了一种有效的方式来防止未经授权的访问。使用 Gingoogle-authenticator,你可以轻松实现这种机制,保护你的用户账户安全。在博客中,你可以展示这些步骤,并强调动态验证码在现代身份验证中的重要性和优势。


  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,这里是一个简单的示例代码,演示了如何使用Gin框架实现登录功能,前端使用HTML和JavaScript。 后端代码(使用Gin框架): ```go package main import ( "net/http" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() // 静态文件目录,存放前端页面 r.Static("/static", "./static") // 登录页面 r.GET("/login", func(c *gin.Context) { c.HTML(http.StatusOK, "login.html", nil) }) // 登录接口 r.POST("/api/login", func(c *gin.Context) { username := c.PostForm("username") password := c.PostForm("password") // 在这里进行账号验证等操作 // ... c.JSON(http.StatusOK, gin.H{ "message": "登录成功", }) }) r.Run(":8080") } ``` 前端代码(使用HTML和JavaScript): ```html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <form id="login-form"> <div> <label>用户名:</label> <input type="text" name="username"> </div> <div> <label>密码:</label> <input type="password" name="password"> </div> <div> <button type="submit">登录</button> </div> </form> <script src="/static/jquery.min.js"></script> <script> $(function() { $('#login-form').on('submit', function(event) { event.preventDefault(); var formData = $(this).serialize(); $.ajax({ type: 'POST', url: '/api/login', data: formData, success: function(data) { alert(data.message); // TODO: 登录成功后的操作 }, error: function(xhr, textStatus, errorThrown) { alert(xhr.responseText); } }); }); }); </script> </body> </html> ``` 在示例代码中,后端路由配置了两个接口,一个是GET请求的/login,用于返回登录页面,一个是POST请求的/api/login,用于处理登录请求。前端页面使用了jQuery库,通过ajax()方法将表单数据发送给后端。在登录成功后,会弹出提示框,提示用户登录成功。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yijiacode

互联网+乞讨

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值