mirror of
https://github.com/kataras/iris.git
synced 2025-12-18 18:37:05 +00:00
add a jwt tutorial + go client
This commit is contained in:
12
_examples/auth/jwt/tutorial/go-client/README.md
Normal file
12
_examples/auth/jwt/tutorial/go-client/README.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# Go Client
|
||||
|
||||
```sh
|
||||
$ go run .
|
||||
```
|
||||
|
||||
```sh
|
||||
2020/11/04 21:08:40 Access Token:
|
||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiYTAwYzI3ZDEtYjVhYS00NjU0LWFmMTYtYjExNzNkZTY1NjI5Iiwicm9sZXMiOlsiYWRtaW4iXSwiaWF0IjoxNjA0NTE2OTIwLCJleHAiOjE2MDQ1MTc4MjAsImp0aSI6IjYzNmVmMDc0LTE2MzktNGJhZi1hNGNiLTQ4ZDM4NGMxMzliYSIsImlzcyI6Im15YXBwIn0.T9B0zG0AHShO5JfQgrMQBlToH33KHgp8nLMPFpN6QmM"
|
||||
2020/11/04 21:08:40 Todo Created:
|
||||
model.Todo{ID:"cfa38d7a-c556-4301-ae1f-fb90f705071c", UserID:"a00c27d1-b5aa-4654-af16-b1173de65629", Title:"test todo title", Body:"test todo body contents", CreatedAt:1604516920}
|
||||
```
|
||||
109
_examples/auth/jwt/tutorial/go-client/client.go
Normal file
109
_examples/auth/jwt/tutorial/go-client/client.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Client is the default http client instance used by the following methods.
|
||||
var Client = http.DefaultClient
|
||||
|
||||
// RequestOption is a function which can be used to modify
|
||||
// a request instance before Do.
|
||||
type RequestOption func(*http.Request) error
|
||||
|
||||
// WithAccessToken sets the given "token" to the authorization request header.
|
||||
func WithAccessToken(token []byte) RequestOption {
|
||||
bearer := "Bearer " + string(token)
|
||||
return func(req *http.Request) error {
|
||||
req.Header.Add("Authorization", bearer)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithContentType sets the content-type request header.
|
||||
func WithContentType(cType string) RequestOption {
|
||||
return func(req *http.Request) error {
|
||||
req.Header.Set("Content-Type", cType)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithContentLength sets the content-length request header.
|
||||
func WithContentLength(length int) RequestOption {
|
||||
return func(req *http.Request) error {
|
||||
req.Header.Set("Content-Length", strconv.Itoa(length))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Do fires a request to the server.
|
||||
func Do(method, url string, body io.Reader, opts ...RequestOption) (*http.Response, error) {
|
||||
req, err := http.NewRequest(method, url, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
if err = opt(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return Client.Do(req)
|
||||
}
|
||||
|
||||
// JSON fires a request with "v" as client json data.
|
||||
func JSON(method, url string, v interface{}, opts ...RequestOption) (*http.Response, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
err := json.NewEncoder(buf).Encode(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
opts = append(opts, WithContentType("application/json; charset=utf-8"))
|
||||
return Do(method, url, buf, opts...)
|
||||
}
|
||||
|
||||
// Form fires a request with "formData" as client form data.
|
||||
func Form(method, url string, formData url.Values, opts ...RequestOption) (*http.Response, error) {
|
||||
encoded := formData.Encode()
|
||||
body := strings.NewReader(encoded)
|
||||
|
||||
opts = append([]RequestOption{
|
||||
WithContentType("application/x-www-form-urlencoded"),
|
||||
WithContentLength(len(encoded)),
|
||||
}, opts...)
|
||||
|
||||
return Do(method, url, body, opts...)
|
||||
}
|
||||
|
||||
// BindResponse binds a response body to the "dest" pointer and closes the body.
|
||||
func BindResponse(resp *http.Response, dest interface{}) error {
|
||||
contentType := resp.Header.Get("Content-Type")
|
||||
if idx := strings.IndexRune(contentType, ';'); idx > 0 {
|
||||
contentType = contentType[0:idx]
|
||||
}
|
||||
|
||||
switch contentType {
|
||||
case "application/json":
|
||||
defer resp.Body.Close()
|
||||
return json.NewDecoder(resp.Body).Decode(dest)
|
||||
default:
|
||||
return fmt.Errorf("unsupported content type: %s", contentType)
|
||||
}
|
||||
}
|
||||
|
||||
// RawResponse simply returns the raw response body.
|
||||
func RawResponse(resp *http.Response) ([]byte, error) {
|
||||
defer resp.Body.Close()
|
||||
|
||||
return ioutil.ReadAll(resp.Body)
|
||||
}
|
||||
69
_examples/auth/jwt/tutorial/go-client/main.go
Normal file
69
_examples/auth/jwt/tutorial/go-client/main.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"myapp/api"
|
||||
"myapp/domain/model"
|
||||
)
|
||||
|
||||
const base = "http://localhost:8080"
|
||||
|
||||
func main() {
|
||||
accessToken, err := authenticate("admin", "admin")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Printf("Access Token:\n%q", accessToken)
|
||||
|
||||
todo, err := createTodo(accessToken, "test todo title", "test todo body contents")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Printf("Todo Created:\n%#+v", todo)
|
||||
}
|
||||
|
||||
func authenticate(username, password string) ([]byte, error) {
|
||||
endpoint := base + "/signin"
|
||||
|
||||
data := make(url.Values)
|
||||
data.Set("username", username)
|
||||
data.Set("password", password)
|
||||
|
||||
resp, err := Form(http.MethodPost, endpoint, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
accessToken, err := RawResponse(resp)
|
||||
return accessToken, err
|
||||
}
|
||||
|
||||
func createTodo(accessToken []byte, title, body string) (model.Todo, error) {
|
||||
var todo model.Todo
|
||||
|
||||
endpoint := base + "/todos"
|
||||
|
||||
req := api.TodoRequest{
|
||||
Title: title,
|
||||
Body: body,
|
||||
}
|
||||
|
||||
resp, err := JSON(http.MethodPost, endpoint, req, WithAccessToken(accessToken))
|
||||
if err != nil {
|
||||
return todo, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
rawData, _ := RawResponse(resp)
|
||||
return todo, fmt.Errorf("failed to create a todo: %s", string(rawData))
|
||||
}
|
||||
|
||||
err = BindResponse(resp, &todo)
|
||||
return todo, err
|
||||
}
|
||||
Reference in New Issue
Block a user