mirror of
https://github.com/astaxie/beego.git
synced 2024-11-22 09:20:55 +00:00
commit
4202fe8fe0
135
plugins/jwt/jwt.go
Normal file
135
plugins/jwt/jwt.go
Normal file
@ -0,0 +1,135 @@
|
||||
// Copyright 2014 beego Author. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package jwt provides JWT (Json Web Token) authentication
|
||||
//
|
||||
// Usage
|
||||
// In file main.go
|
||||
//
|
||||
// import (
|
||||
// "github.com/astaxie/beego"
|
||||
// "github.com/astaxie/beego/plugins/jwt"
|
||||
// )
|
||||
//
|
||||
// func main() {
|
||||
// // JWT for Url matching /v1/*
|
||||
// // PrivateKeyPath: The path for the private RSA key used by JWT
|
||||
// // PublicKeyPath: The path for the public RSA key used by JWT
|
||||
// // The list of Urls should be excluded from the JWT Auth
|
||||
// beego.InsertFilter("/v1/*", beego.BeforeRouter, jwt.AuthRequest(&jwt.Options{
|
||||
// PrivateKeyPath: "conf/beeblog.rsa",
|
||||
// PublicKeyPath: "conf/beeblog.rsa.pub",
|
||||
// WhiteList: []string{"/v1/jwt/issue-token", "/docs"},
|
||||
// }))
|
||||
// beego.Run()
|
||||
// }
|
||||
//
|
||||
// In file routers/router.go
|
||||
//
|
||||
// import (
|
||||
// "github.com/astaxie/beego"
|
||||
// "github.com/astaxie/beego/plugins/jwt"
|
||||
// )
|
||||
// func init() {
|
||||
// ns := beego.NSNamespace("/jwt",
|
||||
// beego.NSInclude(
|
||||
// &jwt.JwtController{},
|
||||
// ),
|
||||
// )
|
||||
// beego.AddNamespace(ns)
|
||||
// }
|
||||
//
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/context"
|
||||
"github.com/astaxie/beego/logs"
|
||||
goJwt "github.com/dgrijalva/jwt-go"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Options for the JWT Auth
|
||||
type Options struct {
|
||||
PrivateKeyPath string
|
||||
PublicKeyPath string
|
||||
WhiteList []string
|
||||
}
|
||||
|
||||
var RSAKeys struct {
|
||||
PrivateKey []byte
|
||||
PublicKey []byte
|
||||
}
|
||||
|
||||
func AuthRequest(o *Options) beego.FilterFunc {
|
||||
RSAKeys.PrivateKey, _ = ioutil.ReadFile(o.PrivateKeyPath)
|
||||
RSAKeys.PublicKey, _ = ioutil.ReadFile(o.PublicKeyPath)
|
||||
|
||||
return func(ctx *context.Context) {
|
||||
// :TODO the url patterns should be considered here.
|
||||
// Shouldn't only use the string equal
|
||||
for _, method := range o.WhiteList {
|
||||
if method == ctx.Request.URL.Path {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
parsedToken, err := goJwt.ParseFromRequest(ctx.Request, func(t *goJwt.Token) (interface{}, error) {
|
||||
return RSAKeys.PublicKey, nil
|
||||
})
|
||||
|
||||
if err == nil && parsedToken.Valid {
|
||||
ctx.Output.SetStatus(http.StatusOK)
|
||||
} else {
|
||||
ctx.Output.SetStatus(http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// oprations for Jwt
|
||||
type JwtController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (this *JwtController) URLMapping() {
|
||||
this.Mapping("IssueToken", this.IssueToken)
|
||||
}
|
||||
|
||||
// @Title IssueToken
|
||||
// @Description Issue a Json Web Token
|
||||
// @Success 200 string
|
||||
// @Failure 403 no privilege to access
|
||||
// @Failure 500 server inner error
|
||||
// @router /issue-token [get]
|
||||
func (this *JwtController) IssueToken() {
|
||||
this.Data["json"] = CreateToken()
|
||||
this.ServeJson()
|
||||
}
|
||||
|
||||
func CreateToken() map[string]string {
|
||||
log := logs.NewLogger(10000)
|
||||
log.SetLogger("console", "")
|
||||
|
||||
token := goJwt.New(goJwt.GetSigningMethod("RS256")) // Create a Token that will be signed with RSA 256.
|
||||
token.Claims["ID"] = "This is my super fake ID"
|
||||
token.Claims["exp"] = time.Now().Unix() + 36000
|
||||
// The claims object allows you to store information in the actual token.
|
||||
tokenString, _ := token.SignedString(RSAKeys.PrivateKey)
|
||||
// tokenString Contains the actual token you should share with your client.
|
||||
return map[string]string{"token": tokenString}
|
||||
}
|
88
plugins/jwt/jwt_test.go
Normal file
88
plugins/jwt/jwt_test.go
Normal file
@ -0,0 +1,88 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testRequest(method, path string) (*httptest.ResponseRecorder, *http.Request) {
|
||||
request, _ := http.NewRequest(method, path, nil)
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
return recorder, request
|
||||
}
|
||||
|
||||
func Test_IssueTokenAction(t *testing.T) {
|
||||
url := "/v1/jwt/issue-token"
|
||||
|
||||
mux := beego.NewControllerRegister()
|
||||
|
||||
mux.InsertFilter("*", beego.BeforeRouter, AuthRequest(&Options{
|
||||
PrivateKeyPath: "test/jwt.rsa",
|
||||
PublicKeyPath: "test/jwt.rsa.pub",
|
||||
WhiteList: []string{"/v1/jwt/issue-token", "/docs"},
|
||||
}))
|
||||
|
||||
mux.Add("/v1/jwt/issue-token", &JwtController{}, "get:IssueToken")
|
||||
|
||||
rw, r := testRequest("GET", url)
|
||||
mux.ServeHTTP(rw, r)
|
||||
|
||||
if rw.Code != http.StatusOK {
|
||||
t.Errorf("Shoud return 200")
|
||||
}
|
||||
}
|
||||
|
||||
func (tc *JwtController) Foo() {
|
||||
tc.Ctx.Output.Body([]byte("ok"))
|
||||
}
|
||||
|
||||
func Test_AuthRequestWithAuthorizationHeader(t *testing.T) {
|
||||
|
||||
url := "/foo"
|
||||
|
||||
mux := beego.NewControllerRegister()
|
||||
|
||||
mux.InsertFilter("*", beego.BeforeRouter, AuthRequest(&Options{
|
||||
PrivateKeyPath: "test/jwt.rsa",
|
||||
PublicKeyPath: "test/jwt.rsa.pub",
|
||||
WhiteList: []string{"/v1/jwt/issue-token", "/docs"},
|
||||
}))
|
||||
|
||||
mux.Add("/foo", &JwtController{}, "get:Foo")
|
||||
newToken := CreateToken()
|
||||
|
||||
rw, r := testRequest("GET", url)
|
||||
r.Header.Add("Authorization", "Bearer "+newToken["token"])
|
||||
mux.ServeHTTP(rw, r)
|
||||
|
||||
if rw.Code != http.StatusOK {
|
||||
t.Errorf("Shoud return 200")
|
||||
}
|
||||
if rw.Body.String() != "ok" {
|
||||
t.Errorf("Should output ok")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_AuthRequestWithoutAuthorizationHeader(t *testing.T) {
|
||||
url := "/foo"
|
||||
|
||||
mux := beego.NewControllerRegister()
|
||||
|
||||
mux.InsertFilter("*", beego.BeforeRouter, AuthRequest(&Options{
|
||||
PrivateKeyPath: "test/jwt.rsa",
|
||||
PublicKeyPath: "test/jwt.rsa.pub",
|
||||
WhiteList: []string{"/v1/jwt/issue-token", "/docs"},
|
||||
}))
|
||||
|
||||
mux.Add("/foo", &JwtController{}, "get:Foo")
|
||||
|
||||
rw, r := testRequest("GET", url)
|
||||
mux.ServeHTTP(rw, r)
|
||||
|
||||
if rw.Code != http.StatusUnauthorized {
|
||||
t.Errorf("Shoud return 401")
|
||||
}
|
||||
}
|
15
plugins/jwt/test/jwt.rsa
Normal file
15
plugins/jwt/test/jwt.rsa
Normal file
@ -0,0 +1,15 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICWwIBAAKBgQCdu+23Y/0J/FTQKnIPnxupoOo9/OYCv90DPXN/KLLRAMjYzgcC
|
||||
DsBST2xVR5jlimI/gyfCpVB62dwpSzzr0cA3MoDhbaGWuTdQUX9zmiLoQ4I7X6h0
|
||||
dwyiihOz+CzOMlAg5+qBhiTGcKvIFlfEc1FUcn/tB3PVRG9j6B1Ibz5CnQIDAQAB
|
||||
AoGAFGg+/i4ai9MwqeoD7c95Bb5C8BgrLgnir0uhCL+cOvwuABbPw01jRoLuEi58
|
||||
Mp5vzaXLXByFSA+ts03/qMbvZkDGac5g5kLli5TjHIONMxVBrdfGQ1+OApnaPayN
|
||||
N+HYjZKs6xao6J5iFqfA0FqzDR9kQhUoeosdQoo1GlxDckECQQDO/0LJrFiLzYWe
|
||||
qS/DxfAnFu2BlClKZjxRJ3vIkRRaON6HPl8BeJW901bFKG5+WSfO+OwQ9egWaf3X
|
||||
fFm/oEHRAkEAwxMor4fOkBZbL4KPW7sen169vwnXuYusqj0t3dIeiIVrCigkOMT4
|
||||
OvX/63u4CTdXh1D5u/4Z/1HTYH92VCP7DQJAJPxbNKnE0IYSf/z++d4eQP3JxkNw
|
||||
9Ug7Msz5QycZGd3bdRLh6uNe7iIa+PN2esD3afX0SDuIEqkxoBUp/CFoYQJAUmi3
|
||||
mV+/7bLkFrALK+9iwmTdt+TKk4HkEY8C32CysW3biFDo7GqZix79XFfJqWsNuQaG
|
||||
WdrA1NGWgH+YV3dTyQJAIWEZGAuUXRkQB20LfjGzpsKgQFbqjTisMS0qe3JjnDwu
|
||||
0JR8sYXapgeEEEisH+OtkZKIfyeFOwoUyNC83bcvgw==
|
||||
-----END RSA PRIVATE KEY-----
|
6
plugins/jwt/test/jwt.rsa.pub
Normal file
6
plugins/jwt/test/jwt.rsa.pub
Normal file
@ -0,0 +1,6 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCdu+23Y/0J/FTQKnIPnxupoOo9
|
||||
/OYCv90DPXN/KLLRAMjYzgcCDsBST2xVR5jlimI/gyfCpVB62dwpSzzr0cA3MoDh
|
||||
baGWuTdQUX9zmiLoQ4I7X6h0dwyiihOz+CzOMlAg5+qBhiTGcKvIFlfEc1FUcn/t
|
||||
B3PVRG9j6B1Ibz5CnQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
Loading…
Reference in New Issue
Block a user