本文介紹go micro中的api訪問權限控制,這裏僅僅介紹內部服務間的互相調用鑑權(jwt),不是針對用戶系統的細緻rbac模式。git
目標:github
有2種方式web
先建立一個myauth的服務,對外提供2個接口數據庫
業務調用步驟json
首先建立一個api項目segmentfault
micro new --type=api myauth
api
GetJwt()、InspectJwt()
相關代碼網絡
// Myauth.Call is called by the API as /myauth/call with post body {"name": "foo"} func (e *Myauth) GetJwt(ctx context.Context, req *api.Request, rsp *api.Response) error { log.Info("Received Myauth.GetJwt request") getmap := req.GetGet() log.Info("Received getmap %+v\n", getmap) postmap := req.GetPost() log.Info("Received postmap %+v\n", postmap) // 內部服務調用底層service,經過jwt驗證 // 定義服務名和key,經過這2個參數獲取jwt access token // serviceName := "order" // serviceKey := "123456" // 對比serviceName\serviceKey 也能夠是用戶名密碼等,這裏的示例爲了方便硬編碼在代碼中 // 實際項目中應該從數據庫或文件讀取 serviceName := extractValue(postmap["service"]) serviceKey := extractValue(postmap["key"]) log.Info("serviceName %+v\n", serviceName, serviceKey) if serviceName != "order" || serviceKey != "123456" { Rsp(rsp, 403, "服務名稱或key錯誤", nil) return nil } //生成jwt // expireTime := time.Now().Add(time.Hour * 24 * 3).Unix() expireTime := time.Now().Add(time.Second * 60 * 60).Unix() token := &token.Token{} token.Init([]byte("key123456")) //實際項目需從數據庫或文件讀取 jwtstring, err := token.Encode("auth jwt", serviceName, expireTime) if err != nil { Rsp(rsp, 403, "jwt 生成錯誤", nil) return nil } msg := make(map[string]interface{}) msg["jwt"] = jwtstring Rsp(rsp, 200, "ok", msg) return nil } // 驗證jwt func (e *Myauth) InspectJwt(ctx context.Context, req *api.Request, rsp *api.Response) error { log.Info("Received Myauth.InspectJwt request") // getmap := req.GetGet() // log.Info("Received getmap %+v\n", getmap) postmap := req.GetPost() // log.Info("Received postmap %+v\n", postmap) jwtString := extractValue(postmap["jwt"]) log.Info("jwtString %+v\n", jwtString) if len(jwtString) == 0 { Rsp(rsp, 403, "jwt參數錯誤", nil) return nil } //解析jwt token := &token.Token{} token.Init([]byte("key123456")) info, err := token.Decode(jwtString) if err != nil { Rsp(rsp, 403, "jwt 解析錯誤", nil) //過時或jwt有問題 return nil } t := make(map[string]interface{}) t["data"] = info Rsp(rsp, 200, "ok", t) return nil } // 返回func func Rsp(rsp *api.Response, code int, err string, msg map[string]interface{}) error { if msg == nil { msg = make(map[string]interface{}) } r := &rspMsg{ Code: code, Err: err, Msg: msg, } b, err2 := json.Marshal(r) if err2 != nil { log.Info("json.Marshal err", err2) } rsp.StatusCode = int32(code) rsp.Body = string(b) return nil }
自定義micro網關代碼app
package main import ( "net/http" "myauth/lib/token" log "github.com/micro/go-micro/v2/logger" "github.com/micro/micro/v2/cmd" "github.com/micro/micro/v2/plugin" ) func main() { tk := &token.Token{} tk.Init([]byte("key123456")) plugin.Register(plugin.NewPlugin( plugin.WithName("auth"), plugin.WithHandler( JWTAuthWrapper(tk), ), )) cmd.Init() } func JWTAuthWrapper(t *token.Token) plugin.Handler { return func(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { log.Info("===========", r.URL.Path) //不須要登陸的url地址 strings.HasPrefix(r.URL.Path, "/hello") || if r.URL.Path == "/myauth/Myauth/GetJwt" || r.URL.Path == "/myauth/Myauth/InspectJwt" { h.ServeHTTP(w, r) return } // tokenstr := r.Header.Get("Authorization")//如今不能夠用Authorization,須要用Bearer tokenstr := r.Header.Get("Bearer") log.Info("tokenstr", tokenstr) userFromToken, e := t.Decode(tokenstr) log.Info("userFromToken", userFromToken) if e != nil { _, _ = w.Write([]byte("unauthorized")) return } // r.Header.Set("X-Example-Username", userFromToken.UserName) h.ServeHTTP(w, r) return }) } }
示例代碼見https://github.com/wulinlw/mi...函數
參考
go-micro網關鑑權之jwt
https://www.jianshu.com/p/426...
【go語言微服務實踐】#5-go-micro實現JWT認證
https://juejin.im/post/5e6123...
https://github.com/Allenxuxu/...
go micro 分析系列文章
go micro server 啓動分析
go micro client
go micro broker
go micro cmd
go micro config
go micro store
go micro registry
go micro router
go micro runtime
go micro transport
go micro web
go micro registry 插件consul
go micro plugin
go micro jwt 網關鑑權
go micro 鏈路追蹤
go micro 熔斷與限流
go micro wrapper 中間件
go micro metrics 接入Prometheus、Grafana