permserver.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. package server
  2. import (
  3. "context"
  4. "fmt"
  5. "net"
  6. "time"
  7. "perms-system-server/internal/consts"
  8. authHelper "perms-system-server/internal/logic/auth"
  9. pub "perms-system-server/internal/logic/pub"
  10. "perms-system-server/internal/middleware"
  11. "perms-system-server/internal/svc"
  12. "perms-system-server/pb"
  13. "github.com/golang-jwt/jwt/v4"
  14. "github.com/zeromicro/go-zero/core/limit"
  15. "google.golang.org/grpc/codes"
  16. "google.golang.org/grpc/peer"
  17. "google.golang.org/grpc/status"
  18. )
  19. type PermServer struct {
  20. svcCtx *svc.ServiceContext
  21. pb.UnimplementedPermServiceServer
  22. }
  23. func NewPermServer(svcCtx *svc.ServiceContext) *PermServer {
  24. return &PermServer{svcCtx: svcCtx}
  25. }
  26. func (s *PermServer) SyncPermissions(ctx context.Context, req *pb.SyncPermissionsReq) (*pb.SyncPermissionsResp, error) {
  27. items := make([]pub.SyncPermItem, len(req.Perms))
  28. for i, p := range req.Perms {
  29. items[i] = pub.SyncPermItem{Code: p.Code, Name: p.Name, Remark: p.Remark}
  30. }
  31. result, err := pub.ExecuteSyncPerms(ctx, s.svcCtx, req.AppKey, req.AppSecret, items)
  32. if err != nil {
  33. if se, ok := err.(*pub.SyncPermsError); ok {
  34. switch se.Code {
  35. case 400:
  36. return nil, status.Error(codes.InvalidArgument, se.Message)
  37. case 401:
  38. return nil, status.Error(codes.Unauthenticated, se.Message)
  39. case 403:
  40. return nil, status.Error(codes.PermissionDenied, se.Message)
  41. default:
  42. return nil, status.Error(codes.Internal, se.Message)
  43. }
  44. }
  45. return nil, status.Error(codes.Internal, "同步权限失败")
  46. }
  47. return &pb.SyncPermissionsResp{Added: result.Added, Updated: result.Updated, Disabled: result.Disabled}, nil
  48. }
  49. func (s *PermServer) Login(ctx context.Context, req *pb.LoginReq) (*pb.LoginResp, error) {
  50. if s.svcCtx.GrpcLoginLimiter != nil {
  51. p, ok := peer.FromContext(ctx)
  52. if ok {
  53. ip, _, _ := net.SplitHostPort(p.Addr.String())
  54. if ip == "" {
  55. ip = p.Addr.String()
  56. }
  57. code, _ := s.svcCtx.GrpcLoginLimiter.Take(fmt.Sprintf("grpc:login:%s", ip))
  58. if code == limit.OverQuota {
  59. return nil, status.Error(codes.ResourceExhausted, "请求过于频繁,请稍后再试")
  60. }
  61. }
  62. }
  63. if req.ProductCode == "" {
  64. return nil, status.Error(codes.InvalidArgument, "productCode不能为空")
  65. }
  66. result, err := pub.ValidateProductLogin(ctx, s.svcCtx, req.Username, req.Password, req.ProductCode)
  67. if err != nil {
  68. if le, ok := err.(*pub.LoginError); ok {
  69. switch le.Code {
  70. case 400:
  71. return nil, status.Error(codes.InvalidArgument, le.Message)
  72. case 401:
  73. return nil, status.Error(codes.Unauthenticated, le.Message)
  74. case 403:
  75. return nil, status.Error(codes.PermissionDenied, le.Message)
  76. }
  77. }
  78. return nil, status.Error(codes.Internal, "登录失败")
  79. }
  80. ud := result.UserDetails
  81. return &pb.LoginResp{
  82. AccessToken: result.AccessToken,
  83. RefreshToken: result.RefreshToken,
  84. Expires: time.Now().Unix() + s.svcCtx.Config.Auth.AccessExpire,
  85. UserId: ud.UserId,
  86. Username: ud.Username,
  87. MemberType: ud.MemberType,
  88. Perms: ud.Perms,
  89. }, nil
  90. }
  91. func (s *PermServer) RefreshToken(ctx context.Context, req *pb.RefreshTokenReq) (*pb.RefreshTokenResp, error) {
  92. claims, err := authHelper.ParseRefreshToken(req.RefreshToken, s.svcCtx.Config.Auth.RefreshSecret)
  93. if err != nil {
  94. return nil, status.Error(codes.Unauthenticated, "refreshToken无效或已过期")
  95. }
  96. productCode := claims.ProductCode
  97. if req.ProductCode != "" && req.ProductCode != productCode {
  98. return nil, status.Error(codes.InvalidArgument, "刷新令牌不允许切换产品")
  99. }
  100. ud := s.svcCtx.UserDetailsLoader.Load(ctx, claims.UserId, productCode)
  101. if ud.Status != consts.StatusEnabled {
  102. return nil, status.Error(codes.PermissionDenied, "账号已被冻结")
  103. }
  104. if productCode != "" && !ud.IsSuperAdmin && ud.MemberType == "" {
  105. return nil, status.Error(codes.PermissionDenied, "您已不是该产品的成员")
  106. }
  107. if claims.TokenVersion != ud.TokenVersion {
  108. return nil, status.Error(codes.Unauthenticated, "登录状态已失效,请重新登录")
  109. }
  110. accessToken, err := authHelper.GenerateAccessToken(
  111. s.svcCtx.Config.Auth.AccessSecret, s.svcCtx.Config.Auth.AccessExpire,
  112. ud.UserId, ud.Username, ud.ProductCode, ud.MemberType, ud.TokenVersion,
  113. )
  114. if err != nil {
  115. return nil, status.Error(codes.Internal, "生成token失败")
  116. }
  117. newRefreshToken, err := authHelper.GenerateRefreshTokenWithExpiry(
  118. s.svcCtx.Config.Auth.RefreshSecret,
  119. claims.ExpiresAt.Time,
  120. ud.UserId, ud.ProductCode, ud.TokenVersion,
  121. )
  122. if err != nil {
  123. return nil, status.Error(codes.Unauthenticated, "refreshToken已过期,请重新登录")
  124. }
  125. return &pb.RefreshTokenResp{
  126. AccessToken: accessToken,
  127. RefreshToken: newRefreshToken,
  128. Expires: time.Now().Unix() + s.svcCtx.Config.Auth.AccessExpire,
  129. }, nil
  130. }
  131. func (s *PermServer) VerifyToken(ctx context.Context, req *pb.VerifyTokenReq) (*pb.VerifyTokenResp, error) {
  132. token, err := jwt.ParseWithClaims(req.AccessToken, &middleware.Claims{}, func(token *jwt.Token) (interface{}, error) {
  133. return []byte(s.svcCtx.Config.Auth.AccessSecret), nil
  134. })
  135. if err != nil || !token.Valid {
  136. return &pb.VerifyTokenResp{Valid: false}, nil
  137. }
  138. claims, ok := token.Claims.(*middleware.Claims)
  139. if !ok || claims.TokenType != consts.TokenTypeAccess {
  140. return &pb.VerifyTokenResp{Valid: false}, nil
  141. }
  142. ud := s.svcCtx.UserDetailsLoader.Load(ctx, claims.UserId, claims.ProductCode)
  143. if ud.Status != consts.StatusEnabled {
  144. return &pb.VerifyTokenResp{Valid: false}, nil
  145. }
  146. if claims.ProductCode != "" && !ud.IsSuperAdmin && ud.MemberType == "" {
  147. return &pb.VerifyTokenResp{Valid: false}, nil
  148. }
  149. if claims.TokenVersion != ud.TokenVersion {
  150. return &pb.VerifyTokenResp{Valid: false}, nil
  151. }
  152. return &pb.VerifyTokenResp{
  153. Valid: true,
  154. UserId: ud.UserId,
  155. Username: ud.Username,
  156. MemberType: ud.MemberType,
  157. Perms: ud.Perms,
  158. }, nil
  159. }
  160. func (s *PermServer) GetUserPerms(ctx context.Context, req *pb.GetUserPermsReq) (*pb.GetUserPermsResp, error) {
  161. ud := s.svcCtx.UserDetailsLoader.Load(ctx, req.UserId, req.ProductCode)
  162. if ud.Username == "" {
  163. return nil, status.Error(codes.NotFound, "用户不存在")
  164. }
  165. return &pb.GetUserPermsResp{
  166. MemberType: ud.MemberType,
  167. Perms: ud.Perms,
  168. }, nil
  169. }