AWD平台2-配置读取和jwt鉴权模块
配置读取和jwt鉴权模块
配置读取
数据库这里的设置写死在代码里肯定是不行的,我们写到一个配置文件中去,然后去解析它。后续上传到仓库中的时候用gitignore就行了
通过通过viper库可以轻松完成配置读取github.com/spf13/viper
在启动时调用这个函数,就回去读取config包下的config.yml
// 初始化设置
func InitConfig() {
workDir, _ := os.Getwd()
viper.SetConfigName("config")
viper.SetConfigType("yml")
viper.AddConfigPath(workDir + "/config")
err := viper.ReadInConfig()
if err != nil {
panic(err)
}
}
获取配置项
这个函数是数据库模块的初始化过程,通过viper.Getxxx读取配置
func InitDB() {
host := viper.GetString("datasource.host")
port := viper.GetString("datasource.port")
database := viper.GetString("datasource.database")
username := viper.GetString("datasource.username")
pwd := viper.GetString("datasource.pwd")
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
username, pwd, host, port, database)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic(err)
}
DB = db
// 初始化一个管理员进去
var admin model.Admin
db.Where("name = ?", "admin").First(&admin)
if admin.ID == 0 {
admin.Name = "admin"
admin.Pwd = auth.Encode("123456")
db.Create(&admin)
}
}
JWT鉴权
jwt是啥
jwt 是 json web token的一个简写,是一个标准,可以有多种实现,他的作用是做身份认证
jwt包含三部分,header、payload、signature
header指定用什么算法加密,payload防有效信息,signature是一个签证信息。
使用过程
客户端带着密码请求服务端后,服务端生成token发给客户端,由客户端保存,客户端之后的请求都带上这个token,供服务端验证身份。
项目中的使用
go标准库中没有jwt模块,我们使用github.com/dgrijalva/jwt-go
这个库
发放token
var jwtKey = []byte("a_secret_crect")
//两种角色,0代表是队伍,1代表是管理员
const TEAM uint8 = 0
const ADMIN uint8 = 1
type Claims struct {
ID uint
Role uint8
jwt.StandardClaims
}
func ReleaseToken(id uint, role uint8) (string, error) {
validity := viper.GetDuration("auth.vilidity") // 有效期写在config.yml里,通过viper读取
expirationTime := time.Now().Add(validity * time.Hour) //指定有效时间
if role != TEAM && role != ADMIN {
return "", errors.New("角色类型不正确")
}
claims := &Claims{
ID: id,
Role: role,
StandardClaims: jwt.StandardClaims{
ExpiresAt: expirationTime.Unix(),
IssuedAt: time.Now().Unix(), //这块的画,去查文档好了
Issuer: "evo",
Subject: "token",
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) //这里用的是HMAC加密的方法,这个方法就够用了
tokenString, err := token.SignedString(jwtKey)
if err != nil {
return "", err
} else {
return tokenString, nil
}
}
解析
解析部分的代码就和能简单,到时候拿到这个token和claims去验证就行。
func ParseToken(tokenString string) (*jwt.Token, *Claims, error) {
claims := &Claims{}
token, err := jwt.ParseWithClaims(tokenString, claims,
func(token *jwt.Token) (i interface{}, err error) {
return jwtKey, nil
})
return token, claims, err
}
写了一个中间件
我这边写了一个中间件去鉴权,因为claims中我放了Role这个定义,然后我们的接口约定好了的,队伍相关的/team开头,管理员相关的是/manager开头,所以这里通过URL.PATH去判断,jwt那边通过再符合角色就能通过
func AuthMW() gin.HandlerFunc {
return func(c *gin.Context) {
tokenStr := c.GetHeader("Authorization")
if tokenStr == "" || !strings.HasPrefix(tokenStr, "Bearer") {
c.JSON(http.StatusUnauthorized, gin.H{
"code": 401,
"msg": "权限不足",
})
c.Abort()
return
}
tokenStr = tokenStr[7:]
//没带token
token, claims, err := auth.ParseToken(tokenStr)
if err != nil || !token.Valid {
c.JSON(http.StatusUnauthorized, gin.H{
"code": 401,
"msg": "权限不足",
})
// Abort 函数会终端这次请求,后面的函数不会再被调用
c.Abort()
return
}
//拿到url中的路径,判断是对选手端还是对管理端的请求
url := c.Request.URL.Path
var role uint8
if strings.HasPrefix(url, "/team") {
role = auth.TEAM
} else {
role = auth.ADMIN
}
if claims.Role != role {
c.JSON(http.StatusUnauthorized, gin.H{
"code": 401,
"msg": "权限不足",
})
}
c.Set("teamId", claims.ID) //把id放进上下文里,方便之后用
c.Next()
}
}
补充 gin的中间件
中间件的实现原理
这个原理其实不复杂,就是一个请求给你一个context,然后这个 context中有一个或者多个gin.HandlerFunc类型的方法,一次请求会依次执行这些方法(这些方法都被放在一个切片中)然后context可以控制他们的执行
上文中c.Next()就是这个中间件处理完了,交给下一个搞,c.Abort()用来打断这个传递的过程,c.Set()方法就用来传递数据,很方便。
源码:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)