您的位置 首页 golang

etcd+jwt实现鉴权

本文基于搭建好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 myetcdimport (    "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 tokenimport (    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())}//检验tokenfunc 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.zhihuclub.com/2790.shtml

关于作者: 智云科技

热门文章

网站地图