
TL; DR: У цьому посібнику я покажу вам, як легко створити веб-додаток із Go та фреймворком Gin та додати до нього аутентифікацію. Перевірте репо Github для коду, який ми збираємося писати.
Gin - це високопродуктивний мікрофреймворк. Він забезпечує дуже мінімалістичну структуру, яка несе в собі лише найважливіші функції, бібліотеки та функціональні можливості, необхідні для побудови веб-додатків та мікросервісів. Це спрощує побудову конвеєру для обробки запитів з модульних деталей, які можна багаторазово використовувати. Це робиться, дозволяючи писати проміжне програмне забезпечення, яке можна підключити до одного або декількох обробників запитів або груп обробників запитів.
Джин особливості
Gin - це швидкий, простий, але повнофункціональний і дуже ефективний веб-фреймворк для Go. Ознайомтеся з деякими функціями нижче, які роблять його гідною структурою для розгляду для вашого наступного проекту Golang.
- Швидкість: Джин створений для швидкості. Фреймворк пропонує маршрутизацію на основі дерева Radix та невеликий розмір пам'яті. Жодних роздумів. Передбачувана продуктивність API.
- Без аварій: Джин має можливість ловити аварії або паніку під час роботи, і може відновити їх. Таким чином ваша заявка буде завжди доступною.
- Маршрутизація: Gin надає інтерфейс маршрутизації, що дозволяє вам висловити вигляд вашого веб-додатка або маршрутів API.
- Перевірка JSON: Gin може легко аналізувати та перевіряти запити JSON, перевіряючи наявність необхідних значень.
- Управління помилками : Gin надає зручний спосіб зібрати всі помилки, які сталися під час запиту HTTP. Зрештою, проміжне програмне забезпечення може записати їх у файл журналу або в базу даних і відправити через мережу.
- Вбудований рендеринг: Gin надає простий у використанні API для візуалізації JSON, XML та HTML.
Передумови
Щоб продовжити роботу з цим посібником, вам потрібно встановити Go на вашій машині, веб-браузер для перегляду програми та командний рядок для виконання команд збірки.
Go, або як його зазвичай називають Golang , - це мова програмування, розроблена Google для створення сучасного програмного забезпечення. Go - це мова, призначена для ефективного та швидкого виконання завдань. Ключові переваги Go включають:
- Сильно набрано і сміття зібрано
- Швидкий швидкий час компіляції
- Вбудована паралельність
- Велика стандартна бібліотека
Перейдіть до розділу завантажень веб-сайту Go, щоб запустити Go на своїй машині.
Створення програми за допомогою Gin
Ми створимо простий додаток для переліку жартів разом з Gin . Наш додаток перелічить кілька дурних жартів з татом. Ми збираємось додати до нього аутентифікацію, так що всі ввійшли користувачі матимуть привілей подобатись і переглядати жарти.
Це дозволить нам проілюструвати, як Gin можна використовувати для розробки веб-додатків та / або API.

Ми будемо використовувати наступні функціональні можливості, пропоновані Gin:
- Проміжне програмне забезпечення
- Маршрутизація
- Групування маршрутів
На старт, увага, марш
Ми напишемо всю програму Go у main.go
файлі. Оскільки це невеликий додаток, його буде легко побудувати лише go run
за допомогою терміналу.
Ми створимо новий каталог golang-gin
у нашій робочій області Go, а потім main.go
файл у ньому:
$ mkdir -p $GOPATH/src/github.com/user/golang-gin $ cd $GOPATH/src/github.com/user/golang-gin $ touch main.go
Зміст main.go
файлу:
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") }
Нам потрібно буде створити ще кілька каталогів для наших статичних файлів. У тому ж каталозі, що і main.go
файл, давайте створимо views
папку. У views
папці створіть js
папку та index.html
файл у ній.
Наразі index.html
файл буде дуже простим:
Jokeish App Welcome to the Jokeish App
Перш ніж перевірити те, що ми маємо на сьогодні, давайте встановимо додані залежності:
$ go get -u github.com/gin-gonic/gin $ go get -u github.com/gin-gonic/contrib/static
Щоб побачити, що працює, нам потрібно запустити наш сервер, запустивши go run main.go
.

Після запуску програми перейдіть до //localhost:3000
веб-переглядача. Якщо все пішло добре, ви побачите текст заголовка 1 рівня Вітається в додатку Jokeish .

Визначення API
Давайте додамо ще трохи коду у наш main.go
файл для наших визначень API. Ми оновимо нашу main
функцію двома маршрутами /jokes/
та /jokes/like/:jokeID
до групи маршрутів /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", }) }
Вміст main.go
файлу повинен виглядати так:
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", }) }
Давайте запустимо наш додаток ще раз go run main.go
і отримаємо доступ до наших маршрутів. //localhost:3000/api/jokes
поверне відповідь 200 OK
заголовка з повідомленням jokes handler not implemented yet
. Запит POST на //localhost:3000/api/jokes/like/1
повернення 200 OK
заголовка та повідомлення Likejoke handler not implemented yet
.
Жарти даних
Оскільки у нас уже встановлено визначення маршрутів, яке робить лише одне (повернути відповідь JSON), ми трохи оживимо нашу кодову базу, додавши до неї ще трохи коду.
// ... 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
Якщо наш код добре виглядає, давайте перевіримо наш API. Ми можемо протестувати за допомогою cURL
або postman
, а потім надіслати GET
запит на //localhost:3000/jokes
отримання повного списку жартів та POST
запит //localhost:3000/jokes/like/{jokeid}
на збільшення кількості жартів.
$ curl //localhost:3000/api/jokes $ curl -X POST //localhost:3000/api/jokes/like/4
Створення інтерфейсу користувача (React)
У нас є наш API, тому давайте створимо інтерфейс для представлення даних з нашого API. Для цього ми будемо використовувати React. Ми не будемо заглиблюватися в React, оскільки це буде виходити за межі цього підручника. Якщо вам потрібно дізнатись більше про React, перегляньте офіційний підручник. Ви можете реалізувати інтерфейс користувача з будь-яким фронтенд-фреймворком, який вам зручний.
Налаштування
Ми відредагуємо index.html
файл, щоб додати зовнішні бібліотеки, необхідні для запуску React. Тоді нам потрібно буде створити app.jsx
файл у views/js
каталозі, який буде містити наш код React.
Наш index.html
файл повинен виглядати так:
Jokeish App
Створення наших компонентів
У React подання розбиваються на компоненти. Нам потрібно буде створити деякі компоненти:
App
компонент в якості головного входу , який запускає додатокHome
компонент , який зіткнеться з Некомерційним зареєстрованими користувачамиLoggedIn
компонент з вмістом тільки видимим користувачам , які пройшли перевірку- і
Joke
компонент для відображення списку жартів.
Ми запишемо всі ці компоненти у app.jsx
файл.
Компонент програми
Цей компонент завантажує весь наш додаток React. Він вирішує, який компонент показувати, виходячи з того, аутентифіковано користувача чи ні. Ми почнемо лише з його основи, а пізніше оновимо її з більшою функціональністю.
class App extends React.Component { render() { if (this.loggedIn) { return (); } else { return (); } } }
Домашній компонент
Цей компонент відображається для користувачів, які не ввійшли в систему, разом із кнопкою, що відкриває розміщений екран блокування, де вони можуть зареєструватися або увійти. Ми додамо цю функцію пізніше.
class Home extends React.Component { render() { return ( Jokeish
A load of Dad jokes XD
Sign in to get access
Sign In ) } }
Вхідний компонент
Цей компонент відображається під час автентифікації користувача. Він зберігає у своєму state
масиві жарти, які заповнюються, коли компонент монтується.
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 (); })} ) } }
Компонент Жарт
Joke
Компонент буде містити інформацію про кожен елемент , від жарту відгуку , які будуть відображатися.
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 ) } }
Ми написали наші компоненти, тож тепер давайте скажемо React, куди візуалізувати додаток. Блок коду ми додамо внизу нашого app.jsx
файлу.
ReactDOM.render(, document.getElementById('app'));
Давайте перезапустимо наш сервер Go go run main.go
і перейдемо до URL-адреси нашого додатка //localhost:3000/
. Ви побачите, що Home
компонент відображається.

Захист нашого додатка для жартів за допомогою Auth0
Auth0 видає веб-маркери JSON під час кожного входу для користувачів. Це означає, що ви можете мати надійну інфраструктуру ідентифікації, включаючи єдиний вхід, управління користувачами, підтримку постачальників соціальних ідентифікаторів (Facebook, Github, Twitter тощо), постачальників корпоративних ідентифікаторів (Active Directory, LDAP, SAML тощо). і власну базу даних користувачів, лише кілька рядків коду.
Ми можемо легко налаштувати автентифікацію в нашому додатку GIN, використовуючи Auth0. Вам знадобиться обліковий запис, щоб підписатися на цю частину. Якщо у вас ще немає облікового запису Auth0, зареєструйтесь зараз.
Застереження: це не спонсорований вміст.Створення клієнта API
Наші маркери будуть генеруватися за допомогою Auth0, тому нам потрібно створити API та клієнта на нашій інформаційній панелі Auth0. Знову ж таки, якщо ви цього ще не зробили, підпишіться на рахунок Auth0.
Щоб створити новий API, перейдіть до розділу API на інформаційній панелі та натисніть кнопку Створити API .

Виберіть назву API та ідентифікатор . Ідентифікатором буде аудиторія проміжного програмного забезпечення. Підписання Алгоритм повинен бути RS256 .
Щоб створити нового клієнта, перейдіть до розділу клієнтів на інформаційній панелі та натисніть кнопку Створити клієнта . Виберіть тип Regular Web Applications
.

Після створення клієнта зверніть увагу на client_id
і client_secret
, оскільки вони нам знадобляться пізніше.

Ми повинні додати облікові дані, необхідні для нашого API, до змінної середовища. У кореневому каталозі створіть новий файл .env
і додайте до нього наступне з деталями з інформаційної панелі Auth0:
export export export AUTH0_DOMAIN="yourdomain.auth0.com" export
Захист наших кінцевих точок API
На даний момент наш API відкритий для усього світу. Нам потрібно захистити наші кінцеві точки, щоб лише авторизовані користувачі мали до них доступ.
Ми будемо використовувати проміжне програмне забезпечення JWT, щоб перевірити наявність дійсного веб-маркера JSON з кожного запиту, що потрапляє в наші кінцеві точки.
Давайте створимо наше проміжне програмне забезпечення:
// ... 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 } } }
У наведеному вище коді ми маємо нову jwtMiddleWare
змінну, яка ініціалізується у main
функції. Він використовується в authMiddleware
середній функції.
Якщо ви помітили, ми витягуємо наші облікові дані на стороні сервера із змінної середовища (одного з принципів 12-факторної програми ). Наше проміжне програмне забезпечення перевіряє та отримує маркер із запиту та викликає jwtMiddleWare.CheckJWT
метод для перевірки відправленого маркера.
Давайте також напишемо функцію для повернення веб-ключів JSON:
// ... 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 }
Використання проміжного програмного забезпечення JWT
Користуватися проміжним програмним забезпеченням дуже просто. Ми просто передаємо його як параметр до визначення наших маршрутів.
... api.GET("/jokes", authMiddleware(), JokeHandler) api.POST("/jokes/like/:jokeID", authMiddleware(), LikeJoke) ...
Наш main.go
файл повинен виглядати так:
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) } }
Встановимо jwtmiddleware
бібліотеки:
$ go get -u github.com/auth0/go-jwt-middleware $ go get -u github.com/dgrijalva/jwt-go
Давайте створимо файл нашого середовища та перезапустимо наш сервер додатків:
$ source .env $ go run main.go
Тепер, якщо ми спробуємо отримати доступ до будь-якої з кінцевих точок, ми зіткнемося з 401 Unauthorized
помилкою. Це тому, що нам потрібно надіслати маркер разом із запитом.
Увійдіть за допомогою Auth0 та React
Давайте впровадимо систему входу, щоб користувачі могли входити в систему або створювати облікові записи та отримувати доступ до наших жартів. Ми додамо до нашого app.jsx
файлу такі облікові дані Auth0:
AUTH0_CLIENT_ID
AUTH0_DOMAIN
AUTH0_CALLBACK_URL
- URL-адреса вашого додаткаAUTH0_API_AUDIENCE
AUTH0_CLIENT_ID
, AUTH0_DOMAIN
і AUTH0_API_AUDIENCE
дані з приладової панелі управління Auth0.Нам потрібно встановити значення, на callback
яке переспрямовує Auth0. Перейдіть до розділу Клієнти на своїй інформаційній панелі. У налаштуваннях встановимо зворотний дзвінок на //localhost:3000
:

З наявними обліковими даними, давайте оновимо наші компоненти React.
Компонент APP
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 ; } }
Ми оновили компонент App з трьома компонентами метод ( setup
, parseHash
і setState
), і методом життєвого циклу componentWillMount
. parseHash
Метод инициализирует auth0
webAuth
клієнт і аналізує хеш більш читається формат, зберігаючи їх у localSt. Щоб показати екран блокування, захопіть і збережіть маркер користувача та додайте правильний заголовок авторизації до будь-яких запитів до нашого API
Домашня складова
Наш компонент Home буде оновлений. Ми додамо функціонал для authenticate
методу, який спричинить відображення розміщеного екрана блокування та дозволить нашим користувачам увійти в систему або зареєструватися.
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
компонент для зв’язку з нашим API і потягнемо всі жарти. Він буде проходити кожну жарт , як prop
до Joke
компоненту, який робить панель початкового завантаження. Давайте напишемо такі:
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 ; })} ); } }
Жартівний компонент
Ми також оновимо Joke
компонент для форматування кожного елемента жарту, переданого йому з батьківського компонента ( LoggedIn
). Ми також додамо like
метод, який збільшить кількість жартів.
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 ) } }
Склавши все це разом
Після завершення інтерфейсу та API ми можемо протестувати наш додаток. Ми почнемо із завантаження нашого сервера source .env && go run main.go
, а потім перейдемо //localhost:3000
з будь-якого браузера. Ви повинні побачити Home
компонент із кнопкою входу. Натиснувши кнопку входу, ви перенаправите на розміщену сторінку блокування (створити обліковий запис або логін), щоб продовжувати користуватися програмою.
Головна

Екран блокування Auth0:

Перегляд програми LoggedIn:

Висновок
Вітаємо! Ви дізналися, як створити додаток та API за допомогою Go та Gin framework.
Я пропустив щось важливе? Повідомте мене про це в коментарях.
Ви можете сказати привіт мені на Twitter @codehakase