210 lines
6.0 KiB
Go
210 lines
6.0 KiB
Go
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
|
||
}
|