diff --git a/README.md b/README.md index aac818f..26a2fd4 100644 --- a/README.md +++ b/README.md @@ -202,4 +202,51 @@ runtime.HTTPError = errors.CustomHTTPError - implement logger for `pkg/v1/utils/errors/errors.go` to log any of error from our service - implement logger for `router/http.go` to log response grpc rest api service - `go run .` -- test call method callapi will generate hif log, custom-error generate error log, call rest will generate rest log \ No newline at end of file +- test call method callapi will generate hif log, custom-error generate error log, call rest will generate rest log + +### Jwt ( Json Web Tokens ) Auth +- add jwt configs to `config.yaml`, jwt: issuer: ajikamaludin, key: P@ssw0rd, type: Bearer +- changes `pkg/v1/config/config.go` add new config struct and validate config, [UPDATE] change New to GetInstance for singleton config +- changes `pkg/v1/utils/constants/constants.go` to add new const for jwt token expired and refresh token expired +- `go get github.com/dgrijalva/jwt-go`, lib to handle jwt token in go +- create new pkg `pkg/v1/jwt/jwt.go`, implement Generate token and Claim token +- create new proto `proto/v1/auth/auth.proto` auth for login and register service, recompile `sh compile-proto.sh` [UPDATE] +- implement `api/v1/auth/auth.go`, `api/v1/auth/login.go` and `api/v1/auth/register.go` +- register new grpc service to grpc server +```go +authpb.RegisterAuthServiceServer(grpcServer, auth.New(configs, logger)) +``` +- register new grp service to grpc gateay (http.go) +```go +authpb.RegisterAuthServiceHandler, +``` +- implement middleware in grpc server, for check jwtoken in every request , and add +```go + grpcServer := grpc.NewServer( + grpc.UnaryInterceptor( + grpc_middleware.ChainUnaryServer( + authInterceptor, + ), + ), + ) +``` +- test call login with any userid and password +```bash +curl -X POST -d '{"userId":"aji","password":"pass"}' http://localhost:8080/api/v1/auth/login +``` +- result +```json +{ + "success":true, + "code":"0000", + "desc":"SUCCESS", + "auth": + { + "type":"Bearer", + "access":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWppIiwiZXhwIjoxNjU4MTU2Njk5LCJpc3MiOiJiYW5rcmF5YSJ9.5o3b0twKzuqVzPtS68GMD6pw91m4JbCaJrg57iQw06A", + "expiredPeriode":3600, + "refresh":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWppIiwiaXNSZWZyZXNoIjp0cnVlLCJleHAiOjE2NTgxNTY2OTksImlzcyI6ImJhbmtyYXlhIn0.C8ZF9JFYWJIg3A0f9Ax2kWlPd1LJPeKZtDOSjX_KW6E" + } +} +``` +- use access token to access other resource / service - method diff --git a/api/v1/auth/auth.go b/api/v1/auth/auth.go new file mode 100644 index 0000000..27c7b3e --- /dev/null +++ b/api/v1/auth/auth.go @@ -0,0 +1,52 @@ +package auth + +import ( + "github.com/ajikamaludin/go-grpc_basic/configs" + "github.com/ajikamaludin/go-grpc_basic/pkg/v1/utils/errors" + authpb "github.com/ajikamaludin/go-grpc_basic/proto/v1/auth" + "github.com/sirupsen/logrus" + "google.golang.org/grpc/codes" +) + +// Method is the methode type +type Method int + +const ( + // SchemeCode of different Methods + GET Method = iota + REGISTER + LOGIN +) + +type Server struct { + config *configs.Configs + logger *logrus.Logger +} + +func New(config *configs.Configs, logger *logrus.Logger) *Server { + return &Server{ + config: config, + logger: logger, + } +} + +// isValidRequest validates the status request +func isValidRequest(m Method, req *authpb.Request) error { + switch m { + case REGISTER, LOGIN: + if req.GetUserId() == "" { + return errors.FormatError(codes.InvalidArgument, &errors.Response{ + Code: "1000", + Msg: "userId is empty", + }) + } + if req.GetPassword() == "" { + return errors.FormatError(codes.InvalidArgument, &errors.Response{ + Code: "1000", + Msg: "password is empty", + }) + } + } + + return nil +} diff --git a/api/v1/auth/login.go b/api/v1/auth/login.go new file mode 100644 index 0000000..48db32b --- /dev/null +++ b/api/v1/auth/login.go @@ -0,0 +1,45 @@ +package auth + +import ( + "context" + + "github.com/ajikamaludin/go-grpc_basic/pkg/v1/jwt" + "github.com/ajikamaludin/go-grpc_basic/pkg/v1/utils/constants" + "github.com/ajikamaludin/go-grpc_basic/pkg/v1/utils/errors" + authpb "github.com/ajikamaludin/go-grpc_basic/proto/v1/auth" + "google.golang.org/grpc/codes" +) + +func (s *Server) Login(ctx context.Context, req *authpb.Request) (*authpb.Response, error) { + err := isValidRequest(LOGIN, req) + if err != nil { + s.logger.Errorf("[AUTH][LOGIN] ERROR %v", err) + return nil, err + } + + // TODO: database logic to match user + + auth, err := jwt.GenerateToken(s.config.Config, req.GetUserId()) + if err != nil { + s.logger.Errorf("[AUTH][LOGIN] ERROR %v", err) + return nil, errors.FormatError(codes.Internal, &errors.Response{ + Code: "1001", + Msg: err.Error(), + }) + } + + s.logger.Infof("[AUTH][LOGIN] SUCCESS") + + return &authpb.Response{ + Success: true, + Code: constants.SuccessCode, + Desc: constants.SuccesDesc, + Auth: &authpb.Auth{ + Type: auth.Type, + Access: auth.Access, + ExpiredPeriode: int32(auth.ExpiredPeriode), + Refresh: auth.Refresh, + }, + }, nil + +} diff --git a/api/v1/auth/register.go b/api/v1/auth/register.go new file mode 100644 index 0000000..effc2dd --- /dev/null +++ b/api/v1/auth/register.go @@ -0,0 +1,19 @@ +package auth + +import ( + "context" + + "github.com/ajikamaludin/go-grpc_basic/pkg/v1/utils/constants" + authpb "github.com/ajikamaludin/go-grpc_basic/proto/v1/auth" +) + +func (s *Server) Register(ctx context.Context, req *authpb.Request) (*authpb.Response, error) { + s.logger.Infof("[AUTH][REGISTER] SUCCESS") + + return &authpb.Response{ + Success: true, + Code: constants.SuccessCode, + Desc: constants.SuccesDesc, + }, nil + +} diff --git a/config.yaml b/config.yaml index 51de289..20f0eec 100644 --- a/config.yaml +++ b/config.yaml @@ -13,3 +13,7 @@ postgres: password: eta cert: path: certfile.pem +jwt: + issuer: ajikamaludin + key: P@ssw0rd + type: Bearer diff --git a/configs/configs.go b/configs/configs.go index 1ddaa3c..fec7b8b 100644 --- a/configs/configs.go +++ b/configs/configs.go @@ -15,7 +15,7 @@ type Configs struct { } func New() (*Configs, *logrus.Logger, error) { - config, err := config.New() + config, err := config.GetInstance() if err != nil { return nil, nil, err diff --git a/go.mod b/go.mod index 4d9e213..67c2c6d 100644 --- a/go.mod +++ b/go.mod @@ -30,8 +30,10 @@ require ( ) require ( + github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/golang/protobuf v1.5.2 github.com/gorilla/handlers v1.5.1 + github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb // indirect golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 // indirect diff --git a/go.sum b/go.sum index e688c1d..8716ad3 100644 --- a/go.sum +++ b/go.sum @@ -14,6 +14,8 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -25,6 +27,10 @@ github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239/go.mod h1:Gdwt2ce0 github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -52,12 +58,18 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag= github.com/jonboulle/clockwork v0.3.0 h1:9BSCMi8C+0qdApAp4auwX0RkLGUjs956h0EkuQymUhg= github.com/jonboulle/clockwork v0.3.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 h1:0iQektZGS248WXmGIYOwRXSQhD4qn3icjMpuxwO7qlo= github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570/go.mod h1:BLt8L9ld7wVsvEWQbuLrUZnCMnUmLZ+CGDzKtclrTlE= github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f h1:sgUSP4zdTUZYZgAGGtN5Lxk92rK+JUFOwf+FT99EEI4= @@ -66,36 +78,51 @@ github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 h1:Bvq8AziQ5j github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042/go.mod h1:TPpsiPUEh0zFL1Snz4crhMlBe60PYxRHr5oFF3rRYg0= github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tebeka/strftime v0.1.5 h1:1NQKN1NiQgkqd/2moD6ySP/5CoZQsKa1d3ZhJ44Jpmg= github.com/tebeka/strftime v0.1.5/go.mod h1:29/OidkoWHdEKZqzyDLUyC+LmgDgdHo4WAFCDT7D/Ig= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U= @@ -106,11 +133,14 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -124,6 +154,11 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -131,6 +166,7 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= @@ -138,6 +174,7 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w= diff --git a/logs/error.log b/logs/error.log index f81153c..5078647 120000 --- a/logs/error.log +++ b/logs/error.log @@ -1 +1 @@ -logs/error_2022-07-15-16:00:00.log \ No newline at end of file +logs/error_2022-07-18-20:00:00.log \ No newline at end of file diff --git a/logs/rest.log b/logs/rest.log index 3e825cd..4051360 120000 --- a/logs/rest.log +++ b/logs/rest.log @@ -1 +1 @@ -logs/hif_2022-07-15-17:00:00.log \ No newline at end of file +logs/rest_2022-07-18-21:00:00.log \ No newline at end of file diff --git a/pkg/v1/config/config.go b/pkg/v1/config/config.go index 16c3bab..3a67ddb 100644 --- a/pkg/v1/config/config.go +++ b/pkg/v1/config/config.go @@ -6,6 +6,7 @@ import ( "fmt" "log" "os" + "sync" "gopkg.in/yaml.v2" ) @@ -31,15 +32,36 @@ type Config struct { Cert struct { Path string `yaml:"path"` } `yaml:"cert"` + Jwt struct { + Issuer string `yaml:"issuer"` + Key string `yaml:"key"` + Type string `yaml:"type"` + } `yaml:"jwt"` } -func New() (*Config, error) { +var lock = &sync.Mutex{} +var config *Config + +func GetInstance() (*Config, error) { + if config == nil { + lock.Lock() + defer lock.Unlock() + config, err := new() + if err != nil { + return nil, err + } + return config, nil + } + return config, nil +} + +func new() (*Config, error) { cfgPath, err := parseFlag() if err != nil { log.Fatal(err) } - config := &Config{} + config = &Config{} file, err := os.Open(cfgPath) if err != nil { @@ -128,6 +150,15 @@ func validateConfigData(config *Config) error { if config.Cert.Path == "" { return errors.New("cert.path is empty") } + if config.Jwt.Issuer == "" { + return errors.New("jwt.issuer is empty") + } + if config.Jwt.Key == "" { + return errors.New("jwt.key is empty") + } + if config.Jwt.Type == "" { + return errors.New("jwt.type is empty") + } return nil } diff --git a/pkg/v1/jwt/jwt.go b/pkg/v1/jwt/jwt.go new file mode 100644 index 0000000..0d8e280 --- /dev/null +++ b/pkg/v1/jwt/jwt.go @@ -0,0 +1,130 @@ +package jwt + +import ( + "strings" + "time" + + "github.com/ajikamaludin/go-grpc_basic/pkg/v1/utils/errors" + + "github.com/ajikamaludin/go-grpc_basic/pkg/v1/config" + "github.com/ajikamaludin/go-grpc_basic/pkg/v1/utils/constants" + "github.com/dgrijalva/jwt-go" +) + +type CustomClaims struct { + User string `json:"user,omitempty"` + IsRefresh bool `json:"isRefresh,omitempty"` + jwt.StandardClaims +} + +type Token struct { + Type string + Access string + ExpiredPeriode int64 + Refresh string +} + +func GenerateToken(config *config.Config, user string) (*Token, error) { + atoken, err := set(user, false, constants.Jwt_Token_Expired_Periode, config) + if err != nil { + return nil, err + } + + arefresh, err := set(user, true, constants.Jwt_Refresh_Expired_Periode, config) + if err != nil { + return nil, err + } + + return &Token{ + Type: config.Jwt.Type, + Access: atoken, + ExpiredPeriode: constants.Jwt_Token_Expired_Periode, + Refresh: arefresh, + }, nil +} + +func set(user string, isrefresh bool, exp time.Duration, config *config.Config) (string, error) { + // create refresh token + claims := CustomClaims{ + User: user, + IsRefresh: isrefresh, + StandardClaims: jwt.StandardClaims{ + ExpiresAt: time.Now().Add(exp * time.Second).Unix(), + Issuer: config.Jwt.Issuer, + }, + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + atoken, err := token.SignedString([]byte(config.Jwt.Key)) + if err != nil { + return "", err + } + + return atoken, nil +} + +func ClaimToken(config *config.Config, auth string, isrefresh bool) (jwt.MapClaims, error) { + var token *jwt.Token + var err error + + if !isrefresh { + // Bearer token as RFC 6750 standard + if strings.Split(auth, " ")[0] != config.Jwt.Type { + return nil, errors.New("Invalid token") + } + + token, err = claim(auth, config.Jwt.Key, false) + if err != nil { + return nil, err + } + } else { + token, err = claim(auth, config.Jwt.Key, true) + if err != nil { + return nil, err + } + } + + claims, ok := token.Claims.(jwt.MapClaims) + if !ok || !token.Valid { + return nil, errors.New("failed to claim token") + } + + // validate issuer + if claims["iss"] != config.Jwt.Issuer { + return nil, errors.New("Invalid token") + } + + // validate refresh token + if isrefresh { + if claims["IsRefresh"] == false { + return nil, errors.New("Invalid token") + } + } else { + if claims["IsRefresh"] == true { + return nil, errors.New("Invalid token") + } + } + + return claims, nil +} + +func claim(auth, key string, isrefresh bool) (*jwt.Token, error) { + if !isrefresh { + auth = strings.Split(auth, " ")[1] + } + + token, err := jwt.Parse(auth, func(token *jwt.Token) (interface{}, error) { + if method, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + errors.New("Signing method invalid") + } else if method != jwt.SigningMethodHS256 { + errors.New("Signing method invalid") + } + + return []byte(key), nil + }) + if err != nil { + return nil, err + } + + return token, nil +} diff --git a/pkg/v1/utils/constants/constants.go b/pkg/v1/utils/constants/constants.go index 0c18899..19b2dde 100644 --- a/pkg/v1/utils/constants/constants.go +++ b/pkg/v1/utils/constants/constants.go @@ -30,3 +30,13 @@ const ( URLEncodedType = "application/x-www-form-urlencoded" STREAMType = "application/octet-stream" ) + +const ( + Jwt_Refresh_Expired_Periode = 3600 + Jwt_Token_Expired_Periode = 3600 +) + +const ( + Endpoint_Auth_Register = `/api.gogrpc.v1.auth.AuthService/Register` + Endpoint_Auth_Login = `/api.gogrpc.v1.auth.AuthService/Login` +) diff --git a/proto/compile-proto.sh b/proto/compile-proto.sh index a774603..d87baad 100755 --- a/proto/compile-proto.sh +++ b/proto/compile-proto.sh @@ -1,7 +1,11 @@ #!/bin/bash WORKDIR=github.com/ajikamaludin/go-grpc_basic -protoc \ +set -ve + +for x in $(ls v1) +do + protoc \ -I. \ -I/usr/local/include \ -I${GOPATH}/src \ @@ -9,4 +13,6 @@ protoc \ -I${GOPATH}/src/$WORKDIR/proto/lib \ --go_out=plugins=grpc:$GOPATH/src \ --grpc-gateway_out=logtostderr=true:$GOPATH/src \ - v1/*/*.proto \ No newline at end of file + v1/$x/$x.proto +done + diff --git a/proto/v1/auth/auth.pb.go b/proto/v1/auth/auth.pb.go new file mode 100644 index 0000000..f3636d2 --- /dev/null +++ b/proto/v1/auth/auth.pb.go @@ -0,0 +1,480 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.21.2 +// source: v1/auth/auth.proto + +package auth + +import ( + context "context" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Request struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId string `protobuf:"bytes,1,opt,name=userId,proto3" json:"userId,omitempty"` + Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` +} + +func (x *Request) Reset() { + *x = Request{} + if protoimpl.UnsafeEnabled { + mi := &file_v1_auth_auth_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Request) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Request) ProtoMessage() {} + +func (x *Request) ProtoReflect() protoreflect.Message { + mi := &file_v1_auth_auth_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Request.ProtoReflect.Descriptor instead. +func (*Request) Descriptor() ([]byte, []int) { + return file_v1_auth_auth_proto_rawDescGZIP(), []int{0} +} + +func (x *Request) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *Request) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +type Auth struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` + Access string `protobuf:"bytes,2,opt,name=access,proto3" json:"access,omitempty"` + ExpiredPeriode int32 `protobuf:"varint,3,opt,name=expiredPeriode,proto3" json:"expiredPeriode,omitempty"` + Refresh string `protobuf:"bytes,4,opt,name=refresh,proto3" json:"refresh,omitempty"` +} + +func (x *Auth) Reset() { + *x = Auth{} + if protoimpl.UnsafeEnabled { + mi := &file_v1_auth_auth_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Auth) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Auth) ProtoMessage() {} + +func (x *Auth) ProtoReflect() protoreflect.Message { + mi := &file_v1_auth_auth_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Auth.ProtoReflect.Descriptor instead. +func (*Auth) Descriptor() ([]byte, []int) { + return file_v1_auth_auth_proto_rawDescGZIP(), []int{1} +} + +func (x *Auth) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *Auth) GetAccess() string { + if x != nil { + return x.Access + } + return "" +} + +func (x *Auth) GetExpiredPeriode() int32 { + if x != nil { + return x.ExpiredPeriode + } + return 0 +} + +func (x *Auth) GetRefresh() string { + if x != nil { + return x.Refresh + } + return "" +} + +type Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` + Code string `protobuf:"bytes,2,opt,name=code,proto3" json:"code,omitempty"` + Desc string `protobuf:"bytes,3,opt,name=desc,proto3" json:"desc,omitempty"` + Auth *Auth `protobuf:"bytes,4,opt,name=auth,proto3" json:"auth,omitempty"` +} + +func (x *Response) Reset() { + *x = Response{} + if protoimpl.UnsafeEnabled { + mi := &file_v1_auth_auth_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Response) ProtoMessage() {} + +func (x *Response) ProtoReflect() protoreflect.Message { + mi := &file_v1_auth_auth_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Response.ProtoReflect.Descriptor instead. +func (*Response) Descriptor() ([]byte, []int) { + return file_v1_auth_auth_proto_rawDescGZIP(), []int{2} +} + +func (x *Response) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +func (x *Response) GetCode() string { + if x != nil { + return x.Code + } + return "" +} + +func (x *Response) GetDesc() string { + if x != nil { + return x.Desc + } + return "" +} + +func (x *Response) GetAuth() *Auth { + if x != nil { + return x.Auth + } + return nil +} + +var File_v1_auth_auth_proto protoreflect.FileDescriptor + +var file_v1_auth_auth_proto_rawDesc = []byte{ + 0x0a, 0x12, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x61, 0x70, 0x69, 0x2e, 0x67, 0x6f, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x76, 0x31, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x3d, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, + 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, + 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x74, 0x0a, 0x04, 0x41, 0x75, 0x74, 0x68, 0x12, 0x12, 0x0a, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x65, 0x78, 0x70, + 0x69, 0x72, 0x65, 0x64, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x0e, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, + 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x22, 0x7a, 0x0a, 0x08, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x63, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x73, 0x63, 0x12, 0x2c, 0x0a, 0x04, 0x61, 0x75, 0x74, + 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x67, 0x6f, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x41, 0x75, 0x74, + 0x68, 0x52, 0x04, 0x61, 0x75, 0x74, 0x68, 0x32, 0xd9, 0x01, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x61, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, + 0x12, 0x1b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x67, 0x6f, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, + 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x67, 0x6f, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x61, 0x75, + 0x74, 0x68, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x17, 0x22, 0x12, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, + 0x68, 0x2f, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x3a, 0x01, 0x2a, 0x12, 0x67, 0x0a, 0x08, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x1b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x67, 0x6f, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x76, 0x31, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x67, 0x6f, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x76, 0x31, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x22, 0x15, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x3a, 0x01, 0x2a, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x61, 0x6a, 0x69, 0x6b, 0x61, 0x6d, 0x61, 0x6c, 0x75, 0x64, 0x69, 0x6e, 0x2f, 0x67, + 0x6f, 0x2d, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x62, 0x61, 0x73, 0x69, 0x63, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, +} + +var ( + file_v1_auth_auth_proto_rawDescOnce sync.Once + file_v1_auth_auth_proto_rawDescData = file_v1_auth_auth_proto_rawDesc +) + +func file_v1_auth_auth_proto_rawDescGZIP() []byte { + file_v1_auth_auth_proto_rawDescOnce.Do(func() { + file_v1_auth_auth_proto_rawDescData = protoimpl.X.CompressGZIP(file_v1_auth_auth_proto_rawDescData) + }) + return file_v1_auth_auth_proto_rawDescData +} + +var file_v1_auth_auth_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_v1_auth_auth_proto_goTypes = []interface{}{ + (*Request)(nil), // 0: api.gogrpc.v1.auth.Request + (*Auth)(nil), // 1: api.gogrpc.v1.auth.Auth + (*Response)(nil), // 2: api.gogrpc.v1.auth.Response +} +var file_v1_auth_auth_proto_depIdxs = []int32{ + 1, // 0: api.gogrpc.v1.auth.Response.auth:type_name -> api.gogrpc.v1.auth.Auth + 0, // 1: api.gogrpc.v1.auth.AuthService.Login:input_type -> api.gogrpc.v1.auth.Request + 0, // 2: api.gogrpc.v1.auth.AuthService.Register:input_type -> api.gogrpc.v1.auth.Request + 2, // 3: api.gogrpc.v1.auth.AuthService.Login:output_type -> api.gogrpc.v1.auth.Response + 2, // 4: api.gogrpc.v1.auth.AuthService.Register:output_type -> api.gogrpc.v1.auth.Response + 3, // [3:5] is the sub-list for method output_type + 1, // [1:3] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_v1_auth_auth_proto_init() } +func file_v1_auth_auth_proto_init() { + if File_v1_auth_auth_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_v1_auth_auth_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_v1_auth_auth_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Auth); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_v1_auth_auth_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_v1_auth_auth_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_v1_auth_auth_proto_goTypes, + DependencyIndexes: file_v1_auth_auth_proto_depIdxs, + MessageInfos: file_v1_auth_auth_proto_msgTypes, + }.Build() + File_v1_auth_auth_proto = out.File + file_v1_auth_auth_proto_rawDesc = nil + file_v1_auth_auth_proto_goTypes = nil + file_v1_auth_auth_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// AuthServiceClient is the client API for AuthService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type AuthServiceClient interface { + Login(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) + Register(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) +} + +type authServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewAuthServiceClient(cc grpc.ClientConnInterface) AuthServiceClient { + return &authServiceClient{cc} +} + +func (c *authServiceClient) Login(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { + out := new(Response) + err := c.cc.Invoke(ctx, "/api.gogrpc.v1.auth.AuthService/Login", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) Register(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { + out := new(Response) + err := c.cc.Invoke(ctx, "/api.gogrpc.v1.auth.AuthService/Register", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// AuthServiceServer is the server API for AuthService service. +type AuthServiceServer interface { + Login(context.Context, *Request) (*Response, error) + Register(context.Context, *Request) (*Response, error) +} + +// UnimplementedAuthServiceServer can be embedded to have forward compatible implementations. +type UnimplementedAuthServiceServer struct { +} + +func (*UnimplementedAuthServiceServer) Login(context.Context, *Request) (*Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method Login not implemented") +} +func (*UnimplementedAuthServiceServer) Register(context.Context, *Request) (*Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method Register not implemented") +} + +func RegisterAuthServiceServer(s *grpc.Server, srv AuthServiceServer) { + s.RegisterService(&_AuthService_serviceDesc, srv) +} + +func _AuthService_Login_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).Login(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/api.gogrpc.v1.auth.AuthService/Login", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).Login(ctx, req.(*Request)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_Register_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).Register(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/api.gogrpc.v1.auth.AuthService/Register", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).Register(ctx, req.(*Request)) + } + return interceptor(ctx, in, info, handler) +} + +var _AuthService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "api.gogrpc.v1.auth.AuthService", + HandlerType: (*AuthServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Login", + Handler: _AuthService_Login_Handler, + }, + { + MethodName: "Register", + Handler: _AuthService_Register_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "v1/auth/auth.proto", +} diff --git a/proto/v1/auth/auth.pb.gw.go b/proto/v1/auth/auth.pb.gw.go new file mode 100644 index 0000000..0219703 --- /dev/null +++ b/proto/v1/auth/auth.pb.gw.go @@ -0,0 +1,250 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: v1/auth/auth.proto + +/* +Package auth is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package auth + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +func request_AuthService_Login_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq Request + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Login(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_AuthService_Login_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq Request + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Login(ctx, &protoReq) + return msg, metadata, err + +} + +func request_AuthService_Register_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq Request + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Register(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_AuthService_Register_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq Request + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Register(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterAuthServiceHandlerServer registers the http handlers for service AuthService to "mux". +// UnaryRPC :call AuthServiceServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterAuthServiceHandlerFromEndpoint instead. +func RegisterAuthServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server AuthServiceServer) error { + + mux.Handle("POST", pattern_AuthService_Login_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AuthService_Login_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_Login_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_AuthService_Register_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AuthService_Register_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_Register_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterAuthServiceHandlerFromEndpoint is same as RegisterAuthServiceHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterAuthServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterAuthServiceHandler(ctx, mux, conn) +} + +// RegisterAuthServiceHandler registers the http handlers for service AuthService to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterAuthServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterAuthServiceHandlerClient(ctx, mux, NewAuthServiceClient(conn)) +} + +// RegisterAuthServiceHandlerClient registers the http handlers for service AuthService +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "AuthServiceClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "AuthServiceClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "AuthServiceClient" to call the correct interceptors. +func RegisterAuthServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client AuthServiceClient) error { + + mux.Handle("POST", pattern_AuthService_Login_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AuthService_Login_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_Login_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_AuthService_Register_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AuthService_Register_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_Register_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_AuthService_Login_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "auth", "login"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_AuthService_Register_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "auth", "register"}, "", runtime.AssumeColonVerbOpt(true))) +) + +var ( + forward_AuthService_Login_0 = runtime.ForwardResponseMessage + + forward_AuthService_Register_0 = runtime.ForwardResponseMessage +) diff --git a/proto/v1/auth/auth.proto b/proto/v1/auth/auth.proto new file mode 100644 index 0000000..60743e8 --- /dev/null +++ b/proto/v1/auth/auth.proto @@ -0,0 +1,42 @@ +syntax = "proto3"; + +package api.gogrpc.v1.auth; + +option go_package = "github.com/ajikamaludin/go-grpc_basic/proto/v1/auth"; + +import "google/api/annotations.proto"; + +message Request { + string userId = 1; + string password = 2; +} + +message Auth { + string type = 1; + string access = 2; + int32 expiredPeriode = 3; + string refresh = 4; +} + +message Response { + bool success = 1; + string code = 2; + string desc = 3; + Auth auth = 4; +} + +service AuthService { + rpc Login(Request) returns (Response) { + option (google.api.http) = { + post: "/api/v1/auth/login", + body:"*" + }; + } + + rpc Register(Request) returns (Response) { + option (google.api.http) = { + post: "/api/v1/auth/register", + body:"*" + }; + } +} \ No newline at end of file diff --git a/router/grpc.go b/router/grpc.go index 4b31e9b..0a63064 100644 --- a/router/grpc.go +++ b/router/grpc.go @@ -1,15 +1,28 @@ package router import ( + "context" "fmt" "log" "net" + "strconv" + "github.com/ajikamaludin/go-grpc_basic/api/v1/auth" "github.com/ajikamaludin/go-grpc_basic/api/v1/health" "github.com/ajikamaludin/go-grpc_basic/configs" + "github.com/ajikamaludin/go-grpc_basic/pkg/v1/config" + "github.com/ajikamaludin/go-grpc_basic/pkg/v1/jwt" + "github.com/ajikamaludin/go-grpc_basic/pkg/v1/utils/constants" + "github.com/ajikamaludin/go-grpc_basic/pkg/v1/utils/errors" + "github.com/ajikamaludin/go-grpc_basic/pkg/v1/utils/logger" + authpb "github.com/ajikamaludin/go-grpc_basic/proto/v1/auth" hlpb "github.com/ajikamaludin/go-grpc_basic/proto/v1/health" + grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" + "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/sirupsen/logrus" "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" "google.golang.org/grpc/reflection" ) @@ -20,9 +33,18 @@ func NewGRPCServer(configs *configs.Configs, logger *logrus.Logger) error { } // register grpc service server - grpcServer := grpc.NewServer() + // grpcServer := grpc.NewServer() + + grpcServer := grpc.NewServer( + grpc.UnaryInterceptor( + grpc_middleware.ChainUnaryServer( + authInterceptor, + ), + ), + ) hlpb.RegisterHealthServiceServer(grpcServer, health.New(configs, logger)) + authpb.RegisterAuthServiceServer(grpcServer, auth.New(configs, logger)) // add reflection service reflection.Register(grpcServer) @@ -34,3 +56,52 @@ func NewGRPCServer(configs *configs.Configs, logger *logrus.Logger) error { return nil } + +func authInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + fmt.Println(info) + if !(info.FullMethod == constants.Endpoint_Auth_Login || + info.FullMethod == constants.Endpoint_Auth_Register) { + // var userId string + + // // create config and logger + // config, err := config.New() + // if err != nil { + // return nil, err + // } + + // read header from incoming request + headers, ok := metadata.FromIncomingContext(ctx) + if !ok { + return nil, errors.New("error get context") + } + + if len(headers.Get("Authorization")) < 1 || headers.Get("Authorization")[0] == "" { + return nil, errors.FormatError(codes.InvalidArgument, &errors.Response{ + Code: "1000", + Msg: "header Authorization is empty", + }) + } + + config, err := config.GetInstance() + if err != nil { + return nil, err + } + + //Verifying token + _, err = jwt.ClaimToken(config, headers.Get("Authorization")[0], false) + if err != nil { + return nil, errors.FormatError(codes.Unauthenticated, &errors.Response{ + Code: strconv.Itoa(runtime.HTTPStatusFromCode(codes.Unauthenticated)), + Msg: err.Error(), + }) + } + } + + // store request log + err := logger.StoreRestRequest(ctx, req, info, "") + if err != nil { + return nil, err + } + + return handler(ctx, req) +} diff --git a/router/http.go b/router/http.go index d8d8383..3d01b0f 100644 --- a/router/http.go +++ b/router/http.go @@ -17,6 +17,7 @@ import ( "github.com/golang/protobuf/proto" + authpb "github.com/ajikamaludin/go-grpc_basic/proto/v1/auth" hlpb "github.com/ajikamaludin/go-grpc_basic/proto/v1/health" ) @@ -42,6 +43,7 @@ func NewHTTPServer(configs *configs.Configs, loggger *logrus.Logger) error { for _, f := range []func(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error{ // register grpc service handler hlpb.RegisterHealthServiceHandler, + authpb.RegisterAuthServiceHandler, } { if err = f(ctx, rmux, conn); err != nil { return err