此处所采用的乃是 Go 语言的 Gin 框架,借助中间件这一途径来达成认证与鉴权之目的。
认证
基于请求头中的 Authorization 来开展认证工作,判别 token 是否存在,token 是否合法,将 token 中的角色信息等存置于上下文中。
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
if token == "" {
utils.ResponseWithError(c, http.StatusUnauthorized, "未授权")
c.Abort()
return
}
token = strings.TrimPrefix(token, "Bearer ")
tokenMD5, err := config.RedisClient.Get(c, token).Result()
if err != nil {
utils.ResponseWithError(c, http.StatusUnauthorized, "token不存在")
c.Abort()
return
}
// 解析 token
claims, err := utils.ParseToken(tokenMD5)
if err != nil {
utils.ResponseWithError(c, http.StatusUnauthorized, "无效的 token")
c.Abort()
return
}
// 将解析后的内容存入上下文
c.Set("permissions", claims["permissions"])
c.Set("userId", claims["userId"])
// 继续执行
c.Next()
}
}
鉴权
凭借上下文中的角色信息来实施鉴权操作
func AuthorizationMiddleware(requiredPermissions []string) gin.HandlerFunc {
return func(c *gin.Context) {
// 获取用户权限列表
permissions, exists := c.Get("permissions")
if !exists {
utils.ResponseWithError(c, http.StatusForbidden, "权限信息缺失")
c.Abort()
return
}
// 转换成 []string
userPermissions, ok := permissions.([]string)
if !ok {
utils.ResponseWithError(c, http.StatusForbidden, "权限数据格式错误")
c.Abort()
return
}
// 检查用户是否拥有所需的权限
for _, requiredPermission := range requiredPermissions {
if !contains(userPermissions, requiredPermission) {
utils.ResponseWithError(c, http.StatusForbidden, "权限不足")
c.Abort()
return
}
}
// 如果权限匹配,继续执行
c.Next()
}
}
// 检查权限列表是否包含某个权限
func contains(permissions []string, permission string) bool {
for _, p := range permissions {
if p == permission {
return true
}
}
return false
}
在路由中使用
r := gin.Default()
// 认证中间件
r.Use(AuthMiddleware())
// 使用鉴权中间件
r.GET("/admin", AuthorizationMiddleware("admin"), func(c *gin.Context) {
// 只有管理员才能访问这个路由
c.JSON(http.StatusOK, gin.H{"message": "Welcome Admin!"})
})
r.GET("/user", AuthorizationMiddleware("user"), func(c *gin.Context) {
// 只有普通用户才能访问这个路由
c.JSON(http.StatusOK, gin.H{"message": "Welcome User!"})
})