未加星标

Authorization with GraphQL, Golang, and Couchbase NoSQL using JWT

字体大小 | |
[数据库(综合) 所属分类 数据库(综合) | 发布者 店小二04 | 时间 2018 | 作者 红领巾 ] 0人收藏点击收藏

Over the past few months I’ve been writing a GraphQL series using the Go programming language. First we saw how to get started with GraphQL and Go , followed by an alternative way to handle data relationships by using resolvers on GraphQL objects. Going a step further we saw how to include JSON web tokens (JWT) for authorization on GraphQL objects, but without a database.

The logical next step in this GraphQL with Golang journey would be to wire upCouchbase to a fully functional GraphQL powered API that includes authorization with JSON web tokens (JWT). We’re going to see how to handle account creation, JWT validation, and working with live data through GraphQL queries.

Before diving into some design and development, if you haven’t seen my previous tutorials on the subject, you probably should. I wouldn’t recommend getting into the JWT side of things until you have an understanding of using GraphQL with Golang.

Including Couchbase in a GraphQL with JWT Application

Instead of reiterating on the process of creating a GraphQL powered application, we’re going to start from where we left off in the series. The previous JWT tutorial in the series left us with the following code:

package main import ( "context" "encoding/json" "errors" "fmt" "net/http" jwt "github.com/dgrijalva/jwt-go" "github.com/graphql-go/graphql" "github.com/mitchellh/mapstructure" ) type User struct { Id string `json:"id"` Username string `json:"username"` Password string `json:"password"` } type Blog struct { Idstring `json:"id"` Title string `json:"title"` Content string `json:"content"` Authorstring `json:"author"` Pageviews int32`json:"pageviews"` } var jwtSecret []byte = []byte("thepolyglotdeveloper") var accountsMock []User = []User{ User{ Id: "1", Username: "nraboy", Password: "1234", }, User{ Id: "2", Username: "mraboy", Password: "5678", }, } var blogsMock []Blog = []Blog{ Blog{ Id:"1", Author:"nraboy", Title: "Sample Article", Content: "This is a sample article written by Nic Raboy", Pageviews: 1000, }, } var accountType *graphql.Object = graphql.NewObject(graphql.ObjectConfig{ Name: "Account", Fields: graphql.Fields{ "id": &graphql.Field{ Type: graphql.String, }, "username": &graphql.Field{ Type: graphql.String, }, "password": &graphql.Field{ Type: graphql.String, }, }, }) var blogType *graphql.Object = graphql.NewObject(graphql.ObjectConfig{ Name: "Blog", Fields: graphql.Fields{ "id": &graphql.Field{ Type: graphql.String, }, "title": &graphql.Field{ Type: graphql.String, }, "content": &graphql.Field{ Type: graphql.String, }, "author": &graphql.Field{ Type: graphql.String, }, "pageviews": &graphql.Field{ Type: graphql.Int, Resolve: func(params graphql.ResolveParams) (interface{}, error) { _, err := ValidateJWT(params.Context.Value("token").(string)) if err != nil { return nil, err } return params.Source.(Blog).Pageviews, nil }, }, }, }) func ValidateJWT(t string) (interface{}, error) { if t == "" { return nil, errors.New("Authorization token must be present") } token, _ := jwt.Parse(t, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("There was an error") } return jwtSecret, nil }) if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { var decodedToken interface{} mapstructure.Decode(claims, &decodedToken) return decodedToken, nil } else { return nil, errors.New("Invalid authorization token") } } func CreateTokenEndpoint(response http.ResponseWriter, request *http.Request) { var user User _ = json.NewDecoder(request.Body).Decode(&user) token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "username": user.Username, "password": user.Password, }) tokenString, error := token.SignedString(jwtSecret) if error != nil { fmt.Println(error) } response.Header().Set("content-type", "application/json") response.Write([]byte(`{ "token": "` + tokenString + `" }`)) } func main() { fmt.Println("Starting the application at :12345...") rootQuery := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ "account": &graphql.Field{ Type: accountType, Resolve: func(params graphql.ResolveParams) (interface{}, error) { account, err := ValidateJWT(params.Context.Value("token").(string)) if err != nil { return nil, err } for _, accountMock := range accountsMock { if accountMock.Username == account.(User).Username { return accountMock, nil } } return &User{}, nil }, }, "blogs": &graphql.Field{ Type: graphql.NewList(blogType), Resolve: func(params graphql.ResolveParams) (interface{}, error) { return blogsMock, nil }, }, }, }) schema, _ := graphql.NewSchema(graphql.SchemaConfig{ Query: rootQuery, }) http.HandleFunc("/graphql", func(response http.ResponseWriter, request *http.Request) { result := graphql.Do(graphql.Params{ Schema:schema, RequestString: request.URL.Query().Get("query"), Context: context.WithValue(context.Background(), "token", request.URL.Query().Get("token")), }) json.NewEncoder(response).Encode(result) }) http.HandleFunc("/login", CreateTokenEndpoint) http.ListenAndServe(":12345", nil) }

Our goal now is to swap out all that mock data with real data that exists in Couchbase. We won’t worry about creating blog data in this tutorial, but if you want to learn about mutations, check out one of the previous tutorials.

The obvious first step towards using dynamic data is to set up our database, Couchbase. Create the following global variable to be used in each of our GraphQL objects:

var bucket *gocb.Bucket

With the global Bucket reference created, let’s establish a connection to our Couchbase cluster and open a bucket. This can be done in our project’s main function:

cluster, _ := gocb.Connect("couchbase://localhost") cluster.Authenticate(gocb.PasswordAuthenticator{Username: "example", Password: "123456"}) bucket, _ = cluster.OpenBucket("example", "")

The above code assumes a locally running cluster and RBAC as well as Bucket information already created and defined. If you haven’t properly configured your Couchbase instance for this application, take a moment to do so.

Since we’re working with a NoSQL database and no longer mock data, our native Go structures need to change slightly:

type User struct { Id string `json:"id,omitempty"` Username string `json:"username"` Password string `json:"password"` Type string `json:"type"` } type Blog struct { Idstring `json:"id,omitempty"` Title string `json:"title"` Content string `json:"content"` Authorstring `json:"author"` Pageviews int32`json:"pageviews"` Typestring `json:"type"` } By adding a Type property, we can write better queries because we can differentiate our data. Changing the Go data structures does not mean we need to update our GraphQL objects. What we expect to retur

本文数据库(综合)相关术语:系统安全软件

主题: SQLHead
tags: graphql,json,nil,amp,token,string,GraphQL,return,Type,Field,User
分页:12
转载请注明
本文标题:Authorization with GraphQL, Golang, and Couchbase NoSQL using JWT
本站链接:https://www.codesec.net/view/580615.html


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 数据库(综合) | 评论(0) | 阅读(52)