add full auth

This commit is contained in:
2026-07-06 15:56:10 +07:00
parent 434627d61a
commit 6be4142487
14 changed files with 1512 additions and 50 deletions
+36
View File
@@ -2,8 +2,13 @@ package app
import (
"context"
"evening_detective_server/internal/modules/processor_jwt"
"evening_detective_server/internal/services/users_service"
proto "evening_detective_server/proto"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
)
type server struct {
@@ -73,3 +78,34 @@ func (s *server) Refresh(ctx context.Context, req *proto.RefreshReq) (*proto.Ref
RefreshToken: refreshToken,
}, nil
}
func (s *server) GetUsers(ctx context.Context, req *proto.GetUsersReq) (*proto.GetUsersRsp, error) {
claims := ctx.Value("claims").(*processor_jwt.JWTClaims)
if !claims.HasRole("admin") {
return nil, status.Errorf(codes.PermissionDenied, "permission denied")
}
users, err := s.usersService.GetUsers(ctx)
if err != nil {
return &proto.GetUsersRsp{
Error: err.Error(),
}, nil
}
resUsers := make([]*proto.User, 0, len(users))
for _, user := range users {
resUsers = append(
resUsers,
&proto.User{
Id: int32(user.ID),
Username: user.Username,
Email: user.Email,
Roles: user.Roles,
IsActive: user.IsActive,
CreatedAt: timestamppb.New(user.CreatedAt),
},
)
}
return &proto.GetUsersRsp{
Users: resUsers,
}, nil
}
@@ -0,0 +1,45 @@
package processor_jwt
import (
"context"
"strings"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)
func NewAuthorizationInterceptor(
publicMethods map[string]bool,
processorJWT IProcessorJWT,
) grpc.UnaryServerInterceptor {
return func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) {
if publicMethods[info.FullMethod] {
return handler(ctx, req)
}
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, status.Errorf(codes.Unauthenticated, "metadata is not provided")
}
values := md.Get("authorization")
if len(values) == 0 {
return nil, status.Errorf(codes.Unauthenticated, "authorization token is not provided")
}
token := strings.TrimPrefix(values[0], "Bearer ")
if token == "" {
return nil, status.Errorf(codes.Unauthenticated, "invalid token format")
}
claims, err := processorJWT.GetClaims(token)
if err != nil {
return nil, status.Errorf(codes.Unauthenticated, "invalid token")
}
ctx = context.WithValue(ctx, "claims", claims)
return handler(ctx, req)
}
}
+3
View File
@@ -1,5 +1,7 @@
package repos
import "time"
type User struct {
ID int
Username string
@@ -7,4 +9,5 @@ type User struct {
PasswordHash string
Roles []string
IsActive bool
CreatedAt time.Time
}
+38
View File
@@ -137,3 +137,41 @@ func (s *UsersRepo) GetUserByID(
return user, nil
}
func (s *UsersRepo) GetUsers(
ctx context.Context,
) ([]*repos.User, error) {
rows, err := s.pool.Query(
ctx,
`SELECT id, username, email, roles, is_active, created_at
FROM users
ORDER BY created_at DESC`,
)
if err != nil {
return nil, err
}
defer rows.Close()
var users []*repos.User
for rows.Next() {
user := &repos.User{}
err := rows.Scan(
&user.ID,
&user.Username,
&user.Email,
&user.Roles,
&user.IsActive,
&user.CreatedAt,
)
if err != nil {
return nil, err
}
users = append(users, user)
}
if err := rows.Err(); err != nil {
return nil, err
}
return users, nil
}
@@ -6,6 +6,7 @@ import (
"evening_detective_server/internal/modules/email_sender"
"evening_detective_server/internal/modules/password_generator"
"evening_detective_server/internal/modules/processor_jwt"
"evening_detective_server/internal/repos"
"evening_detective_server/internal/repos/refresh_tokens_repo"
"evening_detective_server/internal/repos/users_repo"
"fmt"
@@ -186,3 +187,13 @@ func (s *UsersService) Refresh(
return accessToken, refreshToken, nil
}
func (s *UsersService) GetUsers(
ctx context.Context,
) ([]*repos.User, error) {
users, err := s.usersRepo.GetUsers(ctx)
if err != nil {
return nil, err
}
return users, nil
}