Hogyan készítsünk webalkalmazást a Go, a Gin és a React alkalmazással

Ezt a cikket eredetileg a Saját blogon tették közzé

TL; DR: Ebben az oktatóanyagban megmutatom, mennyire egyszerű webalkalmazást építeni a Go és a Gin keretrendszerrel, és hozzáadni hitelesítést. Nézze meg a Github repóban a kódot, amelyet írni fogunk.

A Gin egy nagy teljesítményű mikrokeret. Nagyon minimalista keretrendszert nyújt, amely csak a webalkalmazások és a mikroszolgáltatások létrehozásához szükséges legfontosabb funkciókat, könyvtárakat és funkciókat tartalmazza. Ez megkönnyíti a kérelemkezelő csővezeték megépítését moduláris, újrafelhasználható darabokból. Ezt úgy teszi meg, hogy lehetővé teszi olyan köztes szoftverek írását, amelyek csatlakoztathatók egy vagy több kérelemkezelőhöz vagy kéréskezelők csoportjához.

Gin funkciók

A Gin egy gyors, egyszerű, mégis teljes körű szolgáltatásokat kínáló és nagyon hatékony webes keretrendszer a Go számára. Nézze meg az alábbi funkciókat, amelyek méltó keretet jelentenek a következő Golang-projekt szempontjából.

  • Sebesség: A gint a sebesség érdekében építik. A keretrendszer Radix fa alapú útválasztást és kicsi memóriaterületet kínál. Nincs reflexió. Kiszámítható API teljesítmény.
  • Összeomlásmentes : Gin képes lefutni összeomlásokat vagy pánikokat futás közben, és felépülhet ezekből. Így az alkalmazás mindig elérhető lesz.
  • Útválasztás: A Gin egy útválasztási felületet biztosít, amely lehetővé teszi, hogy kifejezze, hogyan kell kinéznie a webalkalmazás vagy az API útvonalainak.
  • JSON érvényesítés: A Gin könnyen elemezheti és érvényesítheti a JSON kéréseket, ellenőrizve a szükséges értékek meglétét.
  • Hibakezelés: A Gin kényelmes módot kínál a HTTP-kérés során fellépő összes hiba összegyűjtésére. Végül egy köztes szoftver beírhatja őket egy naplófájlba vagy egy adatbázisba, és elküldheti a hálózaton keresztül.
  • Beépített megjelenítés: A Gin könnyen használható API-t biztosít a JSON, XML és HTML megjelenítéshez.

Előfeltételek

Az oktatóanyag követéséhez telepítenie kell a Go szoftvert a számítógépére, egy webböngészőt az alkalmazás megtekintéséhez és egy parancssort a build parancsok végrehajtásához.

A Go vagy más néven a Golang egy programozási nyelv, amelyet a Google fejlesztett ki a modern szoftverek építésére. A Go egy olyan nyelv, amelynek célja a dolgok hatékony és gyors elvégzése. A Go legfontosabb előnyei a következők:

  • Erősen gépelt és szemetet gyűjtöttek
  • Lángoló gyors fordítási idők
  • Beépített párhuzamosság
  • Kiterjedt standard könyvtár

Lépjen a Go webhely letöltések szakaszába, hogy elindulhasson a Go számítógépén.

Alkalmazás építése Ginnel

Egy egyszerű vicclistázó alkalmazást építünk Ginnel . Az alkalmazásunk felsorol néhány buta apa viccet. Hozzá fogjuk adni a hitelesítést, hogy minden bejelentkezett felhasználó kiváltságot élvezhessen a poénok kedvelésére és megtekintésére.

Ez lehetővé teszi számunkra, hogy bemutassuk, hogyan használható a Gin webalkalmazások és / vagy API-k fejlesztésére.

A Gin által kínált következő funkciókat fogjuk használni:

  • Középprogram
  • útvonalválasztás
  • Útvonalak csoportosítása

Vigyázz, kész, rajt

A teljes Go alkalmazásunkat main.gofájlba fogjuk írni . Mivel ez egy kicsi alkalmazás, egyszerű lesz az alkalmazás építése go runa terminálról.

Létrehozunk egy új könyvtárat golang-gina Go munkaterületünkön, majd egy main.gofájlt benne:

$ mkdir -p $GOPATH/src/github.com/user/golang-gin $ cd $GOPATH/src/github.com/user/golang-gin $ touch main.go

A main.gofájl tartalma:

package main import ( "net/http" "github.com/gin-gonic/contrib/static" "github.com/gin-gonic/gin" ) func main() { // Set the router as the default one shipped with Gin router := gin.Default() // Serve frontend static files router.Use(static.Serve("/", static.LocalFile("./views", true))) // Setup route group for the API api := router.Group("/api") { api.GET("/", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H { "message": "pong", }) }) } // Start and run the server router.Run(":3000") }

Hozzon létre még néhány könyvtárat a statikus fájljainkhoz. main.goHozzunk létre egy viewsmappát a fájllal azonos könyvtárban . A viewsmappában hozzon létre egy jsmappát, és egy index.htmlfájl sem.

A index.htmlfájl egyelőre nagyon egyszerű lesz:

   Jokeish App   

Welcome to the Jokeish App

Mielőtt tesztelnénk az eddigieket, telepítsük a hozzáadott függőségeket:

$ go get -u github.com/gin-gonic/gin $ go get -u github.com/gin-gonic/contrib/static

Ahhoz, hogy lássuk, mi működik, futtatással kell elindítanunk a szerverünket go run main.go.

Miután az alkalmazás fut, navigáljon //localhost:3000a böngészőben. Ha minden jól megy, akkor az 1. szintű fejléc Üdvözöljük a Jokeish App jelenik meg.

Az API meghatározása

Vegyünk fel még néhány kódot main.goa fájlunkba az API meghatározásainkhoz. Frissítjük mainfunkciónkat két útvonallal /jokes/és /jokes/like/:jokeIDaz útvonalcsoportra /api/.

func main() { // ... leave the code above untouched... // Our API will consit of just two routes // /jokes - which will retrieve a list of jokes a user can see // /jokes/like/:jokeID - which will capture likes sent to a particular joke api.GET("/jokes", JokeHandler) api.POST("/jokes/like/:jokeID", LikeJoke) } // JokeHandler retrieves a list of available jokes func JokeHandler(c *gin.Context) { c.Header("Content-Type", "application/json") c.JSON(http.StatusOK, gin.H { "message":"Jokes handler not implemented yet", }) } // LikeJoke increments the likes of a particular joke Item func LikeJoke(c *gin.Context) { c.Header("Content-Type", "application/json") c.JSON(http.StatusOK, gin.H { "message":"LikeJoke handler not implemented yet", }) }

A main.gofájl tartalmának így kell kinéznie:

package main import ( "net/http" "github.com/gin-gonic/contrib/static" "github.com/gin-gonic/gin" ) func main() { // Set the router as the default one shipped with Gin router := gin.Default() // Serve frontend static files router.Use(static.Serve("/", static.LocalFile("./views", true))) // Setup route group for the API api := router.Group("/api") { api.GET("/", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H { "message": "pong", }) }) } // Our API will consit of just two routes // /jokes - which will retrieve a list of jokes a user can see // /jokes/like/:jokeID - which will capture likes sent to a particular joke api.GET("/jokes", JokeHandler) api.POST("/jokes/like/:jokeID", LikeJoke) // Start and run the server router.Run(":3000") } // JokeHandler retrieves a list of available jokes func JokeHandler(c *gin.Context) { c.Header("Content-Type", "application/json") c.JSON(http.StatusOK, gin.H { "message":"Jokes handler not implemented yet", }) } // LikeJoke increments the likes of a particular joke Item func LikeJoke(c *gin.Context) { c.Header("Content-Type", "application/json") c.JSON(http.StatusOK, gin.H { "message":"LikeJoke handler not implemented yet", }) }

Futtassuk újra az alkalmazást go run main.go, és érjük el az útjainkat. fejléc választ ad //localhost:3000/api/jokesvissza 200 OKaz üzenettel jokes handler not implemented yet. A POST kérés //localhost:3000/api/jokes/like/1a 200 OKfejléc és az üzenet visszaadására szolgál Likejoke handler not implemented yet.

Viccek adatai

Mivel már megvan az útvonalmeghatározásunk, amely csak egy dolgot hajt végre (visszaküldi a JSON-választ), egy kicsit megspékeljük kódbázisunkat azzal, hogy adunk hozzá még néhány kódot.

// ... leave the code above untouched... // Let's create our Jokes struct. This will contain information about a Joke // Joke contains information about a single Joke type Joke struct { ID int `json:"id" binding:"required"` Likes int `json:"likes"` Joke string `json:"joke" binding:"required"` } // We'll create a list of jokes var jokes = []Joke{ Joke{1, 0, "Did you hear about the restaurant on the moon? Great food, no atmosphere."}, Joke{2, 0, "What do you call a fake noodle? An Impasta."}, Joke{3, 0, "How many apples grow on a tree? All of them."}, Joke{4, 0, "Want to hear a joke about paper? Nevermind it's tearable."}, Joke{5, 0, "I just watched a program about beavers. It was the best dam program I've ever seen."}, Joke{6, 0, "Why did the coffee file a police report? It got mugged."}, Joke{7, 0, "How does a penguin build it's house? Igloos it together."}, } func main() { // ... leave this block untouched... } // JokeHandler retrieves a list of available jokes func JokeHandler(c *gin.Context) { c.Header("Content-Type", "application/json") c.JSON(http.StatusOK, jokes) } // LikeJoke increments the likes of a particular joke Item func LikeJoke(c *gin.Context) { // confirm Joke ID sent is valid // remember to import the `strconv` package if jokeid, err := strconv.Atoi(c.Param("jokeID")); err == nil { // find joke, and increment likes for i := 0; i < len(jokes); i++ { if jokes[i].ID == jokeid { jokes[i].Likes += 1 } } // return a pointer to the updated jokes list c.JSON(http.StatusOK, &jokes) } else { // Joke ID is invalid c.AbortWithStatus(http.StatusNotFound) } } // NB: Replace the JokeHandler and LikeJoke functions in the previous version to the ones above

Ha a kódunk jól néz ki, folytassuk és teszteljük az API-t. Tesztelhetünk a cURLvagy gombbal postman, majd küldhetünk egy GETkérést //localhost:3000/jokesa viccek teljes listájának megszerzéséhez, és egy POSTkérést a poénok //localhost:3000/jokes/like/{jokeid}kedveléseinek növelésére.

$ curl //localhost:3000/api/jokes $ curl -X POST //localhost:3000/api/jokes/like/4

A felhasználói felület felépítése (React)

Megvan az API-nk, ezért készítsünk egy kezelőfelületet, amely bemutatja az API-junkból származó adatokat. Ehhez a React-et fogjuk használni. Nem fogunk túl mélyrehatóan belemenni a React-be, mivel az az oktatóanyag körén kívül esik. Ha többet szeretne megtudni a React-ról, nézze meg a hivatalos oktatóanyagot. A kezelőfelületet bármely olyan frontend keretrendszerrel implementálhatja, amelyiknek Önnek megfelelő.

Beállít

Szerkesztjük a index.htmlfájlt, hogy hozzáadjuk a React futtatásához szükséges külső könyvtárakat. Ezután létre kell hoznunk egy app.jsxfájlt a views/jskönyvtárban, amely tartalmazza a React kódunkat.

A index.htmlfájlunknak így kell kinéznie:

     Jokeish App 

Összetevőink építése

A React-ben a nézetek komponensekre vannak bontva. Ki kell építenünk néhány összetevőt:

  • egy Appkomponens, mint fő bejegyzés, amely elindítja az alkalmazást
  • egy olyan Homekomponens, amely nem bejelentkezett felhasználókkal néz szembe
  • olyan LoggedInalkatrész, amelynek tartalmát csak hitelesített felhasználók láthatják
  • és egy Jokekomponens a viccek listájának megjelenítésére.

Mindezeket az összetevőket beírjuk a app.jsxfájlba.

Az alkalmazás összetevője

Ez az összetevő indítja a teljes React alkalmazást. Az alapján dönt, hogy melyik összetevőt jelenítse meg, annak alapján, hogy a felhasználó hitelesített-e vagy sem. Csak az alapját kezdjük, majd később több funkcióval frissítjük.

class App extends React.Component { render() { if (this.loggedIn) { return (); } else { return (); } } }

A Home komponens

Ez az összetevő a nem bejelentkezett felhasználók számára jelenik meg, valamint egy gomb, amely megnyitja a Tárolt zárolási képernyőt, ahol regisztrálhatnak vagy bejelentkezhetnek. Később hozzáadjuk ezt a funkciót.

class Home extends React.Component { render() { return ( 

Jokeish

A load of Dad jokes XD

Sign in to get access

Sign In ) } }

LoggedIn komponens

Ez az összetevő akkor jelenik meg, amikor a felhasználó hitelesítésre kerül. A stateviccek tömbjében tárolja, amelyet az alkatrész felszerelésekor töltenek be.

class LoggedIn extends React.Component { constructor(props) { super(props); this.state = { jokes: [] } } render() { return (

Log out

Jokeish

Let's feed you with some funny Jokes!!!

{this.state.jokes.map(function(joke, i){ return (); })} ) } }

A Joke komponens

Az Jokeösszetevő információkat tartalmaz a megjelenítendő viccek válaszának minden eleméről.

class Joke extends React.Component { constructor(props) { super(props); this.state = { liked: "" } this.like = this.like.bind(this); } like() { // ... we'll add this block later } render() { return ( #{this.props.joke.id} {this.state.liked} {this.props.joke.joke} {this.props.joke.likes} Likes ) } }

Összeírtuk komponenseinket, ezért most mondjuk meg a Reactnek, hol kell megjeleníteni az alkalmazást. Az alábbi kódblokkot hozzáadjuk a app.jsxfájlunk aljához .

ReactDOM.render(, document.getElementById('app'));

Indítsuk újra a Go szervert go run main.go, és térjünk át alkalmazásunk URL-jére //localhost:3000/. Látni fogja, hogy az Homealkatrész megjelenik.

Viccjeink alkalmazásának biztosítása az Auth0 segítségével

Az Auth0 minden bejelentkezéskor kiadja a JSON web tokent a felhasználók számára. Ez azt jelenti, hogy szilárd identitás-infrastruktúrával rendelkezhet, beleértve az egyszeri bejelentkezést, a felhasználói kezelést, a közösségi identitás-szolgáltatók (Facebook, Github, Twitter stb.), A vállalati identitás-szolgáltatók (Active Directory, LDAP, SAML stb.) Támogatását. és saját felhasználói adatbázisa, csak néhány soros kóddal.

Könnyedén beállíthatjuk a hitelesítést a GIN alkalmazásunkban az Auth0 használatával. A rész követéséhez szükséged lesz egy fiókra. Ha még nincs Auth0-fiókja, regisztráljon most.

Jogi nyilatkozat: Ez nem szponzorált tartalom.

Az API kliens létrehozása

Jelzőinket az Auth0 segítségével generáljuk, ezért az Auth0 irányítópultunkról létre kell hoznunk egy API-t és egy klienst. Ismét, ha még nem tette meg, regisztráljon Auth0 fiókot.

Új API létrehozásához lépjen az irányítópult API-k szakaszába, és kattintson az API létrehozása gombra.

Válasszon egy API nevet és egy azonosítót . Az azonosító lesz a köztes szoftver közönsége . Az aláíró algoritmusnak RS256- nak kell lennie .

Új kliens létrehozásához keresse meg az irányítópult kliensek szakaszát, majd kattintson az Ügyfél létrehozása gombra. Válassza ki a típust Regular Web Applications.

Az ügyfél létrehozása után vegye tudomásul a client_idés client_secret, amire később szükségünk lesz.

Hozzá kell adnunk az API-nál szükséges hitelesítő adatokat egy környezeti változóhoz. Hozzon létre egy új fájlt a gyökérkönyvtárban, .envés adja hozzá a következőket az Auth0 irányítópult részleteivel:

export export export AUTH0_DOMAIN="yourdomain.auth0.com" export

API-végpontjaink biztonsága

Jelenleg az API-nk nyitva áll a világ előtt. Biztosítanunk kell a végpontjainkat, így csak az arra jogosult felhasználók férhetnek hozzá.

Egy JWT köztes szoftvert fogunk használni, hogy ellenőrizzük a JSON Web Token érvényes érvényesítését minden egyes kérésből, amely eléri a végpontjainkat.

Készítsük el a köztes szoftvert:

// ... var jwtMiddleWare *jwtmiddleware.JWTMiddleware func main() { jwtMiddleware := jwtmiddleware.New(jwtmiddleware.Options{ ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) { aud := os.Getenv("AUTH0_API_AUDIENCE") checkAudience := token.Claims.(jwt.MapClaims).VerifyAudience(aud, false) if !checkAudience { return token, errors.New("Invalid audience.") } // verify iss claim iss := os.Getenv("AUTH0_DOMAIN") checkIss := token.Claims.(jwt.MapClaims).VerifyIssuer(iss, false) if !checkIss { return token, errors.New("Invalid issuer.") } cert, err := getPemCert(token) if err != nil { log.Fatalf("could not get cert: %+v", err) } result, _ := jwt.ParseRSAPublicKeyFromPEM([]byte(cert)) return result, nil }, SigningMethod: jwt.SigningMethodRS256, }) // register our actual jwtMiddleware jwtMiddleWare = jwtMiddleware // ... the rest of the code below this function doesn't change yet } // authMiddleware intercepts the requests, and check for a valid jwt token func authMiddleware() gin.HandlerFunc { return func(c *gin.Context) { // Get the client secret key err := jwtMiddleWare.CheckJWT(c.Writer, c.Request) if err != nil { // Token not found fmt.Println(err) c.Abort() c.Writer.WriteHeader(http.StatusUnauthorized) c.Writer.Write([]byte("Unauthorized")) return } } }

A fenti kódban van egy új jwtMiddleWareváltozó, amelyet a mainfüggvény inicializál . A authMiddlewareközépső funkcióban használják.

Ha észreveszi, a kiszolgálóoldali hitelesítő adatainkat egy környezeti változóból (egy 12-faktoros alkalmazás egyik tétele közül) vesszük . Középprogramunk ellenőrzi és kap egy tokent egy kérésből, és meghívja a jwtMiddleWare.CheckJWTmódszert az elküldött token érvényesítésére.

Írjuk meg a függvényt is a JSON webkulcsok visszaadásához:

// ... the code above is untouched... // Jwks stores a slice of JSON Web Keys type Jwks struct { Keys []JSONWebKeys `json:"keys"` } type JSONWebKeys struct { Kty string `json:"kty"` Kid string `json:"kid"` Use string `json:"use"` N string `json:"n"` E string `json:"e"` X5c []string `json:"x5c"` } func main() { // ... the code in this method is untouched... } func getPemCert(token *jwt.Token) (string, error) { cert := "" resp, err := http.Get(os.Getenv("AUTH0_DOMAIN") + ".well-known/jwks.json") if err != nil { return cert, err } defer resp.Body.Close() var jwks = Jwks{} err = json.NewDecoder(resp.Body).Decode(&jwks) if err != nil { return cert, err } x5c := jwks.Keys[0].X5c for k, v := range x5c { if token.Header["kid"] == jwks.Keys[k].Kid { cert = "-----BEGIN CERTIFICATE-----\n" + v + "\n-----END CERTIFICATE-----" } } if cert == "" { return cert, errors.New("unable to find appropriate key.") } return cert, nil }

A JWT köztes szoftver használata

A köztes szoftver használata nagyon egyszerű. Csak átadjuk paraméterként az útvonalak meghatározásához.

... api.GET("/jokes", authMiddleware(), JokeHandler) api.POST("/jokes/like/:jokeID", authMiddleware(), LikeJoke) ...

A main.gofájlunknak így kell kinéznie:

package main import ( "encoding/json" "errors" "fmt" "log" "net/http" "os" "strconv" jwtmiddleware "github.com/auth0/go-jwt-middleware" jwt "github.com/dgrijalva/jwt-go" "github.com/gin-gonic/contrib/static" "github.com/gin-gonic/gin" ) type Response struct { Message string `json:"message"` } type Jwks struct { Keys []JSONWebKeys `json:"keys"` } type JSONWebKeys struct { Kty string `json:"kty"` Kid string `json:"kid"` Use string `json:"use"` N string `json:"n"` E string `json:"e"` X5c []string `json:"x5c"` } type Joke struct { ID int `json:"id" binding:"required"` Likes int `json:"likes"` Joke string `json:"joke" binding:"required"` } /** we'll create a list of jokes */ var jokes = []Joke{ Joke{1, 0, "Did you hear about the restaurant on the moon? Great food, no atmosphere."}, Joke{2, 0, "What do you call a fake noodle? An Impasta."}, Joke{3, 0, "How many apples grow on a tree? All of them."}, Joke{4, 0, "Want to hear a joke about paper? Nevermind it's tearable."}, Joke{5, 0, "I just watched a program about beavers. It was the best dam program I've ever seen."}, Joke{6, 0, "Why did the coffee file a police report? It got mugged."}, Joke{7, 0, "How does a penguin build it's house? Igloos it together."}, } var jwtMiddleWare *jwtmiddleware.JWTMiddleware func main() { jwtMiddleware := jwtmiddleware.New(jwtmiddleware.Options{ ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) { aud := os.Getenv("AUTH0_API_AUDIENCE") checkAudience := token.Claims.(jwt.MapClaims).VerifyAudience(aud, false) if !checkAudience { return token, errors.New("Invalid audience.") } // verify iss claim iss := os.Getenv("AUTH0_DOMAIN") checkIss := token.Claims.(jwt.MapClaims).VerifyIssuer(iss, false) if !checkIss { return token, errors.New("Invalid issuer.") } cert, err := getPemCert(token) if err != nil { log.Fatalf("could not get cert: %+v", err) } result, _ := jwt.ParseRSAPublicKeyFromPEM([]byte(cert)) return result, nil }, SigningMethod: jwt.SigningMethodRS256, }) jwtMiddleWare = jwtMiddleware // Set the router as the default one shipped with Gin router := gin.Default() // Serve the frontend router.Use(static.Serve("/", static.LocalFile("./views", true))) api := router.Group("/api") { api.GET("/", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "pong", }) }) api.GET("/jokes", authMiddleware(), JokeHandler) api.POST("/jokes/like/:jokeID", authMiddleware(), LikeJoke) } // Start the app router.Run(":3000") } func getPemCert(token *jwt.Token) (string, error) { cert := "" resp, err := http.Get(os.Getenv("AUTH0_DOMAIN") + ".well-known/jwks.json") if err != nil { return cert, err } defer resp.Body.Close() var jwks = Jwks{} err = json.NewDecoder(resp.Body).Decode(&jwks) if err != nil { return cert, err } x5c := jwks.Keys[0].X5c for k, v := range x5c { if token.Header["kid"] == jwks.Keys[k].Kid { cert = "-----BEGIN CERTIFICATE-----\n" + v + "\n-----END CERTIFICATE-----" } } if cert == "" { return cert, errors.New("unable to find appropriate key") } return cert, nil } // authMiddleware intercepts the requests, and check for a valid jwt token func authMiddleware() gin.HandlerFunc { return func(c *gin.Context) { // Get the client secret key err := jwtMiddleWare.CheckJWT(c.Writer, c.Request) if err != nil { // Token not found fmt.Println(err) c.Abort() c.Writer.WriteHeader(http.StatusUnauthorized) c.Writer.Write([]byte("Unauthorized")) return } } } // JokeHandler returns a list of jokes available (in memory) func JokeHandler(c *gin.Context) { c.Header("Content-Type", "application/json") c.JSON(http.StatusOK, jokes) } func LikeJoke(c *gin.Context) { // Check joke ID is valid if jokeid, err := strconv.Atoi(c.Param("jokeID")); err == nil { // find joke and increment likes for i := 0; i < len(jokes); i++ { if jokes[i].ID == jokeid { jokes[i].Likes = jokes[i].Likes + 1 } } c.JSON(http.StatusOK, &jokes) } else { // the jokes ID is invalid c.AbortWithStatus(http.StatusNotFound) } }

Telepítsük a jwtmiddlewarekönyvtárakat:

$ go get -u github.com/auth0/go-jwt-middleware $ go get -u github.com/dgrijalva/jwt-go

Forrjuk meg a környezeti fájlt, és indítsuk újra az alkalmazásszerverünket:

$ source .env $ go run main.go

Ha megpróbálunk elérni bármelyik végpontot, akkor 401 Unauthorizedhibával szembesülünk . Ez azért van, mert a tokennel együtt el kell küldenünk egy kérelmet.

Bejelentkezés az Auth0 és a React

Vezessünk be egy bejelentkezési rendszert, hogy a felhasználók bejelentkezhessenek vagy fiókokat hozzanak létre, és hozzáférhessenek vicceinkhez. app.jsxFájlunkhoz hozzáadjuk a következő Auth0 hitelesítő adatokat:

  • AUTH0_CLIENT_ID
  • AUTH0_DOMAIN
  • AUTH0_CALLBACK_URL - Az alkalmazásod URL-je
  • AUTH0_API_AUDIENCE
Megtalálható az AUTH0_CLIENT_ID, AUTH0_DOMAINés AUTH0_API_AUDIENCEaz adatokat a Auth0 menedzsment műszerfalon.

Be kell állítanunk egy, callbackamelyre az Auth0 átirányít. Navigáljon az irányítópult Ügyfelek szakaszához. A beállításokban állítsuk a visszahívást //localhost:3000:

A hitelesítő adatokkal frissítsük a React összetevőket.

APP komponens

const AUTH0_CLIENT_ID = "aIAOt9fkMZKrNsSsFqbKj5KTI0ObTDPP"; const AUTH0_DOMAIN = "hakaselabs.auth0.com"; const AUTH0_CALLBACK_URL = location.href; const AUTH0_API_AUDIENCE = "golang-gin"; class App extends React.Component { parseHash() { this.auth0 = new auth0.WebAuth({ domain: AUTH0_DOMAIN, clientID: AUTH0_CLIENT_ID }); this.auth0.parseHash(window.location.hash, (err, authResult) => { if (err) { return console.log(err); } if ( authResult !== null && authResult.accessToken !== null && authResult.idToken !== null ) { localStorage.setItem("access_token", authResult.accessToken); localStorage.setItem("id_token", authResult.idToken); localStorage.setItem( "profile", JSON.stringify(authResult.idTokenPayload) ); window.location = window.location.href.substr( 0, window.location.href.indexOf("#") ); } }); } setup() { $.ajaxSetup({ beforeSend: (r) => { if (localStorage.getItem("access_token")) { r.setRequestHeader( "Authorization", "Bearer " + localStorage.getItem("access_token") ); } } }); } setState() { let idToken = localStorage.getItem("id_token"); if (idToken) { this.loggedIn = true; } else { this.loggedIn = false; } } componentWillMount() { this.setup(); this.parseHash(); this.setState(); } render() { if (this.loggedIn) { return ; } return ; } }

Frissítettük az App komponens három komponens módszerekkel ( setup, parseHashés setState), és az életciklus módszer componentWillMount. A parseHashmódszer inicializálja az auth0webAuthügyfelet, és a kivonatot olvashatóbb formátumba elemzi, elmentve őket a localSt-be. A zárolási képernyő megjelenítéséhez rögzítse és tárolja a felhasználói tokent, és adja hozzá a helyes hitelesítési fejlécet az API kéréseinkhez

Otthoni alkatrész

A Home komponensünk frissül. Hozzáadjuk a authenticatemódszer funkcionalitását , amely elindítja a hosztolt zárképernyő megjelenítését, és lehetővé teszi felhasználóink ​​számára a bejelentkezést vagy a regisztrációt.

class Home extends React.Component { constructor(props) { super(props); this.authenticate = this.authenticate.bind(this); } authenticate() { this.WebAuth = new auth0.WebAuth({ domain: AUTH0_DOMAIN, clientID: AUTH0_CLIENT_ID, scope: "openid profile", audience: AUTH0_API_AUDIENCE, responseType: "token id_token", redirectUri: AUTH0_CALLBACK_URL }); this.WebAuth.authorize(); } render() { return ( 

Jokeish

A load of Dad jokes XD

Sign in to get access

Sign In ); } }

LoggedIn komponens

Frissítjük az LoggedInösszetevőt, hogy kommunikálhassunk az API-val, és minden viccet behúzunk. Minden viccet átad a- propnak az Jokeösszetevőnek, amely rendszertöltő panelt jelenít meg. Írjuk ezeket:

class LoggedIn extends React.Component { constructor(props) { super(props); this.state = { jokes: [] }; this.serverRequest = this.serverRequest.bind(this); this.logout = this.logout.bind(this); } logout() { localStorage.removeItem("id_token"); localStorage.removeItem("access_token"); localStorage.removeItem("profile"); location.reload(); } serverRequest() { $.get("//localhost:3000/api/jokes", res => { this.setState({ jokes: res }); }); } componentDidMount() { this.serverRequest(); } render() { return (

Log out

Jokeish

Let's feed you with some funny Jokes!!!

{this.state.jokes.map(function(joke, i) { return ; })} ); } }

Vicc komponens

Frissítjük az Jokeösszetevőt úgy is, hogy megformázzuk a Szülő-összetevőtől ( LoggedIn) átadott minden viccelemet . Hozzáadunk egy likemódszert is, amely növeli a viccek tetszését.

class Joke extends React.Component { constructor(props) { super(props); this.state = { liked: "", jokes: [] }; this.like = this.like.bind(this); this.serverRequest = this.serverRequest.bind(this); } like() { let joke = this.props.joke; this.serverRequest(joke); } serverRequest(joke) { $.post( "//localhost:3000/api/jokes/like/" + joke.id, { like: 1 }, res => { console.log("res... ", res); this.setState({ liked: "Liked!", jokes: res }); this.props.jokes = res; } ); } render() { return ( #{this.props.joke.id}{" "} {this.state.liked} {this.props.joke.joke} {this.props.joke.likes} Likes ) } }

Összedobva az egészet

Az UI és az API elkészültével tesztelhetjük az alkalmazásunkat. Először a szerver indításával source .env && go run main.goindulunk, majd //localhost:3000bármelyik böngészőből navigálunk. Látnia kell az Homeösszetevőt egy bejelentkezési gombbal. A bejelentkezés gombra kattintva átirányít egy hosztolt zár oldalra (hozzon létre fiókot vagy bejelentkezési adatot) az alkalmazás folytatásához.

Itthon:

Auth0 tárolt zárolási képernyő:

Bejelentkezett alkalmazás nézetben:

Következtetés

Gratula! Megtanulta, hogyan kell egy alkalmazást és egy API-t felépíteni a Go és a Gin keretrendszerrel.

Hiányzott valami fontos dolog? Tudassa velem a kommentekben.

Sziasztok nekem a Twitteren @codehakase