【REST2SQL】12 REST2SQL增加Token生成和验证

【REST2SQL】01RDB关系型数据库REST初设计
【REST2SQL】02 GO连接Oracle数据库
【REST2SQL】03 GO读取JSON文件
【REST2SQL】04 REST2SQL第一版Oracle版实现
【REST2SQL】05 GO 操作 达梦 数据库
【REST2SQL】06 GO 跨包接口重构代码
【REST2SQL】07 GO 操作 Mysql 数据库
【REST2SQL】08 日志重构增加输出到文件log.txt
【REST2SQL】09 给Go的可执行文件exe加图标和版本信息等
【REST2SQL】10 REST2SQL操作指南
【REST2SQL】11 基于jwt-go生成token与验证


【REST2SQL】11 基于jwt-go生成token与验证的Token生成和验证合并到【REST2SQL】

1 Rest2sql目录下新建token子目录

  • Rest2sql目录下新建token子目录
  • 拷贝 【REST2SQL】11 基于jwt-go生成token与验证 的mytoken.go
  • mytoken.go改名为 token.go
    在这里插入图片描述

2 token.go的代码重构

  • 包名改为token
  • 屏蔽或删除 main()入口函数
  • 重构全局变量,都改为外部不可见,即变量名改为首字母改为小写即可
  • 只暴露生成token函数GenerateTokenHandler()和验证token函数ValidateTokenHandler()
  • 暴露函数第二个参数重构

重构完成的代码如下:

package token

import (
	"crypto/rand"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"time"

	jwt "github.com/dgrijalva/jwt-go"
)

// 初始化函数
func init() {
	// 实例化计数计时器
	counter = NewCounter()

	// 初始化随机 Key
	key, err := generateRandomString(16)
	if err != nil {
		log.Fatal(err)
	}

	// 打印时间戳
	fmt.Println("Start At timeStamp :", timeStamp, time.Unix(timeStamp, 0), key)
}

// Counter 定义一个简单的计数器
type Counter struct {
	value      int
	timeStampc int64 // 时间戳,用于定期更新密钥key
}

// 计时器变量实例
var counter *Counter

// NewCounter 创建一个新的计数器
func NewCounter() *Counter {
	return &Counter{value: 0, timeStampc: time.Now().Unix()}
}

// Increment 增加计数器的值
func (c *Counter) Increment() {
	c.value++
	c.timeStampc = time.Now().Unix()
}

// // Decrement 减少计数器的值
// func (c *Counter) Decrement() {
// 	c.value--
// }

// // Reset 重置计数器的值为0
// func (c *Counter) Reset() {
// 	c.value = 0
// }

// GetValue 返回计数器的当前值
func (c *Counter) GetCounter() *Counter {
	return c
}

// 
// 定义Token的Claims
type customClaims struct {
	Userid string `json:"userid"`
	Passwd string `json:"passwd"`
	jwt.StandardClaims
}

// 定义Token相关变量
var (
	uid string = "BLMa"  //用户名
	pwd string = "5217"  //密码
	key string = "token" //默认密钥,服务启动时会修改
	iss string = "guwuy" //签发者

	timeStamp   int64         = time.Now().Unix() // 时间戳,用于定期更新密钥key
	timeSecond  int64         = 20                //60 * 60 * 24 * 7  //一周时间的秒数,用于7天修改一次Key
	timeExpires time.Duration = 60 * 60 * 8       // Token 过期时间 秒数,8小时
)

// generateRandomString 生成一个指定长度的随机字符串
func generateRandomString(length int) (string, error) {
	const letters = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	bytes := make([]byte, length)
	if _, err := rand.Read(bytes); err != nil {
		return "", err
	}
	for i, b := range bytes {
		bytes[i] = letters[b%byte(len(letters))]
	}
	return string(bytes), nil
}

// 定期生成随机Key
func generateRandomKey() {
	//当前时间戳
	timestamp := counter.GetCounter().timeStampc
	//fmt.Println("Now timeStamp,timestamp:", timeStamp, timestamp)

	if timestamp-timeStamp > timeSecond {
		counter.Increment()
		// 修改Key
		key, err := generateRandomString(16)
		if err != nil {
			log.Fatal(err)
		}
		timeStamp = timestamp // 更新Key修改的时间戳

		// 打印时间戳
		fmt.Println("Now timeStamp :", timeStamp, time.Unix(timeStamp, 0), key)
	}
}

// 生成新的Token
func generateToken(userId string) (string, error) {
	// 计数器,计时器
	counter.Increment()

	// 设置Claims
	claims := customClaims{
		Userid: userId,
		Passwd: pwd,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: time.Now().Add(time.Second * timeExpires).Unix(), // 设置过期时间
			Issuer:    iss,                                              // 设置签发者
		},
	}

	// 创建Token
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	// 定期生成随机Key
	generateRandomKey()
	// 签名Token,这里使用硬编码的密钥,实际生产环境中应使用更安全的密钥管理方式
	signedToken, err := token.SignedString([]byte(key))
	if err != nil {
		return "", err
	}

	return signedToken, nil
}

// 验证Token
func validateToken(tokenString string) (*customClaims, error) {
	// 解析Token
	token, err := jwt.ParseWithClaims(tokenString, &customClaims{}, func(token *jwt.Token) (interface{}, error) {
		// 验证Token的签名,这里使用硬编码的密钥
		return []byte(key), nil
	})

	if claims, ok := token.Claims.(*customClaims); ok && token.Valid {
		return claims, nil
	}

	return nil, err
}

// HTTP处理函数:生成Token
func GenerateTokenHandler(w http.ResponseWriter, uid_pwd map[string]string) {
	//请求参数,实际情况下,这里可能从请求参数或身份验证过程中获取
	uid = uid_pwd["Userid"]
	pwd = uid_pwd["Passwd"]
	// 这里加uid,pwd的数据库校验
	//fmt.Println(uid, pwd)
	token, err := generateToken(uid)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string]string{
		"token": token,
	})
}

// HTTP处理函数:验证Token
func ValidateTokenHandler(w http.ResponseWriter, tokenString string) {

	claims, err := validateToken(tokenString)
	if err != nil {
		http.Error(w, err.Error(), http.StatusUnauthorized)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string]interface{}{
		"userid":  claims.Userid,
		"expires": claims.ExpiresAt,
	})
}

// // main入口
// func main() {
// 	// 检查并生成Key
// 	GenerateRandomKey()

// 	// Token 路由
// 	http.HandleFunc("/generate-token", generateTokenHandler)
// 	// Http://localhost:8080/generate-token?userid=blma&passwd=5217
// 	// curl Http://localhost:8080/generate-token?userid=blma%26passwd=5217
// 	http.HandleFunc("/validate-token", validateTokenHandler)
// 	//curl http://localhost:8080/validate-token -H "Authorization:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOiI5OTk4IiwicGFzc3dkIjoiODk5OSIsImV4cCI6MTcwOTcyMDU0MSwiaXNzIjoiZ3V3dXkifQ.UXiW-cgnDZfGUmLtv_yme6gzFZ9XDiKaNATIdFzJ2fY"

// 	fmt.Println("Starting Token server ...")
// 	fmt.Println("Http://localhost:8080/generate-token?userid=&passwd=")
// 	fmt.Println("curl http://localhost:8080/validate-token -H \"Authorization:token\"")
// 	log.Fatal(http.ListenAndServe(":8080", nil))
// }

3 rest2sql.go的 handler() 增加token访问路由

重构的核心代码如下:

  • 请求路径错误提示代码:
// 2请求路径Path
	req["Path"] = r.URL.Path
	path := strings.Split(r.URL.Path, "/")
	if len(path) < 3 {
		w.Write([]byte("400 Bad Request错误请求。请尝试/rest/xxx or /sql/xxx or /TOKEN/xxx"))
		return
	}
  • 允许的请求路径代码:
// 3 请求类型REST or SQL or Token
	rors := strings.ToUpper(fmt.Sprint(path[1]))
	// 支持的请求类型
	if !(rors == "REST" || rors == "SQL" || rors == "TOKEN") {
		w.Write([]byte("400 Bad Request错误请求。请尝试/REST/xxx or /SQL/xxx or /TOKEN/xxx"))
		return
	}
  • 请求头token结构代码:
// 8 请求头 Authorization
	req["Authorization"] = r.Header.Get("Authorization") // 假设Token在Authorization头中
  • 请求参数增加userid和passw代码:
// 9 请求参数
	query := r.URL.Query()
	req["Userid"] = query.Get("userid") // 登录用户
	req["Passwd"] = query.Get("passwd") // 登录密码

3 dothing.go代码重构

分支代码:
case "TOKEN":
		// Token 生成与校验
		doTOKEN(w, req)
  • doTiken函数代码:
// 根据请求参数执行不同的TOKEN操作 ///
func doTOKEN(w http.ResponseWriter, req map[string]interface{}) {
	// token操作, generate or validate
	resToken := strings.ToLower(req["ResName"].(string))
	switch resToken {
	case "generate-token":
		// w.Write([]byte("generate-token"))
		var uid_pwd map[string]string = make(map[string]string)
		uid_pwd["Userid"] = req["Userid"].(string)
		uid_pwd["Passwd"] = req["Passwd"].(string)
		
		token.GenerateTokenHandler(w, uid_pwd)

		// http://127.0.0.1:5217/TOKEN/generate-token?userid=9998&passwd=8999
	case "validate-token":
		//w.Write([]byte("validate-token"))
		var tokenString string = req["Authorization"].(string)
		token.ValidateTokenHandler(w, tokenString)

		// curl http://localhost:5217/token/validate-token -H "Authorization:token"
	}
}

4 实操演练

Setp 1 启动服务

在这里插入图片描述

Step 2 生成Token

http://127.0.0.1:5217/TOKEN/generate-token?userid=9998&passwd=8999

在这里插入图片描述

Step 3 验证Token

curl http://localhost:5217/token/validate-token -H "Authorization:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MDk4Njk0OTEsImlzcyI6Imd1d3V5In0.7CLaQKNXZOhnirLfOb_1meYYnc6KVDkXUhrxbfvYgKw"

在这里插入图片描述

Step 4 服务日志

在这里插入图片描述


本文完。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

阿里云有免费服务器吗?在哪领?

阿里云服务器免费试用申请链接入口&#xff1a;aliyunfuwuqi.com/go/free 阿里云个人用户和企业用户均可申请免费试用&#xff0c;最高可以免费使用3个月&#xff0c;阿里云服务器网分享阿里云服务器免费试用申请入口链接及云服务器配置&#xff1a; 阿里云免费服务器领取 阿里…

数据结构之deque双端队列

一、概念&#xff1a; 众所周知&#xff0c;数据结构是用来存储数据&#xff0c;deque也不例外&#xff0c;他是集结了队列和栈的性质而成的结构&#xff0c;他几乎拥有所有数据结构能有的操作&#xff0c;看似已经大杀四方&#xff0c;可实际情况如何呢&#xff0c;那就带者这…

ssm+vue的农业信息管理系统(有报告)。Javaee项目,ssm vue前后端分离项目。

演示视频&#xff1a; ssmvue的农业信息管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;ssm vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&…

C语言第三十七弹---文件操作(下)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 文件操作 1、文件的随机读写 1.1、fseek 1.2、ftell 1.3、rewind 2、文件读取结束的判定 2.1、被错误使用的 feof 3、文件缓冲区 总结 1、文件的随机读写…

“轻松入门Electron:一步步构建梦想中的桌面软件

在数字化的浪潮中&#xff0c;桌面应用依旧占据着其独特而重要的位置&#xff0c;不论是在企业解决方案、专业工具软件还是个性化应用领域中都是如此。随着技术的演进&#xff0c;创建这些应用的过程已经变得更为简单和可行&#xff0c;尤其是随着Electron等框架的出现。Electr…

启动查看工具总结

启动目标&#xff1a;2s内优秀&#xff0c;2-5s普通&#xff0c;之后的都需要优化&#xff0c;热启动则是1.5s-2s内 1 看下大致串联启动流程&#xff1a; App 进程在 Fork 之后&#xff0c;需要首先执行 bindApplication Application 的环境创建好之后&#xff0c;就开始activ…

Dynamo——常用几何形体的创建与编辑(二)

上一次&#xff0c;我们简单整理了一些创建几何形体的节点用法&#xff0c;今天我们接着整理一些&#xff0c;几何形体的编辑方法。 一、坐标点的平移复制 [Point.Add] 使用节点 “Vector.ByCoordinates” 生成一个向量&#xff0c;将该向量连接到 “Point.Add” 节点的输入端 …

使用R语言进行聚类分析

一、样本数据描述 城镇居民人均消费支出水平包括食品、衣着、居住、生活用品及服务、通信、文教娱乐、医疗保健和其他用品及服务支出这八项指标来描述。表中列出了2016年我国分地区的城镇居民的人均消费支出的原始数据&#xff0c;数据来源于2017年的《中国统计年鉴》&#xf…

点云数据切片及使用threejs加载

测试点云数数据大小 2.94G cesium 加载&#xff1a; 数据处理&#xff1a;cesiumlab 点云切片->cesium 3Dtiles API 加载 threejs 加载 只支持 pcd 格式&#xff0c;故将 lsa 数据导入&#xff0c;在导出为了 pcd&#xff0c;在将数据直接转出 pcd 会直接闪退&#xff0…

HUAWEI 华为交换机 配置 MAC 防漂移 防MAC伪造示例

组网需求 某企业网络中&#xff0c;用户需要访问企业的服务器。如果某些非法用户从其他接口假冒服务器的MAC 地址发送报文&#xff0c;则服务器的 MAC 地址将在其他接口学习到。这样用户发往服务器的报文就会发往非法用户&#xff0c;不仅会导致用户与服务器不能正常通信&…

FreeRTOS之消息队列的示例记录

前言 我的理解是 消息队列主要是用于任务之间存在主从关系的时候&#xff0c;比如说显示屏显示数据&#xff0c;显示屏的作用只是提供显示&#xff0c;数据来源应该是其他任务线程&#xff0c;所以就存在多个线程通信问题。 FreeRTOS中消息队列 这里我们以数组为例&#xff…

Pytorch学习 day07(神经网络基本骨架的搭建、2D卷积操作、2D卷积层)

神经网络基本骨架的搭建 Module&#xff1a;给所有的神经网络提供一个基本的骨架&#xff0c;所有神经网络都需要继承Module&#xff0c;并定义_ _ init _ _方法、 forward() 方法在_ _ init _ _方法中定义&#xff0c;卷积层的具体变换&#xff0c;在forward() 方法中定义&am…

Python 3 教程(1)

Python 3 教程 Python 的 3.0 版本&#xff0c;常被称为 Python 3000&#xff0c;或简称 Py3k。相对于 Python 的早期版本&#xff0c;这是一个较大的升级。为了不带入过多的累赘&#xff0c;Python 3.0 在设计的时候没有考虑向下兼容。 Python 介绍及安装教程我们在后期中有介…

【高效开发工具系列】Windows 系统下将 Windows 键盘的 ctrl 和 alt 互换

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

JVM——执行引擎

文章目录 1、概述2、计算机语言的发展史2.1、机器码2.2、汇编语言2.3、高级语言2.4、字节码 3、Java代码编译和执行过程4、解释器5、JIT编译器5.1、为什么HotSpot VM同时存在JIT编译器和解释器5.2、热点代码探测确定何时JIT5.3、设置执行模式5.4、C1编译器和C2编译器 6、AOT编译…

【蓝桥杯-单片机】LED和按键小练习:Led彩灯控制系统

文章目录 【蓝桥杯-单片机】LED和按键小练习&#xff1a;Led彩灯控制系统01 题目描述02 题目解答03 本题总结整体逻辑框架&#xff08;详细版&#xff09;整体逻辑框架&#xff08;缩略版&#xff09;按键读取模块按键消抖模块流水灯显示模式&#xff08;1&#xff09;从上向下…

USB PD快充充电器静电浪涌保护TVS

USB PD快充充电器已经成为生活中无处不在的必备物品&#xff0c;它能够为我们的各种电子设备提供快速而便捷的充电解决方案&#xff0c;比如智能手机和平板电脑&#xff0c;笔记本电脑&#xff0c;可穿戴设备&#xff0c;摄像机和摄像设备&#xff0c;汽车充电器&#xff0c;以…

图片二维码不限扫码次数怎么做?长期有效的图片二维码在线生成技巧

图片制作二维码能长期使用吗&#xff1f;在生活中很多地方都可以看到很多存有图片的二维码&#xff0c;通过扫码后查看图片内容&#xff0c;比如一些公共场所、产品介绍、景区等场所中都有图片转二维码的应用。那么怎么做出可以长期扫码展示图片二维码呢&#xff0c;其实方法很…

Awesome-Backbones-main——alexnet模型分析

AlexNet作为骨干网络相对较老&#xff0c;可能在复杂数据集上的表现不如一些最新的深度网络结构&#xff0c;如ResNet、EfficientNet等&#xff0c;学习率调整策略中采用了阶梯式学习率更新器&#xff0c;可能并不总是适合所有数据集和模型&#xff0c;需要根据具体情况调整学习…

【办公类-21-09】三级育婴师 视频转音频Python

背景需求&#xff1a; 用AI对话工具试试能否Python将MP4视频转成音频&#xff0c;再转成文字docx&#xff08;不用格式工厂转&#xff09; 结果&#xff1a; 视频MP4转音频wav 视频MP4转音频wav 作者&#xff1a;AI对话大师&#xff0c; 时间&#xff1a;2024年3月8日 impo…