add jwt authentication, and fix cours for next js

main
Tulyaganov Shuhrat 2023-05-02 11:02:06 +03:00
parent 3026f89f2e
commit 05b8d55d0e
17 changed files with 471 additions and 64 deletions

View File

@ -7,4 +7,4 @@ log_level: "debug"
# db # db
DB: DB:
baseurlbd: "host=localhost:7000 user=films password=5429593sS dbname=postgres sslmode=disable" baseurlbd: ""

3
go.mod
View File

@ -5,7 +5,9 @@ go 1.19
require github.com/sirupsen/logrus v1.9.0 require github.com/sirupsen/logrus v1.9.0
require ( require (
github.com/felixge/httpsnoop v1.0.1 // indirect
github.com/golang-jwt/jwt/v5 v5.0.0-rc.2 // indirect github.com/golang-jwt/jwt/v5 v5.0.0-rc.2 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.14.0 // indirect github.com/jackc/pgconn v1.14.0 // indirect
github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgio v1.0.0 // indirect
@ -15,6 +17,7 @@ require (
github.com/jackc/pgtype v1.14.0 // indirect github.com/jackc/pgtype v1.14.0 // indirect
github.com/jackc/puddle v1.3.0 // indirect github.com/jackc/puddle v1.3.0 // indirect
github.com/jackc/puddle/v2 v2.2.0 // indirect github.com/jackc/puddle/v2 v2.2.0 // indirect
github.com/rs/cors v1.9.0 // indirect
golang.org/x/sync v0.1.0 // indirect golang.org/x/sync v0.1.0 // indirect
) )

6
go.sum
View File

@ -7,6 +7,8 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
@ -14,6 +16,8 @@ github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx
github.com/golang-jwt/jwt/v5 v5.0.0-rc.2 h1:hXPcSazn8wKOfSb9y2m1bdgUMlDxVDarxh3lJVbC6JE= github.com/golang-jwt/jwt/v5 v5.0.0-rc.2 h1:hXPcSazn8wKOfSb9y2m1bdgUMlDxVDarxh3lJVbC6JE=
github.com/golang-jwt/jwt/v5 v5.0.0-rc.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.0.0-rc.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
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/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
@ -101,6 +105,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE=
github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=

View File

@ -13,6 +13,7 @@ type Bd struct {
filmsrepo *Filmsrepo filmsrepo *Filmsrepo
siriesrepo *Siriesrepo siriesrepo *Siriesrepo
userrepo *Userrepo userrepo *Userrepo
tokenrepo *Tokenrepo
} }
func New(config *ConfigBD) *Bd { func New(config *ConfigBD) *Bd {
@ -68,3 +69,13 @@ func (b *Bd) User() *Userrepo {
} }
return b.userrepo return b.userrepo
} }
func (b *Bd) Token() *Tokenrepo {
if b.tokenrepo != nil {
return b.tokenrepo
}
b.tokenrepo = &Tokenrepo{
db: *b,
}
return b.tokenrepo
}

View File

@ -5,6 +5,14 @@ type User struct {
Login string `json:"login"` Login string `json:"login"`
Email string `json:"email"` Email string `json:"email"`
Password string `json:"password"` Password string `json:"password"`
Avatar_Url string Avatar_Url *string
AccesToken string
PermisionLVL int PermisionLVL int
} }
type UserData struct {
Login string
Email string
PermisionLVL int
AccesToken string
}

View File

@ -0,0 +1,62 @@
package bd
import (
"context"
"fmt"
)
type Tokenrepo struct {
db Bd
}
func (t *Tokenrepo) Create(login string, refreshToken string) error {
sql := fmt.Sprint("INSERT INTO tokens (login, refreshtoken) VALUES($1, $2)")
_, err := t.db.db.Exec(context.Background(), sql, login, refreshToken)
if err != nil {
return err
}
return nil
}
func (t *Tokenrepo) FindByLogin(login string) (*string, error) {
var refreshToken string
sql := fmt.Sprint("Select refreshtoken from tokens WHERE login = $1")
rows, err := t.db.db.Query(context.Background(), sql, login)
if err != nil {
return nil, err
}
for rows.Next() {
err = rows.Scan(&refreshToken)
if err != nil {
return nil, err
}
}
return &refreshToken, nil
}
func (t *Tokenrepo) FindByToken(token string) (*string, error) {
var login string
sql := fmt.Sprint("Select login from tokens WHERE refreshtoken = $1")
rows, err := t.db.db.Query(context.Background(), sql, token)
if err != nil {
return nil, err
}
for rows.Next() {
err = rows.Scan(&login)
if err != nil {
return nil, err
}
}
return &login, nil
}
func (t *Tokenrepo) DeleteByLogin(login string) error {
sql := fmt.Sprint("DELETE FROM tokens WHERE login = $1")
_, err := t.db.db.Exec(context.Background(), sql, login)
if err != nil {
return err
}
return err
}

View File

@ -12,8 +12,8 @@ type Userrepo struct {
} }
func (u *Userrepo) Create(user *model.User) error { func (u *Userrepo) Create(user *model.User) error {
_, err := u.db.db.Exec(context.Background(), sql := fmt.Sprint("INSERT INTO users (login, email, password, permisionlvl) VALUES($1, $2, $3, $4)")
"INSERT INTO users (login, email, password, permisionlvl) VALUES($1, $2, $3, $4)", user.Login, user.Email, user.Password, user.PermisionLVL) _, err := u.db.db.Exec(context.Background(), sql, user.Login, user.Email, user.Password, user.PermisionLVL)
if err != nil { if err != nil {
return err return err
} }
@ -60,6 +60,18 @@ func (u *Userrepo) FindByEmail(email string) (*model.User, error) {
} }
func (u *Userrepo) FindByAll() (*model.User, error) { func (u *Userrepo) FindByLoginPas(login string) (*model.User, error) {
return nil, nil var user model.User
rows, err := u.db.db.Query(context.Background(), "SELECT login, password, permisionlvl, email FROM users WHERE login = $1", login)
if err != nil {
return nil, err
}
for rows.Next() {
err := rows.Scan(&user.Login, &user.Password, &user.PermisionLVL, &user.Email)
if err != nil {
return nil, err
}
}
return &user, nil
} }

View File

@ -13,12 +13,12 @@ import (
func (r *RestServer) configureRouterFilms() { func (r *RestServer) configureRouterFilms() {
r.router.HandleFunc("/api/hello", r.HandleHello()).Methods("GET") r.router.HandleFunc("/api/hello", r.HandleHello()).Methods("GET")
r.router.HandleFunc("/api/films", r.HendleFindAll()).Methods("GET") r.router.HandleFunc("/api/films", r.checkJwtAccess(r.HendleFindAll())).Methods("GET")
r.router.HandleFunc("/api/films/{id:[0-9]+}", r.HendleFindID()).Methods("GET") r.router.HandleFunc("/api/films/{id:[0-9]+}", r.checkJwtAccess(r.HendleFindID())).Methods("GET")
r.router.HandleFunc("/api/films/{name}", r.HeandleFilmsFindName()).Methods("GET") r.router.HandleFunc("/api/films/{name}", r.checkJwtAccess(r.HeandleFilmsFindName())).Methods("GET")
r.router.HandleFunc("/api/films/genres/{name}", r.HeandleFilmsSortGenres()).Methods("GET") r.router.HandleFunc("/api/films/genres/{name}", r.checkJwtAccess(r.HeandleFilmsSortGenres())).Methods("GET")
r.router.HandleFunc("/api/films/page/{page:[0-9]+}", r.HendlePagination()).Methods("GET") r.router.HandleFunc("/api/films/page/{page:[0-9]+}", r.checkJwtAccess(r.HendlePagination())).Methods("GET")
r.router.HandleFunc("/api/films/last/", r.HeadleGetLastItem()).Methods("GET") r.router.HandleFunc("/api/films/last/", r.checkJwtAccess(r.HeadleGetLastItem())).Methods("GET")
} }
func (r *RestServer) HandleHello() http.HandlerFunc { func (r *RestServer) HandleHello() http.HandlerFunc {
@ -64,10 +64,6 @@ func (r *RestServer) HendleFindAll() http.HandlerFunc {
func (r *RestServer) HeandleFilmsFindName() http.HandlerFunc { func (r *RestServer) HeandleFilmsFindName() http.HandlerFunc {
return func(w http.ResponseWriter, res *http.Request) { return func(w http.ResponseWriter, res *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
w.Header().Set("Content-Type", "application/json")
name := mux.Vars(res)["name"] name := mux.Vars(res)["name"]
films, err := r.db.Films().FindByName(name) films, err := r.db.Films().FindByName(name)
if err != nil { if err != nil {
@ -88,9 +84,6 @@ func (r *RestServer) HeandleFilmsFindName() http.HandlerFunc {
func (r *RestServer) HeandleFilmsSortGenres() http.HandlerFunc { func (r *RestServer) HeandleFilmsSortGenres() http.HandlerFunc {
return func(w http.ResponseWriter, res *http.Request) { return func(w http.ResponseWriter, res *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
w.Header().Set("Content-Type", "application/json")
name := mux.Vars(res)["name"] name := mux.Vars(res)["name"]
films, err := r.db.Films().SortByGanres(name) films, err := r.db.Films().SortByGanres(name)
if err != nil { if err != nil {
@ -106,9 +99,6 @@ func (r *RestServer) HeandleFilmsSortGenres() http.HandlerFunc {
func (r *RestServer) HendleFindID() http.HandlerFunc { func (r *RestServer) HendleFindID() http.HandlerFunc {
return func(w http.ResponseWriter, res *http.Request) { return func(w http.ResponseWriter, res *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
w.Header().Set("Content-Type", "application/json")
id := mux.Vars(res)["id"] id := mux.Vars(res)["id"]
fmt.Println(mux.Vars(res)) fmt.Println(mux.Vars(res))
film, err := r.db.Films().FindById(id) film, err := r.db.Films().FindById(id)
@ -126,9 +116,6 @@ func (r *RestServer) HendleFindID() http.HandlerFunc {
func (r *RestServer) HendlePagination() http.HandlerFunc { func (r *RestServer) HendlePagination() http.HandlerFunc {
return func(w http.ResponseWriter, res *http.Request) { return func(w http.ResponseWriter, res *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
w.Header().Set("Content-Type", "application/json")
id := mux.Vars(res)["page"] id := mux.Vars(res)["page"]
films, err := r.db.Films().Pagination(id) films, err := r.db.Films().Pagination(id)
if err != nil { if err != nil {
@ -145,9 +132,6 @@ func (r *RestServer) HendlePagination() http.HandlerFunc {
func (r *RestServer) HeadleGetLastItem() http.HandlerFunc { func (r *RestServer) HeadleGetLastItem() http.HandlerFunc {
return func(w http.ResponseWriter, res *http.Request) { return func(w http.ResponseWriter, res *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
w.Header().Set("Content-Type", "application/json")
films, err := r.db.Films().LastItem() films, err := r.db.Films().LastItem()
if err != nil { if err != nil {
r.logger.Errorln(err) r.logger.Errorln(err)

View File

@ -0,0 +1,38 @@
package restserver
import (
"io"
"net/http"
"os"
"strings"
"git.ukamnya.ru/stulyaganov/RestApiv2/pkg/utils/jwt"
)
func (r *RestServer) checkJwtAccess(next http.HandlerFunc) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, res *http.Request) {
w.Header().Set("Content-Type", "application/json")
str := res.Header.Values("Authorization")
if str == nil {
w.WriteHeader(http.StatusUnauthorized)
io.WriteString(w, `{"data":"Ошибка Авторизации"}`)
return
}
token := strings.Split(str[0], " ")
chek, err := jwt.ValidateToken(token[1], []byte(os.Getenv("JWT_SECRET_KEY_ACCESS")))
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
io.WriteString(w, `{"data":"Ошибка Авторизации"}`)
r.logger.Error(err)
return
}
if chek {
next(w, res)
} else {
w.WriteHeader(http.StatusUnauthorized)
io.WriteString(w, `{"data":"Ошибка Авторизации"}`)
}
})
}

View File

@ -5,6 +5,7 @@ import (
"git.ukamnya.ru/stulyaganov/RestApiv2/internal/bd" "git.ukamnya.ru/stulyaganov/RestApiv2/internal/bd"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/rs/cors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -37,14 +38,19 @@ func (r *RestServer) Start() error {
if err := r.configurebd(); err != nil { if err := r.configurebd(); err != nil {
return err return err
} }
corsHendler := cors.New(cors.Options{
AllowedOrigins: []string{"http://localhost:3000"},
AllowedHeaders: []string{"Content-Type", "Authorization", "Set-Cookie"},
AllowedMethods: []string{http.MethodGet, http.MethodPost, http.MethodOptions, http.MethodDelete, http.MethodPut},
AllowCredentials: true,
}).Handler(r.router)
r.configureRouterFilms() r.configureRouterFilms()
r.configureRouterSiries() r.configureRouterSiries()
r.configureRouterUser() r.configureRouterUser()
r.logger.Info("Starting Server") r.logger.Info("Starting Server")
r.logger.Info("Listen server on ", r.config.BindPort, " Port") r.logger.Info("Listen server on ", r.config.BindPort, " Port")
return http.ListenAndServe(r.config.BindPort, r.router) return http.ListenAndServe(r.config.BindPort, corsHendler)
} }
func (r *RestServer) configureLogger() error { func (r *RestServer) configureLogger() error {

View File

@ -12,20 +12,17 @@ import (
) )
func (r *RestServer) configureRouterSiries() { func (r *RestServer) configureRouterSiries() {
r.router.HandleFunc("/api/siries", r.HendleFindAllSiries()).Methods("GET") r.router.HandleFunc("/api/siries", r.checkJwtAccess(r.HendleFindAllSiries())).Methods("GET")
r.router.HandleFunc("/api/siries/{id:[0-9]+}", r.HendleFindIDSiries()).Methods("GET") r.router.HandleFunc("/api/siries/{id:[0-9]+}", r.checkJwtAccess(r.HendleFindIDSiries())).Methods("GET")
r.router.HandleFunc("/api/siries/{name}", r.HeandleSiriesFindName()).Methods("GET") r.router.HandleFunc("/api/siries/{name}", r.checkJwtAccess(r.HeandleSiriesFindName())).Methods("GET")
r.router.HandleFunc("/api/siries/genres/{name}", r.HeandleSiriesSortGenres()).Methods("GET") r.router.HandleFunc("/api/siries/genres/{name}", r.checkJwtAccess(r.HeandleSiriesSortGenres())).Methods("GET")
r.router.HandleFunc("/api/siries/page/{page:[0-9]+}", r.HendlePaginationSiries()).Methods("GET") r.router.HandleFunc("/api/siries/page/{page:[0-9]+}", r.checkJwtAccess(r.HendlePaginationSiries())).Methods("GET")
r.router.HandleFunc("/api/siries/lastS/", r.HeadleGetLastItemSiries()).Methods("GET") r.router.HandleFunc("/api/siries/lastS/", r.checkJwtAccess(r.HeadleGetLastItemSiries())).Methods("GET")
} }
func (r *RestServer) HandleHelloSiries() http.HandlerFunc { func (r *RestServer) HandleHelloSiries() http.HandlerFunc {
return func(w http.ResponseWriter, res *http.Request) { return func(w http.ResponseWriter, res *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
w.Header().Set("Content-Type", "application/json")
id := res.URL.Query().Get("id") id := res.URL.Query().Get("id")
fmt.Println(id) fmt.Println(id)
cout, err := r.db.Siries().GetCountFilms() cout, err := r.db.Siries().GetCountFilms()
@ -63,9 +60,6 @@ func (r *RestServer) HendleFindAllSiries() http.HandlerFunc {
func (r *RestServer) HeandleSiriesFindName() http.HandlerFunc { func (r *RestServer) HeandleSiriesFindName() http.HandlerFunc {
return func(w http.ResponseWriter, res *http.Request) { return func(w http.ResponseWriter, res *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
w.Header().Set("Content-Type", "application/json")
name := mux.Vars(res)["name"] name := mux.Vars(res)["name"]
siries, err := r.db.Siries().FindByName(name) siries, err := r.db.Siries().FindByName(name)
if err != nil { if err != nil {
@ -86,9 +80,6 @@ func (r *RestServer) HeandleSiriesFindName() http.HandlerFunc {
func (r *RestServer) HeandleSiriesSortGenres() http.HandlerFunc { func (r *RestServer) HeandleSiriesSortGenres() http.HandlerFunc {
return func(w http.ResponseWriter, res *http.Request) { return func(w http.ResponseWriter, res *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
w.Header().Set("Content-Type", "application/json")
name := mux.Vars(res)["name"] name := mux.Vars(res)["name"]
siries, err := r.db.Siries().SortByGanres(name) siries, err := r.db.Siries().SortByGanres(name)
if err != nil { if err != nil {
@ -104,9 +95,6 @@ func (r *RestServer) HeandleSiriesSortGenres() http.HandlerFunc {
func (r *RestServer) HendleFindIDSiries() http.HandlerFunc { func (r *RestServer) HendleFindIDSiries() http.HandlerFunc {
return func(w http.ResponseWriter, res *http.Request) { return func(w http.ResponseWriter, res *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
w.Header().Set("Content-Type", "application/json")
id := mux.Vars(res)["id"] id := mux.Vars(res)["id"]
fmt.Println(mux.Vars(res)) fmt.Println(mux.Vars(res))
siries, err := r.db.Siries().FindById(id) siries, err := r.db.Siries().FindById(id)
@ -123,9 +111,6 @@ func (r *RestServer) HendleFindIDSiries() http.HandlerFunc {
func (r *RestServer) HendlePaginationSiries() http.HandlerFunc { func (r *RestServer) HendlePaginationSiries() http.HandlerFunc {
return func(w http.ResponseWriter, res *http.Request) { return func(w http.ResponseWriter, res *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
w.Header().Set("Content-Type", "application/json")
id := mux.Vars(res)["page"] id := mux.Vars(res)["page"]
siries, err := r.db.Siries().Pagination(id) siries, err := r.db.Siries().Pagination(id)
if err != nil { if err != nil {
@ -142,9 +127,6 @@ func (r *RestServer) HendlePaginationSiries() http.HandlerFunc {
func (r *RestServer) HeadleGetLastItemSiries() http.HandlerFunc { func (r *RestServer) HeadleGetLastItemSiries() http.HandlerFunc {
return func(w http.ResponseWriter, res *http.Request) { return func(w http.ResponseWriter, res *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
w.Header().Set("Content-Type", "application/json")
siries, err := r.db.Siries().LastItem() siries, err := r.db.Siries().LastItem()
if err != nil { if err != nil {
r.logger.Errorln(err) r.logger.Errorln(err)

View File

@ -1,6 +1,7 @@
package restserver package restserver
import ( import (
"encoding/json"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
@ -11,8 +12,9 @@ import (
func (r *RestServer) configureRouterUser() { func (r *RestServer) configureRouterUser() {
r.router.HandleFunc("/api/register", r.chekUserRegistr(r.HandleFuncRegUser())).Methods("POST") r.router.HandleFunc("/api/register", r.chekUserRegistr(r.HandleFuncRegUser())).Methods("POST")
r.router.HandleFunc("/api/login", r.HandleFuncLoginUser()).Methods("POST") r.router.HandleFunc("/api/login", r.chekUserLogin(r.HandleFuncLoginUser())).Methods("POST")
r.router.HandleFunc("/api/logout", r.HandleFuncLogOutUser()).Methods("POST") r.router.HandleFunc("/api/logout", r.chekUserLogout(r.HandleFuncLogOutUser())).Methods("GET")
r.router.HandleFunc("/api/refresh", r.checkUserRefresh(r.HandleFuncRefresh())).Methods("GET")
} }
func (r *RestServer) HandleFuncRegUser() http.HandlerFunc { func (r *RestServer) HandleFuncRegUser() http.HandlerFunc {
@ -29,7 +31,27 @@ func (r *RestServer) HandleFuncRegUser() http.HandlerFunc {
if err != nil { if err != nil {
r.logger.Error(err) r.logger.Error(err)
} else { } else {
io.WriteString(w, `{"data":"Пользователь создан"}`) // Reftoken, err := r.db.Token().FindByLogin(users.Login)
// if err != nil {
// fmt.Println(err)
// }
// if Reftoken != nil {
// users.RefreshToken = *Reftoken
// } else {
// r.db.Token().Create(users.Login, users.RefreshToken)
// }
// data := &model.UserData{
// Email: users.Email,
// PermisionLVL: users.PermisionLVL,
// AccesToken: users.AccesToken,
// RefreshToken: users.RefreshToken,
// }
// err = json.NewEncoder(w).Encode(data)
// if err != nil {
// r.logger.Errorln(err)
// }
io.WriteString(w, `{"data":"Пользователь успешно зарегистрирован"}`)
} }
} }
@ -38,12 +60,40 @@ func (r *RestServer) HandleFuncRegUser() http.HandlerFunc {
func (r *RestServer) HandleFuncLoginUser() http.HandlerFunc { func (r *RestServer) HandleFuncLoginUser() http.HandlerFunc {
return func(w http.ResponseWriter, res *http.Request) { return func(w http.ResponseWriter, res *http.Request) {
fmt.Println("login") users := res.Context().Value(ContextKeyUser).(*model.User)
data := &model.UserData{
Login: users.Login,
Email: users.Email,
PermisionLVL: users.PermisionLVL,
AccesToken: users.AccesToken,
}
err := json.NewEncoder(w).Encode(data)
if err != nil {
r.logger.Errorln(err)
}
} }
} }
func (r *RestServer) HandleFuncLogOutUser() http.HandlerFunc { func (r *RestServer) HandleFuncLogOutUser() http.HandlerFunc {
return func(w http.ResponseWriter, res *http.Request) { return func(w http.ResponseWriter, res *http.Request) {
fmt.Println("login") fmt.Println("Logout")
}
}
func (r *RestServer) HandleFuncRefresh() http.HandlerFunc {
return func(w http.ResponseWriter, res *http.Request) {
users := res.Context().Value(ContextKeyUser).(*model.User)
data := &model.UserData{
Login: users.Login,
Email: users.Email,
PermisionLVL: users.PermisionLVL,
AccesToken: users.AccesToken,
}
err := json.NewEncoder(w).Encode(data)
if err != nil {
r.logger.Errorln(err)
}
} }
} }

View File

@ -6,8 +6,12 @@ import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"os"
"time"
"git.ukamnya.ru/stulyaganov/RestApiv2/internal/bd/model" "git.ukamnya.ru/stulyaganov/RestApiv2/internal/bd/model"
"git.ukamnya.ru/stulyaganov/RestApiv2/pkg/utils/jwt"
"git.ukamnya.ru/stulyaganov/RestApiv2/pkg/utils/password"
"git.ukamnya.ru/stulyaganov/RestApiv2/pkg/utils/validator" "git.ukamnya.ru/stulyaganov/RestApiv2/pkg/utils/validator"
) )
@ -21,6 +25,9 @@ func (r *RestServer) chekUserRegistr(next http.HandlerFunc) http.HandlerFunc {
err := json.NewDecoder(res.Body).Decode(users) err := json.NewDecoder(res.Body).Decode(users)
if err != nil { if err != nil {
r.logger.Error(err) r.logger.Error(err)
w.WriteHeader(http.StatusBadRequest)
io.WriteString(w, `{"data":"Что-то пошло не так"}`)
return
} }
user, err := r.db.User().FindByLogin(users.Login) user, err := r.db.User().FindByLogin(users.Login)
if err != nil { if err != nil {
@ -44,6 +51,133 @@ func (r *RestServer) chekUserRegistr(next http.HandlerFunc) http.HandlerFunc {
io.WriteString(w, fmt.Sprintf(`{"data":"%s"}`, err)) io.WriteString(w, fmt.Sprintf(`{"data":"%s"}`, err))
return return
} }
users.PermisionLVL = defaultPermLvl
// jwtToken, _ := jwt.GenerateTokens(*users)
// cookie := http.Cookie{
// Name: "refreshToken",
// Value: jwtToken.RefreshToken,
// Expires: time.Now().Add(time.Hour * 24 * 360),
// HttpOnly: true,
// }
// http.SetCookie(w, &cookie)
// users.AccesToken = jwtToken.AccesToken
// users.RefreshToken = jwtToken.RefreshToken
next(w, res.WithContext(context.WithValue(res.Context(), ContextKeyUser, users))) next(w, res.WithContext(context.WithValue(res.Context(), ContextKeyUser, users)))
} }
} }
func (r *RestServer) chekUserLogin(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, res *http.Request) {
users := &model.User{}
err := json.NewDecoder(res.Body).Decode(users)
if err != nil {
r.logger.Error(err)
w.WriteHeader(http.StatusUnauthorized)
io.WriteString(w, `{"data":"Что-то пошло не так"}`)
return
}
user, err := r.db.User().FindByLoginPas(users.Login)
if err != nil {
r.logger.Error(err)
w.WriteHeader(http.StatusUnauthorized)
io.WriteString(w, `{"data":"Что-то пошло не так"}`)
return
}
if user.Login == "" {
w.WriteHeader(http.StatusUnauthorized)
io.WriteString(w, `{"data":"Неверный логин или пароль"}`)
return
}
checkPass := password.CheckValid(users.Password, user.Password)
if !checkPass {
w.WriteHeader(http.StatusUnauthorized)
io.WriteString(w, `{"data":"Неверный логин или пароль"}`)
return
}
jwtToken, _ := jwt.GenerateTokens(*user)
Reftoken, err := r.db.Token().FindByLogin(users.Login)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
io.WriteString(w, `{"data":"Что-то пошло не так "}`)
return
}
if *Reftoken != "" {
jwtToken.RefreshToken = *Reftoken
} else {
r.db.Token().Create(users.Login, jwtToken.RefreshToken)
}
cookie := http.Cookie{
Name: "refreshToken",
Value: jwtToken.RefreshToken,
Path: "/",
SameSite: http.SameSiteDefaultMode,
Expires: time.Now().Add(time.Hour * 24 * 360),
HttpOnly: true,
}
http.SetCookie(w, &cookie)
users.AccesToken = jwtToken.AccesToken
users.PermisionLVL = user.PermisionLVL
users.Email = user.Email
next(w, res.WithContext(context.WithValue(res.Context(), ContextKeyUser, users)))
}
}
func (r *RestServer) chekUserLogout(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, res *http.Request) {
checkCookie, err := res.Cookie("refreshToken")
if err != nil {
r.logger.Error(err)
} else {
if checkCookie.Value != "" {
login, _ := r.db.Token().FindByToken(checkCookie.Value)
if *login != "" {
r.db.Token().DeleteByLogin(*login)
}
cookie := http.Cookie{
Name: "refreshToken",
Value: "",
MaxAge: -1,
Path: "/",
HttpOnly: true,
}
http.SetCookie(w, &cookie)
}
}
next(w, res)
}
}
func (r *RestServer) checkUserRefresh(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, res *http.Request) {
users := &model.User{}
checkCookie, err := res.Cookie("refreshToken")
if err != nil {
r.logger.Error(err)
w.WriteHeader(http.StatusUnauthorized)
return
}
chekToken, err := jwt.ValidateToken(checkCookie.Value, []byte(os.Getenv("JWT_SECRET_KEY_REFRESH")))
if err != nil {
r.logger.Error(err)
w.WriteHeader(http.StatusUnauthorized)
return
}
login, err := r.db.Token().FindByToken(checkCookie.Value)
if err != nil {
r.logger.Error(err)
w.WriteHeader(http.StatusUnauthorized)
return
}
if *login != "" && chekToken {
userdb, _ := r.db.User().FindByLoginPas(*login)
jwtToken, _ := jwt.GenerateTokens(*userdb)
users.Login = userdb.Login
users.AccesToken = jwtToken.AccesToken
users.PermisionLVL = userdb.PermisionLVL
users.Email = userdb.Email
next(w, res.WithContext(context.WithValue(res.Context(), ContextKeyUser, users)))
}
}
}

View File

@ -16,11 +16,15 @@ CREATE TABLE films (
iframe_src VARCHAR(2000), iframe_src VARCHAR(2000),
ratingImdbVoteCount INTEGER, ratingImdbVoteCount INTEGER,
ratingKinopoiskVoteCount INTEGER, ratingKinopoiskVoteCount INTEGER,
created VARCHAR(1500), created VARCHAR(1000),
content_type VARCHAR(25),
ratingAgeLimits VARCHAR(25),
media JSON, media JSON,
PRIMARY KEY(id) PRIMARY KEY(id)
); );
CREATE TABLE users ( CREATE TABLE users (
id SERIAL, id SERIAL,
login TEXT not NULL, login TEXT not NULL,
@ -34,8 +38,32 @@ CREATE TABLE users (
PRIMARY KEY(id) PRIMARY KEY(id)
); );
CREATE TABLE Siries (
id INTEGER NOT NULL,
ru_title VARCHAR(256),
orig_title VARCHAR(255),
imdb_id VARCHAR(255),
kinopoisk_id INTEGER,
posterUrl VARCHAR(1500),
posterUrlPreview VARCHAR(1500),
countries JSON,
genres JSON,
year INTEGER,
description VARCHAR(20000),
ratingKinopoisk INTEGER,
ratingImdb INTEGER,
iframe_src VARCHAR(2000),
ratingImdbVoteCount INTEGER,
ratingKinopoiskVoteCount INTEGER,
created VARCHAR(1000),
content_type VARCHAR(25),
ratingAgeLimits VARCHAR(25),
translation JSON,
episodes JSON,
PRIMARY KEY(id)
);
CREATE TABLE tokens ( CREATE TABLE tokens (
userID INTEGER NOT NULL, login TEXT NOT NULL,
refreshToken TEXT NOT NULL refreshToken TEXT NOT NULL,
PRIMARY KEY(login)
); );

View File

@ -0,0 +1,24 @@
package jwt
import (
"fmt"
"github.com/golang-jwt/jwt/v5"
)
func ValidateToken(tokenString string, secretKey []byte) (bool, error) {
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return secretKey, nil
})
if err != nil {
return false, err
}
if _, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
return true, nil
} else {
return false, nil
}
}

View File

@ -0,0 +1,48 @@
package jwt
import (
"os"
"time"
"git.ukamnya.ru/stulyaganov/RestApiv2/internal/bd/model"
"github.com/golang-jwt/jwt/v5"
)
type jwtToken struct {
AccesToken string
RefreshToken string
}
func GenerateTokens(payload model.User) (*jwtToken, error) {
AccessKey := os.Getenv("JWT_SECRET_KEY_ACCESS")
RefreshKey := os.Getenv("JWT_SECRET_KEY_REFRESH")
claimsAccess := jwt.MapClaims{
"name": payload.Login,
"permisionlvl": payload.PermisionLVL,
"email": payload.Email,
"exp": time.Now().Add(time.Hour * 24 * 60).Unix(),
}
claimsRefresh := jwt.MapClaims{
"name": payload.Login,
"permisionlvl": payload.PermisionLVL,
"email": payload.Email,
"exp": time.Now().Add(time.Hour * 24 * 360).Unix(),
}
tokenAcc := jwt.NewWithClaims(jwt.SigningMethodHS256, claimsAccess)
tokenRef := jwt.NewWithClaims(jwt.SigningMethodHS256, claimsRefresh)
AccesToken, err := tokenAcc.SignedString([]byte(AccessKey))
if err != nil {
return nil, err
}
RefreshToken, err := tokenRef.SignedString([]byte(RefreshKey))
if err != nil {
return nil, err
}
return &jwtToken{
AccesToken: AccesToken,
RefreshToken: RefreshToken,
}, nil
}

View File

@ -1,6 +1,8 @@
package password package password
import "golang.org/x/crypto/bcrypt" import (
"golang.org/x/crypto/bcrypt"
)
func HashPassword(password string) (*[]byte, error) { func HashPassword(password string) (*[]byte, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14) bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
@ -9,3 +11,12 @@ func HashPassword(password string) (*[]byte, error) {
} }
return &bytes, err return &bytes, err
} }
func CheckValid(password string, hash string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
if err != nil {
return false
}
return true
}