美文网首页
etcd+jwt实现鉴权

etcd+jwt实现鉴权

作者: 鬼厉 | 来源:发表于2020-06-02 16:11 被阅读0次

    本文基于搭建好etcd集群,若为搭建请移步:https://www.jianshu.com/p/ec0e4911236d
    etcd我们使用其存储key/value的功能,存储jwt的私有key,也可以通过etcd来更新key。

    设计思路:

    内部服务通过go-micro api相互访问时,为了保证访问的安全,防止来自外部的攻击,我们在服务间通过token来识别。
    各服务在请求对方是在header中加入token,token使用jwt生成,jwt 的私有key来自etcd。

    为什么这么做

    我们使用go-micro api 作为网关 ,使用etcd作为服务发现,此时访问各服务的出入口在go-micro api,其对外的地址和端口是固定的,若我们不做防护,来自外部的访问,就可以直接访问到我们内部的服务,很不安全。

    为什么使用etcd来存储私有key

    这样做是为了,使用相同的私有key,不用每个服务都设置一遍,而且可以实现热更新key,当私有key存在泄漏风险时,通过etcdctl指令更新key即可,无需部署发布。

    ok,下面我们说如何在etcd中存储数据,以及如何使用golang代码访问etcd获取数据
    当搭建完etcd后,使用一下指令进入其中一个etcd,因为我们搭建的etcd是集群,所以任意一个修改,都是生效的。
    使用如下指令进入etcd

    docker exec -it 7ffad5617908 /bin/bash
    如果不可用改为:
    docker exec -it 7ffad5617908 /bin/sh
    

    指定 Etcd API 的版本,默认是 2。指定版本是为了想要在任意位置访问到 etcd 和 etcdctl,如果不设置,代码是无法获取到值的。

    执行指令:
    export ETCDCTL_API=3
    

    查看版本

    etcdctl version
    

    可看到如下输出


    图片.png

    然后,设置jwt的key

    etcdctl put jwtkey 123456
    

    说明:

    etcdctl :是etcd指令标识
    put:标识新增或更新值
    jwtkey:是值名称
    123456:是值
    

    至此,etcd就设置好了,开始写golang代码获取etcd中jwtkey的值

    package myetcd
    
    import (
        "context"
            "fmt"
        "github.com/coreos/etcd/clientv3"
    )
    //etcdAddr 是etcd地址(如:192.168.109.131:12379,12379是etcd容器开放对外的端口)
    //key ,传jwtkey即可
    func GetKey(etcdAddr string,key string)(value string){
        cli, err := clientv3.New(clientv3.Config{
            Endpoints:   []string{etcdAddr},
        })
        if err != nil {
            fmt.Println("connect etcd failed, err:%s", err.Error())
            return
        }
    
        mylog.Info("connect etcd success")
        defer cli.Close()
        kv := clientv3.NewKV(cli)
    
        resp, err := kv.Get(context.TODO(), key)
        if err != nil {
            fmt.Println("get etcd key failed, key:%s, err:%s", key, err.Error())
            return
        }
        for _, ev := range resp.Kvs {
            value = string(ev.Value)
        }
        return
    }
    

    至此就可以获取到jwtkey了,
    下面使用jwt生成token

    package token
    
    import (
        jwt "github.com/dgrijalva/jwt-go"
        "github.com/kukayyou/commonlib/myetcd"
        "sync"
        "time"
    )
    
    // CustomClaims 自定义的 metadata在加密后作为 JWT 的第二部分返回给客户端
    type ServerClaims struct {
        Server string `json:"server"`
        jwt.StandardClaims
    }
    
    // Token jwt服务
    var (
        rwlock     sync.RWMutex
        PrivateKey string = "orangetutor"
    )
    
    //获取私钥
    func get() []byte {
        rwlock.RLock()
        defer rwlock.RUnlock()
    
        return []byte(PrivateKey)
    }
    
    //设置私钥
    func put(newKey string) {
        rwlock.Lock()
        defer rwlock.Unlock()
    
        PrivateKey = newKey
    }
    
    //检测jwt私钥是否改变
    func Init(opt string) {
        go func() {
            for {
                key := myetcd.GetKey(opt, "jwtkey")//获取etcd中的jwtkey
                put(key)
                time.Sleep(time.Second * 10)
            }
        }()
    }
    
    //创建token,server是服务名,这里也可以不使用这个字段
    //expireTime 是token过期时间
    func CreateServerToken(server string, expireTime int64) (string, error) {
        claims := ServerClaims{
            server,
            jwt.StandardClaims{
                Issuer:    ISSUSER,
                IssuedAt:  time.Now().Unix(),
                ExpiresAt: expireTime,
            },
        }
    
        jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
        return jwtToken.SignedString(get())
    }
    
    //检验token
    func CheckServerToken(tokenStr string) (*ServerClaims, error) {
        t, err := jwt.ParseWithClaims(tokenStr, &ServerClaims{}, func(token *jwt.Token) (interface{}, error) {
            return get(), nil
        })
    
        if err != nil {
            return nil, err
        }
        // 解密转换类型并返回
        if claims, ok := t.Claims.(*ServerClaims); ok && t.Valid {
            return claims, nil
        }
    
        return nil, err
    }
    
    

    ok,全部搞定

    相关文章

      网友评论

          本文标题:etcd+jwt实现鉴权

          本文链接:https://www.haomeiwen.com/subject/jtxszhtx.html