玩转Gin框架:Golang使用Gin完成登录流程
文章目录
- 背景
- 基于Token认证机制简介
- 常见的Token类型
- Token的生成和验证
- 在项目工程里创建jwt.go文件
- 根目录新建.env文件
- 创建登录接口 /login
- Token认证机制的优点
背景
登录流程,相信大家都很熟悉的。传统网站采用session后端验证登录状态,大致流程如下:
- 用户输入用户名和密码 / 手机号和验证码点击登录按钮提交表单。
- 后端校验前端传递过来的信息,验证通过在缓存中存储用户信息。
- 后续每次请求时,携带session_id发送给服务端验证登录状态。
综上所述,一个简单的登录流程就完成了,但是你会发现在现如今session机制已无法满足一些服务架构,特别是在分布式服务和单点登录等功能使用session机制完成登录认证过程就需要解决共享session的问题,再者如果用户量很多,服务器内存压力会很大等等。
基于Token认证机制简介
Token 认证机制 是一种常用的身份验证方法,特别适用于现代化的 前后端分离 和 微服务架构 的应用。相比传统的 Session 认证机制,Token 认证具有一些明显的优势,特别是在 扩展性 和 跨平台 支持上,大致流程如下:
4. 客户端通过用户名和密码请求登录,后端对接收到的账号和密码进行验证
5. 如验证通过,则会签发一个Token返回给客户端进行存储
6. 后续客户端通过Authorization头部携带Token向服务器请求资源。
常见的Token类型
最常用的Token类型是JWT(JSON Web Token),它是一种自包含的、基于JSON格式的Token。
JWT分为三个部分:
- Header(头部):
- 通常包含Token类型(例如
JWT)和所使用的签名算法(例如HS256)。
- 通常包含Token类型(例如
- Payload(负载):
- 包含用户的相关信息(如用户ID、权限等)。这是Token的主体部分,不加密,因此可以被客户端解码,但签名确保其不被篡改。
- Signature(签名):
- 由服务器端的密钥生成,用来验证Token的合法性和完整性。签名部分用于防止Token在传输过程中被篡改。
Token的生成和验证
在项目工程里创建jwt.go文件
参考路径:BackEnd/pkg/auth/jwt.go
package authimport ("errors""os""time""github.com/golang-jwt/jwt/v5""github.com/joho/godotenv"
)// Secret 从环境变量中加载 JWT 密钥
var jwtSecret = []byte(getJWTSecret())// getJWTSecret 从环境变量中获取 JWT 密钥
func getJWTSecret() string {// 加载.env文件if err := godotenv.Load(); err != nil {panic("无法加载 .env 文件,请确保文件存在并正确配置")}secret := os.Getenv("JWT_SECRET")if secret == "" {panic("环境变量 JWT_SECRET 未设置,请配置后再运行程序")}return secret
}// GenerateToken 生成 JWT Token
func GenerateToken(username string) (string, error) {claims := jwt.MapClaims{"username": username,"exp": time.Now().Add(time.Hour).Unix(), // 一小时后过期"iat": time.Now().Unix(), // 签发时间}token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)return token.SignedString(jwtSecret)
}
// 验证签名时,通过解析 token ,验证 token 是否有效,再验证是否过期。验证Token 是用在用户登录后所有请求都需要携带 token ,然后服务端获取到 token 再进行验证过。
func ValidateToken(tokenString string) (jwt.MapClaims, error) {token, err := jwt.Parse(tokenString, func(t *jwt.Token) (interface{}, error) {if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {return nil, errors.New("签名方法无效,请检查 Token 的生成方式")}return jwtSecret, nil})if err != nil {return nil, err}if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {return claims, nil}return nil, errors.New("无效的 Token,请重新登录获取有效的 Token")
}
根目录新建.env文件
该文件用于区分不同环境的参数和记录密钥等信息
JWT_SECRET=kklive
创建登录接口 /login
参考路径:BackEnd/internal/user/handle.go
package userimport ("database/sql""my-ecommerce-app/pkg/auth""net/http""github.com/gin-gonic/gin""golang.org/x/crypto/bcrypt"
)// Response 定义统一的响应结构
type Response struct {Code int `json:"code"`Message string `json:"message"`
}// UserLoginRequest 定义登录请求结构
type UserLoginRequest struct {Username string `json:"username" binding:"required"`Password string `json:"password" binding:"required"`
}// UserQueryRequest 查询用户请求结构
type UserQueryRequest struct {Username string `json:"username" binding:"required"`
}// UserQueryResponse 查询用户响应结构
type UserQueryResponse struct {ID int `json:"id"`Username string `json:"username"`Nickname string `json:"nickname"`Face string `json:"face"`Email string `json:"email"`Created_at string `json:"created_at"`
}// UserLoginResponse 定义登录成功的响应
type UserLoginResponse struct {Message string `json:"message"`Token string `json:"token,omitempty"`Code int `json:"code"`
}// LoginHandler 用户登录接口
// @Summary 用户登录
// @Description 用户通过用户名和密码登录
// @Tags 用户模块
// @Accept json
// @Produce json
// @Param user body UserLoginRequest true "登录请求参数"
// @Success 200 {object} UserLoginResponse
// @Failure 400 {object} Response
// @Failure 401 {object} Response
// @Router /api/login [post]
func LoginHandler(db *sql.DB) gin.HandlerFunc {return func(ctx *gin.Context) {var req UserLoginRequestif err := ctx.ShouldBindJSON(&req); err != nil {ctx.JSON(http.StatusBadRequest, gin.H{"code": 401,"message": "参数错误",})return}var passwordHash stringerr := db.QueryRow("SELECT password FROM li_admin_user WHERE username = ?", req.Username).Scan(&passwordHash)if err != nil {if err == sql.ErrNoRows {ctx.JSON(http.StatusUnauthorized, gin.H{"code": 405,"message": "用户名或密码错误",})} else {ctx.JSON(http.StatusInternalServerError, gin.H{"code": 500,"message": "服务器错误",})}return}if err := bcrypt.CompareHashAndPassword([]byte(passwordHash), []byte(req.Password)); err != nil {ctx.JSON(http.StatusUnauthorized, gin.H{"code": 405,"message": "用户名或密码错误",})return}token, err := auth.GenerateToken(req.Username)if err != nil {ctx.JSON(http.StatusInternalServerError, gin.H{"code": 500, // Token生成错误"message": "请重新登录",})return}ctx.JSON(http.StatusOK, UserLoginResponse{Code: 200,Message: "登录成功!",Token: token,})}
}
Token认证机制的优点
使用Token进行无状态登录认证后,就可以轻松的实现多端登录和单点登录SSO,在签名算法中加入Token机器信息,就可以有效的控制账号的多端登录登出场景。
- 支持多端同时登录,任意端退出登录时,其他端保持不变,每个端会生成自己的Token,并且相互独立
- 支持多端同时登录,一端退出所有端退出登录,增加用户登录设备表,记录账号登录的设备和对应的Token信息,当一端点击退出时,在服务端删除缓存中的Token信息即可
- 多端选择性退出部分端:退出登录时增加一个需要退出端的对应设备类型或者设备ID,然后对应设备下的token 进行失效处理。
当然,除了以上使用场景,还有其他的优点,欢迎在评论区一起交流~
相关文章:
玩转Gin框架:Golang使用Gin完成登录流程
文章目录 背景基于Token认证机制简介常见的Token类型Token的生成和验证在项目工程里创建jwt.go文件根目录新建.env文件 创建登录接口 /loginToken认证机制的优点 背景 登录流程,相信大家都很熟悉的。传统网站采用session后端验证登录状态,大致流程如下&…...
Java实习生面试题汇总
Java实习生面试题汇总 简介 本人是二本大三学生,下半年大四。暑假在上海这边找实习工作,面了几家公司,所问到的问题记录在下面。 因为是在校生,没任何实习经历,一般找我面试的都是小公司,一般问的比较简…...
Java 如何覆盖第三方 jar 包中的类
目录 一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理 背景: 在我们日常的开发中,经常需要使用第三方的 jar 包,有时候我们会发现第三方的 jar 包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,…...
解密 Java Lambda 表达式中的 “effectively final“ 陷阱
文章目录 1. 引言 (Introduction)1.1. 核心问题1.2. 博客目标1.3. 目标读者1.4. 阅读收获 2. 重现错误 (Reproducing the Error)2.1. 代码示例 (LambdaErrorExampleCorrected.java)2.2. 逐步演示2.2.1. 没有错误的代码版本 (list 满足 effectively final)2.2.2. 导致错误的代码…...
react的antd中Cascader级联选择如何回显
如果你的数据都是这个样子的 {"id": 1015,"pid": 0,"name": "电力、热力、燃气及水生产和供应业","children": [{"id": 1403,"pid": 1015,"name": "热力",},{"id": 140…...
深度学习系列--04.梯度下降以及其他优化器
目录 一.梯度概念 1.一元函数 2.二元函数 3.几何意义上的区别 二.梯度下降 1.原理 2.步骤 3.示例代码(Python) 4.不同类型的梯度下降 5.优缺点 三.动量优化器(Momentum) 适用场景 1.复杂地形的优化问题 2.数据具有噪声的问…...
k8s常见面试题2
k8s常见面试题2 安全与权限RBAC配置如何保护 Kubernetes 集群的 API Server?如何管理集群中的敏感信息(如密码、密钥)?如何限制容器的权限(如使用 SecurityContext)?如何防止容器逃逸࿰…...
云计算行业分析
云计算作为数字经济的核心基础设施,未来十年将持续重塑全球科技格局,并渗透到几乎所有行业的数字化转型中。 一、云计算的发展潜力 1. 技术融合驱动爆发式创新 AI与云计算的深度耦合 - **智能云服务**:云厂商将提供预训练模型、自动化ML工…...
【C语言篇】“三子棋”
一、游戏介绍 三子棋,英文名为 Tic - Tac - Toe,是一款简单而经典的棋类游戏。游戏在一个 33 的棋盘上进行,两名玩家轮流在棋盘的空位上放置自己的棋子(通常用 * 和 # 表示),率先在横、竖或斜方向上连成三个…...
TongSearch3.0.4.0安装和使用指引(by lqw)
文章目录 安装准备手册说明支持的数据类型安装控制台安装单节点(如需集群请跳过这一节)解压和启动开启X-Pack Security和生成p12证书(之后配置内置密码和ssl要用到)配置内置用户密码配置ssl(先配置内置用户密码再配ssl)配置控制台…...
在本地顺利的部署一个al模型从零开始 windows
引言 (踩的坑,省流引言的内容没有有使模型跑起来) 最近想在本地部署一个deepseek模型,就在网上搞了3 4天终于是能够部署下来了,在部署的时候也是成功的踩了无数的坑,比如我先问al如何在本地部署一个语言模…...
【容器技术01】使用 busybox 构建 Mini Linux FS
使用 busybox 构建 Mini Linux FS 构建目标 在 Linux 文件系统下构建一个 Mini 的文件系统,构建目标如下: minilinux ├── bin │ ├── ls │ ├── top │ ├── ps │ ├── sh │ └── … ├── dev ├── etc │ ├── g…...
Nginx如何实现 TCP和UDP代理?
文章目录 前言 Nginx之TCP和UDP代理 工作原理示意图 配置文件和命令参数注释 基本命令 配置实例说明 TCP代理实例UDP代理实例 总结 前言 Nginx是一个高性能的HTTP和反向代理服务器,同时也支持TCP/UDP代理。在1.9.13版本后,Nginx已经支持端口转发&…...
基于keepalived+GTID半同步主从复制的高可用MySQL集群
文章目录 项目架构图项目名称项目环境项目描述ip地址规划项目步骤一.安装好8台全新的centos7.9的系统,关闭firewalld和selinux,配置每台主机的静态ip地址,设置每台主机对应的主机名。1、关闭firewalld2.关闭seLinux3.配置每台主机静态ip地址4…...
尝试在Excel里调用硅基流动上的免费大语言模型
我个人觉得通过api而不是直接浏览器客户端聊天调用大语言模型是使用人工智能大模型的一个相对进阶的阶段。 于是就尝试了一下。我用的是老师木 袁进辉博士新创的硅基流动云上的免费的大模型。——虽然自己获赠了不少免费token,但测试阶段用不上。 具体步骤如下&am…...
SqlSugar简单使用之Nuget包封装-Easy.SqlSugar.Core
SqlSugar官方文档 Nuget包开源地址 Nuget包是为了简化SqlSugar的使用步骤,增加一些基础的使用封装 引入分为两个版本,一个Ioc模式,另一个是注入模式,如果不想影响原本的仓储代码推荐使用Ioc模式,两者区别不到,方法通…...
Linux网络 | 理解NATPT, 数据链路层Done
前言:本节内容结束数据链路层, 本节的重要内容有两个:一个是见一个综合性面试题,另一个就是NAT技术NATPT。 那么废话不多说, 开始我们的学习吧!!! ps:最好先看一下上一篇…...
微信小程序~django Petting pets(爱抚宠物)小程序
博主介绍:✌程序猿徐师兄、8年大厂程序员经历。全网粉丝15w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…...
如何利用Python爬虫获取商品销量详情:应对eBay反爬策略的实战指南与代码示例
在当今数据驱动的商业环境中,获取商品销量数据对于市场分析、竞品研究和商业决策至关重要。然而,像eBay这样的大型电商平台通常会部署多种反爬虫机制来保护其数据。本文将详细介绍如何利用Python编写爬虫程序,获取eBay商品的销量详情…...
【实战篇】巧用 DeepSeek,让 Excel 数据处理更高效
一、为何选择用 DeepSeek 处理 Excel 在日常工作与生活里,Excel 是我们频繁使用的工具。不管是统计公司销售数据、分析学生成绩,还是梳理个人财务状况,Excel 凭借其强大的功能,如数据排序、筛选和简单公式计算,为我们提供了诸多便利。但当面对复杂的数据处理任务,比如从…...
UE (标识符, meta=())笔记
视频连接: [UFSH2024]UE5(标识符, meta(详解, 史上最全)) | 大钊 Epic Games 虚幻社区经理 参考文档: UE5标识符详解 | 史上最全 UnrealSpecifiers | UE5标识符详解 GitHub 老外整理的标识符文档 标识符 CPP_Default_ParamName(18:22&a…...
并发编程 引用类型 原子类 Stamped和Markable atomicMarkableReference表单Ref和标记Markable 面试题
目录 Stamped 和 Markable 的区别 示例代码 所以这个东西是一次性的 从来没听说过 从来没见过 Stamped 和 Markable 的区别 标记号 boolean 一次性的 版本号 整型数 不建议用 Markable 解决 ABA 问题 AtomicMarkableReference 是一个位于 java.util.concurrent.atomic 包中…...
绿联NAS安装cpolar内网穿透工具实现无公网IP远程访问教程
文章目录 前言1. 开启ssh服务2. ssh连接3. 安装cpolar内网穿透4. 配置绿联NAS公网地址 前言 本文主要介绍如何在绿联NAS中使用ssh远程连接后,使用一行代码快速安装cpolar内网穿透工具,轻松实现随时随地远程访问本地内网中的绿联NAS,无需公网…...
【Ubuntu】ARM交叉编译开发环境解决“没有那个文件或目录”问题
【Ubuntu】ARM交叉编译开发环境解决“没有那个文件或目录”问题 零、起因 最近在使用Ubuntu虚拟机编译ARM程序,解压ARM的GCC后想要启动,报“没有那个文件或目录”,但是文件确实存在,环境配置也检查过了没问题,本文记…...
深入浅出 NRM:加速你的 npm 包管理之旅
文章目录 前言一、NRM 是什么?二、为什么需要 NRM?三、NRM 的优势四、NRM 的安装与使用4.1 安装 NRM4.2 查看可用的 npm 源4.3 切换 npm 源4.4 测试 npm 源速度4.5 添加自定义 npm 源4.6 删除 npm 源 五、NRM 的进阶使用六、总结 前言 作为一名 JavaScr…...
微信小程序~电器维修系统小程序
博主介绍:✌程序猿徐师兄、8年大厂程序员经历。全网粉丝15w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…...
使用Python的Tabulate库优雅地格式化表格数据
使用Python的Tabulate库优雅地格式化表格数据 在数据分析和软件开发中,表格数据的展示是一个常见的需求。无论是简单的数据报告,还是复杂的数据可视化,表格都是一种直观且有效的信息展示方式。Python作为一门强大的编程语言,拥有…...
android 适配 api 35(android 15) 遇到的问题
首先升级 targetSdkVersion 和 compileSdkVersion 到 35,升级后发生的报错 一、 解决方案: 升级 gradle 和 gradle 插件版本 com.android.tools.build:gradle -> 8.3.0-alpha02 gradle-wrapper.properties : distributionUrl -> gradle-8.6-bin.zip htt…...
DeepSeek和ChatGPT的对比
最近DeepSeek大放异彩,两者之间有什么差异呢?根据了解到的信息,简单做了一个对比。 DeepSeek 和 ChatGPT 是两种不同的自然语言处理(NLP)模型架构,尽管它们都基于 Transformer 架构,但在设计目标…...
【1】高并发导出场景下,服务器性能瓶颈优化
高并发导出场景下,服务器性能瓶颈通常出现在 CPU、内存、磁盘 I/O 或网络带宽等方面。为了解决这些问题,可以从以下几个方面进行优化: 1. 优化导出逻辑 减少计算复杂度:检查导出逻辑中是否存在不必要的计算或重复操作,…...
