Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
netqyq committed Oct 3, 2017
0 parents commit bf632e2
Show file tree
Hide file tree
Showing 35 changed files with 1,265 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
test-results/
tmp/
routes/
*.db
117 changes: 117 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# deer-api
An API server using JWT Authentication based on Revel framework.


### About JWT Authetication

Using jwt-go lib. Setting user's email as `email` in cliams.

It behaviors like knock ruby gem. https://github.com/nsarno/knock

### Authenticating from a web or mobile application

1. register user
```
curl -v -X POST -d 'email="test@test.com"&password="your_pass"' http://localhost:9001/register
```

the response
```
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im5ldHF5cUAxNjMuY29tIiwibmJmIjoxNDQ0NDc4NDAwfQ.bZo1DzrzZBetB9IP7fVip5XA_GiFBb_z8zDNTalReuU"
```


2. request to get a token from your API:
```
POST /login
{"auth": {"email": "foo@bar.com", "password": "secret"}}
```

Example response from the API:
```
201 Created
{"jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9"}
```

To make an authenticated request to your API, you need to pass the token via the request header:
```
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
GET /my_resources
```


### Basic CRUD Example
`resources :products`

create product
```
curl -v -X POST -H "Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im5ldHF5cUAxNjMuY29tIiwibmJmIjoxNDQ0NDc4NDAwfQ.bZo1DzrzZBetB9IP7fVip5XA_GiFBb_z8zDNTalReuU" -d 'name="tomato"&price="12.0"&code="T0001"}' "http://localhost:9001/products"
```

show product
```
curl -v -X GET -H "Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im5ldHF5cUAxNjMuY29tIiwibmJmIjoxNDQ0NDc4NDAwfQ.bZo1DzrzZBetB9IP7fVip5XA_GiFBb_z8zDNTalReuU" "http://localhost:9001/products/1"
```

index product
```
curl -v -X GET -H "Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im5ldHF5cUAxNjMuY29tIiwibmJmIjoxNDQ0NDc4NDAwfQ.bZo1DzrzZBetB9IP7fVip5XA_GiFBb_z8zDNTalReuU" "http://localhost:9001/products"
```

update product
```
curl -v -X PUT -H "Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im5ldHF5cUAxNjMuY29tIiwibmJmIjoxNDQ0NDc4NDAwfQ.bZo1DzrzZBetB9IP7fVip5XA_GiFBb_z8zDNTalReuU" -d 'name="tomato"&price="12.0"&code="T0001"}' "http://localhost:9001/products/1"
```

delete product
```
curl -v -X DELETE -H "Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im5ldHF5cUAxNjMuY29tIiwibmJmIjoxNDQ0NDc4NDAwfQ.bZo1DzrzZBetB9IP7fVip5XA_GiFBb_z8zDNTalReuU" "http://localhost:9001/products/1"
```



### Press Testing
see docs/press_testing.md


### JWT Secret Key
change `hmacSecret` var to your own.


### Start the web server:

revel run deer-api



### Code Layout

The directory structure of a generated Revel application:

conf/ Configuration directory
app.conf Main app configuration file
routes Routes definition file

app/ App sources
init.go Interceptor registration
controllers/ App controllers go here
views/ Templates directory

messages/ Message files

public/ Public static assets
css/ CSS files
js/ Javascript files
images/ Image files

tests/ Test suites




### Help

* The [Getting Started with Revel](http://revel.github.io/tutorial/gettingstarted.html).
* The [Revel guides](http://revel.github.io/manual/index.html).
* The [Revel sample apps](http://revel.github.io/examples/index.html).
* The [API documentation](https://godoc.org/github.com/revel/revel).
Binary file added app/.DS_Store
Binary file not shown.
Binary file added app/controllers/.DS_Store
Binary file not shown.
14 changes: 14 additions & 0 deletions app/controllers/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package controllers

import (
"github.com/revel/revel"
)

type App struct {
GorpController
}

func (c App) Index() revel.Result {
greeting := "Aloha World"
return c.Render(greeting)
}
17 changes: 17 additions & 0 deletions app/controllers/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package controllers

import (
"errors"
"log"
)

var (
errAuthHeaderNotFound = errors.New("authorization header not found")
errInvalidTokenFormat = errors.New("token format is invalid")
)

func checkErr(err error, msg string) {
if err != nil {
log.Println(msg)
}
}
1 change: 1 addition & 0 deletions app/controllers/gorm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package controllers
83 changes: 83 additions & 0 deletions app/controllers/gorp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package controllers

import (
"database/sql"

"github.com/netqyq/deer-api/app/models"

"github.com/go-gorp/gorp"
_ "github.com/mattn/go-sqlite3"

"github.com/revel/modules/db/app"
r "github.com/revel/revel"
)

var (
Dbm *gorp.DbMap
)

type GorpController struct {
*r.Controller
Txn *gorp.Transaction
}

func InitDB1() {
db.Init()
Dbm = &gorp.DbMap{Db: db.Db, Dialect: gorp.SqliteDialect{}}

setColumnSizes := func(t *gorp.TableMap, colSizes map[string]int) {
for col, size := range colSizes {
t.ColMap(col).MaxSize = size
}
}

t := Dbm.AddTable(models.User{}).SetKeys(true, "UserId")
t.ColMap("Password").Transient = true
setColumnSizes(t, map[string]int{
"Email": 60,
"Name": 100,
})

t1 := Dbm.AddTable(models.Product{}).SetKeys(true, "Id")
setColumnSizes(t1, map[string]int{
"Name": 200,
})

err := Dbm.CreateTablesIfNotExists()
checkErr(err, "Create tables failed")

Dbm.TraceOn("[gorp]", r.INFO)
Dbm.CreateTables()

}

func (c *GorpController) Begin() r.Result {
txn, err := Dbm.Begin()
if err != nil {
panic(err)
}
c.Txn = txn
return nil
}

func (c *GorpController) Commit() r.Result {
if c.Txn == nil {
return nil
}
if err := c.Txn.Commit(); err != nil && err != sql.ErrTxDone {
panic(err)
}
c.Txn = nil
return nil
}

func (c *GorpController) Rollback() r.Result {
if c.Txn == nil {
return nil
}
if err := c.Txn.Rollback(); err != nil && err != sql.ErrTxDone {
panic(err)
}
c.Txn = nil
return nil
}
80 changes: 80 additions & 0 deletions app/controllers/init.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package controllers

import (
"log"
"net/http"
"strings"

jwt "github.com/dgrijalva/jwt-go"
"github.com/revel/revel"
)

func AddLog(c *revel.Controller) revel.Result {
log.Println("InterceptFunc Test.")
return nil
}

// Authenticate is and method will be called before any authenticate needed action.
// In order to valid the user.
func Authenticate(c *revel.Controller) revel.Result {
log.Println("Authenticate!")
log.Println(c.Params)

tokenString, err := getTokenString(c)
if err != nil {
log.Println("get token string failed")
c.Response.Status = http.StatusBadRequest
return c.RenderJSON("get token string failed")
}

var claims jwt.MapClaims
claims, err = decodeToken(tokenString)
if err != nil {
c.Response.Status = http.StatusUnauthorized
return c.RenderJSON("auth failed")
}
log.Println("claims decode:", claims)
log.Println(claims["email"])
email, found := claims["email"]
if !found {
log.Println(err)
c.Response.Status = http.StatusBadRequest
return c.RenderJSON("email not found in db")
}
log.Println("email found:", email)
_, err = getUser(email.(string))
if err != nil {
log.Println(err)
c.Response.Status = http.StatusUnauthorized
return c.RenderJSON("auth failed")
}
log.Println("auth token success")
return nil
}

func getTokenString(c *revel.Controller) (tokenString string, err error) {
authHeader := c.Request.Header.Get("Authorization")
if authHeader == "" {
log.Println(errAuthHeaderNotFound)
return "", errAuthHeaderNotFound
}

tokenSlice := strings.Split(authHeader, " ")
if len(tokenSlice) != 2 {
return "", errInvalidTokenFormat
}
tokenString = tokenSlice[1]
return tokenString, nil

}

func init() {
revel.OnAppStart(InitDB1)
// test
revel.InterceptFunc(AddLog, revel.BEFORE, &App{})

revel.InterceptMethod((*GorpController).Begin, revel.BEFORE)
revel.InterceptFunc(Authenticate, revel.BEFORE, &App{})
revel.InterceptMethod((*GorpController).Commit, revel.AFTER)
revel.InterceptMethod((*GorpController).Rollback, revel.FINALLY)
}

0 comments on commit bf632e2

Please sign in to comment.