Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

authorization and authentication #7

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/Dnlbb/chat-server
go 1.22.5

require (
github.com/Dnlbb/auth v0.0.0-20241015204829-7b1556231b70
github.com/Dnlbb/auth v0.0.0-20241123185353-e5461bcac8db
github.com/Dnlbb/platform_common v0.0.0-20241104122631-d7f17ae48ff2
github.com/Masterminds/squirrel v1.5.4
github.com/brianvoe/gofakeit/v6 v6.28.0
Expand All @@ -14,7 +14,7 @@ require (
github.com/pkg/errors v0.9.1
github.com/rakyll/statik v0.1.7
github.com/rs/cors v1.11.1
github.com/stretchr/testify v1.8.4
github.com/stretchr/testify v1.9.0
google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38
google.golang.org/grpc v1.67.1
google.golang.org/protobuf v1.35.1
Expand Down
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
github.com/Dnlbb/auth v0.0.0-20241015204829-7b1556231b70 h1:/OfiXdqCE2hWuplwdfongxuJ4yWA/oqyyw5IMWsfy8Q=
github.com/Dnlbb/auth v0.0.0-20241015204829-7b1556231b70/go.mod h1:s4KkLeUqmD90srrP8dDU3bbWSlZmuZj1MmFCU7eR2/o=
github.com/Dnlbb/auth v0.0.0-20241123185353-e5461bcac8db h1:UpXT8CHtuoKSTct1w3mh/N/OArymnEJj3OszdSV1I74=
github.com/Dnlbb/auth v0.0.0-20241123185353-e5461bcac8db/go.mod h1:eJ6Hya97vTR56gutD+E18OceG2FoevleAaotKbdUpbE=
github.com/Dnlbb/platform_common v0.0.0-20241104122631-d7f17ae48ff2 h1:hhCF5Hb1/FjMzKLLGvrquZJZqnJl+XSoMLoD5WpABrY=
github.com/Dnlbb/platform_common v0.0.0-20241104122631-d7f17ae48ff2/go.mod h1:1rRSHI08ymQM2D6FgIGfyX7fU/RT5bA8+CYrkBLAYbM=
github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM=
Expand Down Expand Up @@ -54,13 +54,13 @@ github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/f
github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
Expand Down
4 changes: 3 additions & 1 deletion internal/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ func (a *App) initServiceProvider(_ context.Context) error {
}

func (a *App) initGRPCServer(ctx context.Context) error {
a.grpcServer = grpc.NewServer(grpc.Creds(insecure.NewCredentials()), grpc.UnaryInterceptor(interceptor.ValidateInterceptor))
interceptors := grpc.ChainUnaryInterceptor(interceptor.ValidateInterceptor, a.serviceProvider.GetAuthInterceptor(ctx).AccessInterceptor)

a.grpcServer = grpc.NewServer(grpc.Creds(insecure.NewCredentials()), interceptors)

reflection.Register(a.grpcServer)

Expand Down
70 changes: 58 additions & 12 deletions internal/app/service_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ import (
"context"
"log"

authv1 "github.com/Dnlbb/auth/pkg/auth_v1"
"github.com/Dnlbb/auth/pkg/auth_v1"
userv1 "github.com/Dnlbb/auth/pkg/user_v1"
"github.com/Dnlbb/chat-server/internal/api/chat"
"github.com/Dnlbb/chat-server/internal/config"
accessInterceptor "github.com/Dnlbb/chat-server/internal/interceptor/access"
accessRepo "github.com/Dnlbb/chat-server/internal/repository/access"
"github.com/Dnlbb/chat-server/internal/repository/authrepo"
"github.com/Dnlbb/chat-server/internal/repository/postgres/storage"
"github.com/Dnlbb/chat-server/internal/repository/repointerface"
"github.com/Dnlbb/chat-server/internal/service/access"
"github.com/Dnlbb/chat-server/internal/service/chatserv"
"github.com/Dnlbb/chat-server/internal/service/servinterfaces"
"github.com/Dnlbb/platform_common/pkg/closer"
Expand All @@ -25,15 +29,20 @@ type serviceProvider struct {
httpConfig config.HTTPConfig
swaggerConfig config.SwaggerConf

dbClient db.Client
txManager db.TxManager
chatRepository repointerface.StorageInterface
authRepository repointerface.AuthInterface
dbClient db.Client
txManager db.TxManager

chatService servinterfaces.ChatService
authClient authv1.AuthClient
chatRepository repointerface.StorageInterface
authRepository repointerface.AuthInterface
accessRepository repointerface.Access
userClient userv1.UserApiClient
authClient auth_v1.AuthClient

authController *chat.Controller
chatService servinterfaces.ChatService
accessService servinterfaces.Access

authController *chat.Controller
authInterceptor *accessInterceptor.AuthInterceptor
}

func newServiceProvider() *serviceProvider {
Expand Down Expand Up @@ -134,12 +143,20 @@ func (s *serviceProvider) GetChatRepository(ctx context.Context) repointerface.S

func (s *serviceProvider) GetAuthRepository(_ context.Context) repointerface.AuthInterface {
if s.authRepository == nil {
s.authRepository = authrepo.NewAuthRepo(s.GetAuthClient())
s.authRepository = authrepo.NewAuthRepo(s.GetUserClient())
}

return s.authRepository
}

func (s *serviceProvider) GetAccessRepository(_ context.Context) repointerface.Access {
if s.accessRepository == nil {
s.accessRepository = accessRepo.NewAccessRepo(s.GetAuthClient())
}

return s.accessRepository
}

// GetAuthService инициализация сервиса авторизации.
func (s *serviceProvider) GetAuthService(ctx context.Context) servinterfaces.ChatService {
if s.chatService == nil {
Expand All @@ -152,15 +169,37 @@ func (s *serviceProvider) GetAuthService(ctx context.Context) servinterfaces.Cha
return s.chatService
}

func (s *serviceProvider) GetAuthClient() authv1.AuthClient {
func (s *serviceProvider) GetAccessService(ctx context.Context) servinterfaces.Access {
if s.accessService == nil {
s.accessService = access.NewAccessService(s.GetAccessRepository(ctx))
}

return s.accessService
}

func (s *serviceProvider) GetUserClient() userv1.UserApiClient {
if s.userClient == nil {
conn, err := grpc.Dial("localhost:50052", grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
closer.Add(conn.Close)

s.userClient = userv1.NewUserApiClient(conn)
}

return s.userClient
}

func (s *serviceProvider) GetAuthClient() auth_v1.AuthClient {
if s.authClient == nil {
conn, err := grpc.Dial("localhost:50052", grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
closer.Add(conn.Close)

s.authClient = authv1.NewAuthClient(conn)
s.authClient = auth_v1.NewAuthClient(conn)
}

return s.authClient
Expand All @@ -169,9 +208,16 @@ func (s *serviceProvider) GetAuthClient() authv1.AuthClient {
// GetChatController инициализация контроллера.
func (s *serviceProvider) GetChatController(ctx context.Context) *chat.Controller {
if s.authController == nil {

s.authController = chat.NewController(s.GetAuthService(ctx))
}

return s.authController
}

func (s *serviceProvider) GetAuthInterceptor(ctx context.Context) accessInterceptor.AuthInterceptor {
if s.authInterceptor == nil {
s.authInterceptor = accessInterceptor.NewAuthInterceptor(s.GetAccessService(ctx))
}

return *s.authInterceptor
}
16 changes: 16 additions & 0 deletions internal/interceptor/access/access.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package access

import (
"context"

"google.golang.org/grpc"
)

// AccessInterceptor интерцептор для авторизации.
func (a AuthInterceptor) AccessInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
if err := a.AccessService.Access(ctx, info.FullMethod); err != nil {
return nil, err
}

return handler(ctx, req)
}
17 changes: 17 additions & 0 deletions internal/interceptor/access/controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package access

import (
"github.com/Dnlbb/chat-server/internal/service/servinterfaces"
)

// AuthInterceptor структура реализующая интерцептор для авторизации.
type AuthInterceptor struct {
AccessService servinterfaces.Access
}

// NewAuthInterceptor конструктор для структуры реализующей интерцептор для авторизации.
func NewAuthInterceptor(accessService servinterfaces.Access) *AuthInterceptor {
return &AuthInterceptor{
AccessService: accessService,
}
}
13 changes: 13 additions & 0 deletions internal/repository/access/access.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package access

import (
"context"

"github.com/Dnlbb/auth/pkg/auth_v1"
)

// Access вызываем сервис авторизации для проверки доступа.
func (repo RepoAccess) Access(ctx context.Context, path string) error {
_, err := repo.client.Check(ctx, &auth_v1.CheckRequest{EndpointAddress: path})
return err
}
15 changes: 15 additions & 0 deletions internal/repository/access/accessrepo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package access

import (
"github.com/Dnlbb/auth/pkg/auth_v1"
)

// RepoAccess структура реализующая доступ к клиенту для интерцептора.
type RepoAccess struct {
client auth_v1.AuthClient
}

// NewAccessRepo конструктор для структуры реализующей доступ к клиенту для интерцептора.
func NewAccessRepo(client auth_v1.AuthClient) *RepoAccess {
return &RepoAccess{client: client}
}
6 changes: 3 additions & 3 deletions internal/repository/authrepo/authrepo.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package authrepo

import (
"github.com/Dnlbb/auth/pkg/auth_v1"
"github.com/Dnlbb/auth/pkg/user_v1"
"github.com/Dnlbb/chat-server/internal/repository/repointerface"
)

// AuthRepo структура реализующая методы для похода в сервис auth за айдишниками пользователей.
type AuthRepo struct {
authClient auth_v1.AuthClient
authClient user_v1.UserApiClient
}

// NewAuthRepo конструктор для AuthRepo.
func NewAuthRepo(authClient auth_v1.AuthClient) repointerface.AuthInterface {
func NewAuthRepo(authClient user_v1.UserApiClient) repointerface.AuthInterface {
return AuthRepo{authClient: authClient}
}
2 changes: 1 addition & 1 deletion internal/repository/authrepo/get_ids.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"context"
"fmt"

authv1 "github.com/Dnlbb/auth/pkg/auth_v1"
authv1 "github.com/Dnlbb/auth/pkg/user_v1"
"github.com/Dnlbb/chat-server/internal/models"
)

Expand Down
5 changes: 5 additions & 0 deletions internal/repository/repointerface/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,8 @@ type StorageInterface interface {
type AuthInterface interface {
GetIDs(ctx context.Context, usernames models.Usernames) ([]models.ID, error)
}

// Access интерфейс для проверки доступа.
type Access interface {
Access(ctx context.Context, path string) error
}
36 changes: 36 additions & 0 deletions internal/service/access/access.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package access

import (
"context"
"fmt"
"strings"

"google.golang.org/grpc/metadata"
)

const (
authPrefix = "Bearer "
)

// Access метод дял проверки доступа пользователя.
func (as ServiceAccess) Access(ctx context.Context, path string) error {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return fmt.Errorf("metadata error")
}

authHeader, ok := md["authorization"]
if !ok || len(authHeader) == 0 {
return fmt.Errorf("authorization header is not provided")
}

if !strings.HasPrefix(authHeader[0], authPrefix) {
return fmt.Errorf("invalid authorization header format")
}

accessToken := strings.TrimPrefix(authHeader[0], authPrefix)
mod := metadata.New(map[string]string{"Authorization": "Bearer " + accessToken})
clientCtx := metadata.NewOutgoingContext(ctx, mod)

return as.accessRepository.Access(clientCtx, path)
}
18 changes: 18 additions & 0 deletions internal/service/access/service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package access

import (
"github.com/Dnlbb/chat-server/internal/repository/repointerface"
"github.com/Dnlbb/chat-server/internal/service/servinterfaces"
)

// ServiceAccess структура реализующая сервис интерцептора.
type ServiceAccess struct {
accessRepository repointerface.Access
}

// NewAccessService конструктор для сервиса интерцептора.
func NewAccessService(accessRepository repointerface.Access) servinterfaces.Access {
return &ServiceAccess{
accessRepository: accessRepository,
}
}
5 changes: 5 additions & 0 deletions internal/service/servinterfaces/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ type ChatService interface {
Delete(ctx context.Context, chat models.Chat) error
SendMessage(ctx context.Context, message models.Message) error
}

// Access интерфейс реализующий проверку.
type Access interface {
Access(ctx context.Context, path string) error
}
31 changes: 31 additions & 0 deletions vendor.protogen/google/api/annotations.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package google.api;

import "google/api/http.proto";
import "google/protobuf/descriptor.proto";

option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
option java_multiple_files = true;
option java_outer_classname = "AnnotationsProto";
option java_package = "com.google.api";
option objc_class_prefix = "GAPI";

extend google.protobuf.MethodOptions {
// See `HttpRule`.
HttpRule http = 72295728;
}
Loading