这篇文章中的 plugin 次要讲https://github.com/micro/micro 中的插件,次要用于自定义网关中如何加载插件。(如文章[micro auth jwt])
go-micro中的插件请见https://github.com/micro/go-p…
官网README中有一些介绍
https://github.com/micro/micr…
官网示例:
在我的项目目录创立plugin.go
package main
import (
"log"
"github.com/micro/cli/v2"
"github.com/micro/micro/v2/plugin"
)
func init() {
plugin.Register(plugin.NewPlugin(
plugin.WithName("example"),
plugin.WithFlag(cli.StringFlag{
Name: "example_flag",
Usage: "This is an example plugin flag",
EnvVars: []string{"EXAMPLE_FLAG"},
Value: "avalue",
}),
plugin.WithInit(func(ctx *cli.Context) error {
log.Println("Got value for example_flag", ctx.String("example_flag"))
return nil
}),
))
}
最初编译
`go build -o micro ./main.go ./plugin.go`
一步步看看是怎么注册的,在micro/plugin/manager.go中
type manager struct {
sync.Mutex
plugins []Plugin
registered map[string]bool
}
var (
// global plugin manager
defaultManager = newManager()
)
func newManager() *manager {
return &manager{
registered: make(map[string]bool),
}
}
plugin包有默认`defaultManager = newManager()`,是一个manager{}对象
再来看plugin.NewPlugin()
// NewPlugin makes it easy to create a new plugin
func NewPlugin(opts ...Option) Plugin {
return newPlugin(opts...)
}
func newPlugin(opts ...Option) Plugin {
options := Options{
Name: "default",
Init: func(ctx *cli.Context) error { return nil },
}
for _, o := range opts {
o(&options)
}
handler := func(hdlr http.Handler) http.Handler {
for _, h := range options.Handlers {
hdlr = h(hdlr)
}
return hdlr
}
return &plugin{
opts: options,
handler: handler,
}
}
做了以下事件:
- 初始化并设置options
-
定义handler办法
- 顺次调用options.Handlers
-
初始化并返回plugin{}
- 初始化plugin.handler时,调用了第2步的handler办法,顺次调用了注册的handler,(注册插件时传入的
plugin.WithHandler()
,例子放在最初)
- 初始化plugin.handler时,调用了第2步的handler办法,顺次调用了注册的handler,(注册插件时传入的
最初是外层的plugin.Register()
// Register registers a global plugins
func Register(plugin Plugin) error {
return defaultManager.Register(plugin)
}
func (m *manager) Register(plugin Plugin) error {
m.Lock()
defer m.Unlock()
name := plugin.String()
if m.registered[name] {
return fmt.Errorf("Plugin with name %s already registered", name)
}
m.registered[name] = true
m.plugins = append(m.plugins, plugin)
return nil
}
做了以下事件:
- 获取插件名称,判断是否已注册
- manager.plugins中增加以后plugin
到这里插件的注册就实现了,那什么是被调用的,怎么失效的呢?
接下来看cmd.Init()
// Init initialised the command line
func Init(options ...micro.Option) {
Setup(cmd.App(), options...)
cmd.Init(
cmd.Name(name),
cmd.Description(description),
cmd.Version(buildVersion()),
)
}
func setup(app *ccli.App) {
//无关内容略...
plugins := plugin.Plugins()
for _, p := range plugins {
if flags := p.Flags(); len(flags) > 0 {
app.Flags = append(app.Flags, flags...)
}
if cmds := p.Commands(); len(cmds) > 0 {
app.Commands = append(app.Commands, cmds...)
}
}
before := app.Before
app.Before = func(ctx *ccli.Context) error {
//无关内容略...
for _, p := range plugins {
if err := p.Init(ctx); err != nil {
return err
}
}
//无关内容略...
}
}
做了以下事件:
- 获取插件列表,收集所有参数
- 顺次调用所有插件的
Init()
办法
上面是一个有plugin.WithHandler()
的插件例子
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
})
}
}
这个例子是一个自定义micro网关,拦挡申请查看header中的jwt token信息
总结
- 本篇介绍的是 micro 的插件应用及外部流程,次要用于自定义网关。不要和 go-micro 插件搞混同了。
- micro/plugin/build下内容是对于build和load插件.so的,不太欠缺这里就不深入研究了。
发表回复