Files
hm-server/app/main/api/internal/middleware/adminauthinterceptormiddleware.go
2025-09-30 17:44:18 +08:00

210 lines
6.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package middleware
import (
"context"
"net/http"
"strings"
"tydata-server/app/main/api/internal/config"
"tydata-server/app/main/model"
jwtx "tydata-server/common/jwt"
"tydata-server/common/xerr"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/rest/httpx"
)
const (
// 定义错误码
AdminErrCodeUnauthorized = 401
)
type AdminAuthInterceptorMiddleware struct {
Config config.Config
// 注入model依赖
AdminUserModel model.AdminUserModel
AdminUserRoleModel model.AdminUserRoleModel
AdminRoleModel model.AdminRoleModel
AdminApiModel model.AdminApiModel
AdminRoleApiModel model.AdminRoleApiModel
}
func NewAdminAuthInterceptorMiddleware(c config.Config,
adminUserModel model.AdminUserModel,
adminUserRoleModel model.AdminUserRoleModel,
adminRoleModel model.AdminRoleModel,
adminApiModel model.AdminApiModel,
adminRoleApiModel model.AdminRoleApiModel) *AdminAuthInterceptorMiddleware {
return &AdminAuthInterceptorMiddleware{
Config: c,
AdminUserModel: adminUserModel,
AdminUserRoleModel: adminUserRoleModel,
AdminRoleModel: adminRoleModel,
AdminApiModel: adminApiModel,
AdminRoleApiModel: adminRoleApiModel,
}
}
func (m *AdminAuthInterceptorMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// 1. JWT 校验
claims, err := m.validateJWT(r)
if err != nil {
httpx.Error(w, err)
return
}
// 2. 检查用户类型是否为管理员
if claims.UserType != model.UserTypeAdmin {
httpx.Error(w, errors.Wrapf(xerr.NewErrCode(xerr.TOKEN_EXPIRE_ERROR), "用户类型错误,需要管理员权限"))
return
}
// 3. 检查平台标识
if claims.Platform != model.PlatformAdmin {
httpx.Error(w, errors.Wrapf(xerr.NewErrCode(xerr.TOKEN_EXPIRE_ERROR), "平台标识错误,需要管理员平台"))
return
}
// 4. 将用户信息放入上下文
ctx := context.WithValue(r.Context(), jwtx.ExtraKey, claims)
r = r.WithContext(ctx)
// 5. API 权限校验
if err := m.validateApiPermission(r.Context(), claims.UserId, r.Method, r.URL.Path); err != nil {
httpx.Error(w, err)
return
}
// 6. 通过所有校验,继续处理请求
next(w, r)
}
}
// validateJWT 验证JWT token
func (m *AdminAuthInterceptorMiddleware) validateJWT(r *http.Request) (*jwtx.JwtClaims, error) {
// 从请求头中获取Authorization字段
authHeader := r.Header.Get("Authorization")
if authHeader == "" {
return nil, errors.Wrapf(xerr.NewErrCode(AdminErrCodeUnauthorized), "缺少Authorization头")
}
// 去掉Bearer前缀
token := strings.TrimPrefix(authHeader, "Bearer ")
if token == authHeader {
return nil, errors.Wrapf(xerr.NewErrCode(AdminErrCodeUnauthorized), "Authorization头格式错误缺少Bearer前缀")
}
claims, err := jwtx.ParseJwtToken(token, m.Config.AdminConfig.AccessSecret)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(AdminErrCodeUnauthorized), "token解析失败: %v", err)
}
return claims, nil
}
// validateApiPermission 验证API权限
func (m *AdminAuthInterceptorMiddleware) validateApiPermission(ctx context.Context, userId int64, method, path string) error {
// 1. 获取用户角色
userRoles, err := m.getUserRoles(ctx, userId)
if err != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取用户角色失败: %v", err)
}
if len(userRoles) == 0 {
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "用户没有分配角色")
}
// 2. 检查是否为超级管理员
if m.isSuperAdmin(ctx, userRoles) {
// 超级管理员拥有所有权限,直接放行
return nil
}
// 3. 获取当前请求的API信息
api, err := m.getApiByMethodAndPath(ctx, method, path)
if err != nil {
// 如果API不存在可能是公开接口放行
return nil
}
// 4. 检查用户角色是否有该API权限
hasPermission, err := m.checkRoleApiPermission(ctx, userRoles, api.Id)
if err != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "检查API权限失败: %v", err)
}
if !hasPermission {
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "权限不足,无法访问该接口")
}
return nil
}
// getUserRoles 获取用户角色
func (m *AdminAuthInterceptorMiddleware) getUserRoles(ctx context.Context, userId int64) ([]int64, error) {
builder := m.AdminUserRoleModel.SelectBuilder().Where("user_id = ?", userId)
userRoles, err := m.AdminUserRoleModel.FindAll(ctx, builder, "")
if err != nil {
return nil, err
}
var roleIds []int64
for _, userRole := range userRoles {
roleIds = append(roleIds, userRole.RoleId)
}
return roleIds, nil
}
// isSuperAdmin 检查是否为超级管理员
func (m *AdminAuthInterceptorMiddleware) isSuperAdmin(ctx context.Context, roleIds []int64) bool {
// 检查是否有超级管理员角色
for _, roleId := range roleIds {
role, err := m.AdminRoleModel.FindOne(ctx, roleId)
if err != nil {
continue
}
// 检查是否为超级管理员角色
if role.RoleCode == model.AdminRoleCodeSuper {
return true
}
}
return false
}
// getApiByMethodAndPath 根据方法和路径获取API信息
func (m *AdminAuthInterceptorMiddleware) getApiByMethodAndPath(ctx context.Context, method, path string) (*model.AdminApi, error) {
builder := m.AdminApiModel.SelectBuilder().
Where("method = ? AND url = ? AND status = ?", method, path, 1)
apis, err := m.AdminApiModel.FindAll(ctx, builder, "")
if err != nil {
return nil, err
}
if len(apis) == 0 {
return nil, errors.New("API不存在")
}
return apis[0], nil
}
// checkRoleApiPermission 检查角色是否有API权限
func (m *AdminAuthInterceptorMiddleware) checkRoleApiPermission(ctx context.Context, roleIds []int64, apiId int64) (bool, error) {
for _, roleId := range roleIds {
// 检查角色是否有该API权限
_, err := m.AdminRoleApiModel.FindOneByRoleIdApiId(ctx, roleId, apiId)
if err == nil {
// 找到权限记录,说明有权限
return true, nil
}
// 如果错误不是NotFound说明是其他错误
if !errors.Is(err, model.ErrNotFound) {
return false, err
}
}
return false, nil
}