本文介绍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