赞
踩
参考文档:
https://www.kancloud.cn/jiajunxi/ginweb100/1801414
https://github.com/hanjialeOK/going
最终代码地址:https://github.com/qinliangql/gin_mini_test.git
wget https://dl.google.com/go/go1.20.2.linux-amd64.tar.gz
tar -C /usr/local -zxf go1.20.2.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
// All Tools installed by go are in $GOPATH.
export GOPATH=$PATH:/usr/local/go
export PATH=$PATH:$GOPATH/bin
// https://goproxy.cn is faster than aliyun.
export GOPROXY=https://goproxy.cn
验证安装是否成功
go version
hello world
mkdir hello && cd /hello
go mod init example/hello
创建一个hello.go
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
在hello下运行
go run hello.go
做一个映射出来的
安装
go get github.com/gin-gonic/gin
我映射了端口8001
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
router := gin.Default()
router.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "Hello World")
})
router.Run(":8001")
}
go run hello.go
// For ubuntu 18.04
sudo apt install mysql-server
// start mysql
service mysql start
Change the password for mysql
// login
mysql -u root
// change the password for mysql
use mysql;
update user set authentication_string='' where user='root';
// newpassword: 123456
alter user 'root'@'localhost' identified with mysql_native_password by '123456';
// exit
quit
// restart mysql
service mysql restart
Create database and table.
mysql -u root -p
create database gobase;
use gobase;
CREATE TABLE `account` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
`email` varchar(50) NOT NULL,
`password` varchar(30) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
查看数据库信息(先quit再重新打开mysql)
show databases;
查看table
use gobase;
\\ List Table info
show tables;
\\ Look structure of table
desc account;
安装依赖
go get github.com/gin-gonic/gin
go get gorm.io/driver/mysql
go get gorm.io/gorm
代码:
package main import ( "fmt" "net/http" "net/mail" "github.com/gin-gonic/gin" "gorm.io/driver/mysql" "gorm.io/gorm" // "regexp" ) type UserInfo struct { ID int `form:"id"` Name string `form:"name" binding:"required"` Email string `form:"email" binding:"required,email"` Password string `form:"password" binding:"required,min=6"` } func main() { // 创建一个默认的 Gin 路由器 r := gin.Default() // 创建一个路由,允许用户提交新账户信息 r.POST("/api/register", create) // 启动 Gin 服务器,默认监听在 8001 端口 r.Run(":8001") } // isValidEmail 检查电子邮件格式是否正确 func isValidEmail(email string) bool { _, err := mail.ParseAddress(email) // 如果解析正确,err会变为nil return err == nil } func create(c *gin.Context) { // 绑定请求体到 UserInfo 结构体类型的form var form UserInfo if err := c.ShouldBindJSON(&form); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 检查电子邮件格式是否正确 if !isValidEmail(form.Email) { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid email format"}) return } // 打开数据库,3306是MySQL默认端口 dsn := "root:123456@tcp(127.0.0.1:3306)/gobase" db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // check whether the name exists. var user UserInfo db.Table("account").Where("name = ?", form.Name).First(&user) if (user != UserInfo{}) { c.JSON(http.StatusBadRequest, gin.H{"error": "name exists!"}) return } // check whether the email has been used. db.Table("account").Where("email = ?", form.Email).First(&user) if (user != UserInfo{}) { c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("email %s has been used!", form.Email)}) return } // 保存用户到数据库(:= 对于没有声明的变量会自动声明) user = UserInfo{Name: form.Name, Email: form.Email, Password: form.Password} result := db.Table("account").Create(&user) if result.Error != nil { c.JSON(http.StatusBadRequest, gin.H{"error": result.Error}) return } // 这里只是返回成功消息 c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("Account %s created successfully!",user.Name)}) }
测试代码:
-X 指定发送的请求类型为 POST 请求
-H 设置请求头,指定请求的内容类型为 JSON 格式
curl -X POST -H "Content-Type: application/json" -d '{"name":"QL","email":"qinl@example.com","password":"password"}' http://localhost:8001/api/register
查看数据库当前情况
service mysql start
mysql -u root -p
show databases;
use gobase;
show tables;
SELECT * FROM account;
quit
新加代码:
// 新增路由,允许用户通过提供电子邮件和密码来检索其帐户信息,相当于登陆 r.POST("/api/login", login) /* // 处理登录请求的函数 (这种必须要求输入完整的UserInfo类型信息才行,所以放弃) func login(c *gin.Context) { // 绑定请求体到 UserInfo 结构体类型的 form var form UserInfo if err := c.ShouldBindJSON(&form); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 打开数据库 dsn := "root:123456@tcp(127.0.0.1:3306)/gobase" db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 查询数据库中是否存在匹配的用户记录 var user UserInfo result := db.Table("account").Where("email = ? AND password = ?", form.Email, form.Password).First(&user) if result.Error != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid email or password"}) return } // 返回匹配的用户信息 c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("Welcom user %s !", user.Name)}) } */ func login(c *gin.Context) { // 绑定请求体到 UserInfo 结构体类型的 form email := c.Query("email") password := c.Query("password") // 打开数据库 dsn := "root:123456@tcp(127.0.0.1:3306)/gobase" db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 查询数据库中是否存在匹配的用户记录 var user UserInfo result := db.Table("account").Where("email = ? AND password = ?", email, password).First(&user) if result.Error != nil { c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("Invalid email:%s or password:%s",email,password)}) return } // 返回匹配的用户信息 c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("Welcom user %s !", user.Name)}) }
测试代码:
# 正确案例
curl -X POST "http://localhost:8001/api/login?email=qinl@example.com&password=password"
# 错误案例
curl -X POST "http://localhost:8001/api/login?email=qinl@example.com&password=654321"
安装依赖
go get github.com/golang-jwt/jwt/v5
更新的代码:
package main import ( "fmt" "net/http" "net/mail" "time" "github.com/gin-gonic/gin" "gorm.io/driver/mysql" "gorm.io/gorm" "github.com/golang-jwt/jwt/v5" ) // 创建一个 JWT(JSON Web Token)字符串。 // JWT 是一种用于在网络应用之间安全传递声明的开放标准。 var jwtKey = []byte("my_secret_key") // 用于签名和验证 JWT 的密钥 // input: email || output:string,error func createToken(email string) (string, error) { token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "email": email, "exp": time.Now().Add(time.Minute * 10).Unix(), // 有效时长10分钟 }) return token.SignedString(jwtKey) } func validateToken(tokenString string) (*jwt.Token, error) { token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) } return jwtKey, nil }) if err != nil { return nil, err } if _, ok := token.Claims.(jwt.MapClaims); !ok || !token.Valid { return nil, fmt.Errorf("bad token.") } return token, nil } func validateCookie(c *gin.Context) (*jwt.Token, error) { tokenString, err := c.Cookie("gin_cookie") if err != nil { return nil, err } token, err := validateToken(tokenString) if err != nil { return nil, err } return token, nil } func main() { // 创建一个默认的 Gin 路由器 r := gin.Default() // 创建一个路由,允许用户提交新账户信息 r.POST("/api/register", create) // 新增路由,允许用户通过提供电子邮件和密码来检索其帐户信息,相当于登陆 r.POST("/api/login", login) r.POST("/api/update", update) // 新增的路由,用于更新用户信息 // 启动 Gin 服务器,默认监听在 8001 端口 r.Run(":8001") } func login(c *gin.Context) { // ... // Create the JWT string. token, err := createToken(user.Email) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create token"}) return } // tell the user it's ok. 3600 是最大存活时间1h c.SetCookie("gin_cookie", token, 3600, "/", "", false, true) // 返回匹配的用户信息 c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("Welcom user %s !", user.Name)}) } func update(c *gin.Context) { token, err := validateCookie(c) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // get email from cookie email := token.Claims.(jwt.MapClaims)["email"] // new password password := c.Query("password") name := c.Query("name") // update dsn := "root:123456@tcp(127.0.0.1:3306)/gobase" db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // retrieve the user by email. var user UserInfo db.Table("account").Where("email = ?", email).First(&user) if (user == UserInfo{}) { c.JSON(http.StatusBadRequest, gin.H{"error": "this email has not been registered."}) return } // 更新用户信息 if name != "" { user.Name = name } if password != "" { user.Password = password } // 保存更新后的用户信息到数据库 if err := db.Table("account").Save(&user).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update user"}) return } // 返回更新成功的消息 c.JSON(http.StatusOK, gin.H{"message": "User information updated successfully"}) }
测试代码,用 -i 可以更细致的看到信息,目前还是在curl里面传递cookie的
curl -i -X POST "http://localhost:8001/api/login?email=qinl@example.com&password=password"
curl -i -X POST "http://localhost:8001/api/update?password=newpassword" --cookie "gin_cookie=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InFpbmxAZXhhbXBsZS5jb20iLCJleHAiOjE3MTI4MDU0NTl9.VTLihEYTy-kWZjZhLrwpwIMuPgimpm-DVnYwvhoKnNs"
修改后的数据库
新加代码:
r.POST("/api/delete",delete) // 删除用户信息 func delete(c *gin.Context) { email := c.Query("email") password := c.Query("password") // 打开数据库 dsn := "root:123456@tcp(127.0.0.1:3306)/gobase" db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 查询数据库中是否存在匹配的用户记录 var user UserInfo result := db.Table("account").Where("email = ? AND password = ?", email, password).First(&user) if result.Error != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid email or password"}) return } // 删除用户账户 if err := db.Table("account").Delete(&user).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete account"}) return } // 返回删除成功的消息 c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("Account %s deleted successfully",user.Name)}) }
测试代码:
curl -X POST "http://localhost:8001/api/delete?email=qinl@example.com&password=newpassword"
新加代码:
func show_all(c *gin.Context) { if _, err := validateCookie(c); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 打开数据库 dsn := "root:123456@tcp(127.0.0.1:3306)/gobase" db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } // 查询数据库,获取所有帐户列表 var accountNames []string if err := db.Table("account").Pluck("name", &accountNames).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve accounts"}) return } // 返回帐户列表给客户端 c.JSON(http.StatusOK, accountNames) }
测试代码:
# 先加两个用户
curl -X POST -H "Content-Type: application/json" -d '{"name":"QL","email":"qinl@example.com","password":"password"}' http://localhost:8001/api/register
curl -X POST -H "Content-Type: application/json" -d '{"name":"ZS","email":"zs@example.com","password":"password"}' http://localhost:8001/api/register
# 登录一个用户获取token
curl -i -X POST "http://localhost:8001/api/login?email=qinl@example.com&password=password"
# 用token,获取用户信息
curl -X POST "http://localhost:8001/api/show_all" --cookie "gin_cookie=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InFpbmxAZXhhbXBsZS5jb20iLCJleHAiOjE3MTI4MDc0OTB9.hoB7TY0TorAlmdtm-jyqb8U5nSAehmP7d2n5EjSE1r8"
[“QL”,“ZS”]
主流鉴权方式:
基于Token的认证(Token-based Authentication):用户在登录成功后会收到一个令牌(Token),之后每次请求都需要在请求头中携带这个令牌进行验证。常见的Token包括JWT(JSON Web Token)和OAuth2 Token。
OAuth2认证(OAuth2 Authentication):OAuth2是一种开放标准,允许用户授权第三方应用访问其资源。用户可以通过第三方认证提供者(如Google、Facebook等)进行登录,然后授权给应用访问其资源的权限。
基于Session的认证(Session-based Authentication):用户在登录成功后,服务器会为其创建一个会话(Session),并将会话ID存储在Cookie中,用户在后续的请求中都会携带这个会话ID。服务器通过会话ID来验证用户的身份和权限。
原本的是基于token做的,这里改为基于session做
安装依赖:
go get github.com/gorilla/sessions
新代码:
// 定义一个全局的会话存储对象
var store = sessions.NewCookieStore([]byte("my-secret"))
// 创建会话并将用户ID存储在会话中
session, _ := store.Get(c.Request, "session-name")
session.Values["userID"] = user.ID
session.Save(c.Request, c.Writer)
// 获取会话中的用户ID
session, _ := store.Get(c.Request, "session-name")
_, ok := session.Values["userID"].(int)
if !ok {
c.JSON(http.StatusBadRequest, gin.H{"error": "User not authenticated"})
return
}
测试代码:
# 登录一个用户
curl -i -X POST "http://localhost:8001/api/login?email=qinl@example.com&password=password"
# 用token,获取用户信息
curl -X POST "http://localhost:8001/api/show_all" --cookie "session-name=MTcxMjgyNjI1NHxEdi1CQkFFQ180SUFBUkFCRUFBQUhmLUNBQUVHYzNSeWFXNW5EQWdBQm5WelpYSkpSQU5wYm5RRUFnQUV8hXB2Vl_OaBCvi71u6KLgrh96uhu-Irt-CAzSbxFBMeY="
Namespace(命名空间):
Pod(Pod):
Deployment(部署):
Service(服务):
综上所述,Namespace用于组织和隔离资源,Pod是最小的部署单元,Deployment用于管理Pod副本,Service提供网络访问入口,使应用程序或服务可以在集群内部或外部可达。这些概念共同构成了Kubernetes的核心功能,为容器化应用程序的部署、管理和扩展提供了强大的支持。
Node(节点):
Cluster(集群):
Resource Quota(资源配额):
ConfigMap(配置映射):
Role(角色)和RoleBinding(角色绑定):
Service Account(服务账户):
PersistentVolume(持久化卷)和PersistentVolumeClaim(持久化卷声明):
mkdir ~/.kube
# 需要管理员权限才能复制配置文件
sudo cp /etc/kubernetes/admin.conf ~/.kube/config
# 把文件权限改为自己,xxx就是自己的用户名
sudo chown -R qinl:qinl ~/.kube/
# 修改为自己的命名空间,vim编辑~/.kube/config文件,在context一栏加上一行,然后保存并退出即可:
nano ~/.kube/config
- context:
cluster: kubernetes
user: kubernetes-admin
namespace: xxx # 这里加上自己的命名空间xxx,一般用自己的用户名
name: kubernetes-admin@kubernetes
# 创建自己的命名空间,和上面的xxx对应
kubectl create ns qinl
测试
kubectl get po
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。