micro統(tǒng)一認證 Token

micro 使用 jwt 做統(tǒng)一的token 驗證冰抢,看代碼就好了

package token_jwt

import (
    "encoding/json"
    "errors"
    "github.com/dgrijalva/jwt-go"
    "github.com/micro/cli"
    "github.com/micro/go-micro/config"
    "github.com/micro/go-micro/config/source/etcd"
    "github.com/micro/go-micro/v2/logger"
    "github.com/micro/micro/plugin"
    "net/http"
    "strings"
)

var (
    TokenExpired     = errors.New("Token is expired")
    TokenNotValidYet = errors.New("Token not active yet")
    TokenMalformed   = errors.New("That's not even a token")
    TokenInvalid     = errors.New("Couldn't handle this token:")
)

type Token struct {
    Name       string
    PrivateKey []byte
    conf config.Config
    UnAuthPath []string
}

type JwtPayloadInfo struct {
    UserName string
    UUID        string
    ID          uint
    NickName    string
    AuthorityId string
    jwt.StandardClaims
}

//定義一些參數,可以通過啟動micro 的時候傳參
func (l *Token) Flags() []cli.Flag {
    return []cli.Flag{cli.StringFlag{
        Name:   "token_path",
        Usage:  "token私鑰在etcd中的路徑",
        EnvVar: "TOKEN_PATH",
    }}
}
func (l *Token) Commands() []cli.Command {
    return nil
}

//處理程序 會在每次請求的時候調用
func (l *Token) Handler() plugin.Handler {
    return func(handler http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            //處理token 的邏輯
            if  Contains(l.UnAuthPath,r.URL.Path)!=-1  {
                logger.Info("allow pass url :",r.URL.Path)
                handler.ServeHTTP(w, r)
                return
            }
            authStr := r.Header.Get("Authorization")
            logger.Infof("authStr:%s",authStr)
            payload, err := l.Decode(authStr)
            if err != nil {
                logger.Info("auth fail:",err)
                w.WriteHeader(http.StatusUnauthorized)
                return
            }
            bs,_:=json.Marshal(payload)
            logger.Infof("payload info= %s", string(bs))
            r.Header.Add("claims",string(bs))
            handler.ServeHTTP(w, r)
            return
        })
    }
}

//初始化數據,程序啟動的時候會調用這個方法炸站,可以在這里初始化一些參數
func (l *Token) Init(ctx *cli.Context) error {
    //從配置加載 公鑰
    //加載公鑰蔚万,放行鏈接等,存放到實例里面
    address:=ctx.String("registry_address")
    token_path:=ctx.String("token_path")
    source := etcd.NewSource(
        etcd.WithAddress(address),
        )

    l.conf=config.NewConfig()
    err:=l.conf.Load(source)
    if err!=nil {
        logger.Fatal(err)
    }
    value:=l.conf.Get(strings.Split(token_path,"/")...).Bytes()
    logger.Debug(l.conf.Map())
    if err!=nil {
        logger.Fatal(err)
    }
    l.PrivateKey=value

    logger.Info("JWT privateKey:", string(value))

    //初始化放行地址
    l.UnAuthPath=make([]string,0)
    l.UnAuthPath=append(l.UnAuthPath,"/admin/base/login")

    l.enableAutoUpdate(strings.Split(token_path,"/")...)
    return nil
}

//配置更新的方法
func (l *Token) enableAutoUpdate(path ...string) {
    go func() {
        for {
            w, err := l.conf.Watch(path...)
            if err != nil {
                logger.Error(err)
            }
            v, err := w.Next()
            if err != nil {
                logger.Error(err)
            }

            value := v.Bytes()
            l.PrivateKey=value

            logger.Info("New JWT privateKey:", string(l.PrivateKey))
        }
    }()
}


func (l *Token) String() string {
    return l.Name
}

//調用這個方法 new 插件,也可以在啟動的時候這樣子寫
func NewPlugin() plugin.Plugin {
    return &Token{
        Name: "token-jwt",
    }
}

//Decode 解碼
func (l *Token) Decode(tokenStr string) (*JwtPayloadInfo, error) {
    token, err := jwt.ParseWithClaims(tokenStr, &JwtPayloadInfo{}, func(token *jwt.Token) (i interface{}, e error) {
        return l.PrivateKey, nil
    })
    if err != nil {
        if ve, ok := err.(*jwt.ValidationError); ok {
            if ve.Errors&jwt.ValidationErrorMalformed != 0 {
                return nil, TokenMalformed
            } else if ve.Errors&jwt.ValidationErrorExpired != 0 {
                // Token is expired
                return nil, TokenExpired
            } else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
                return nil, TokenNotValidYet
            } else {
                return nil, TokenInvalid
            }
        }
    }
    if token != nil {
        if claims, ok := token.Claims.(*JwtPayloadInfo); ok && token.Valid {
            return claims, nil
        }
        return nil, TokenInvalid

    } else {
        return nil, TokenInvalid

    }
}

// Encode 將 User 用戶信息加密為 JWT 字符串
// expireTime := time.Now().Add(time.Hour * 24 * 3).Unix() 三天后過期
func (l *Token) CreateToken(claims JwtPayloadInfo) (string, error) {
    logger.Infof("encode token info :%v",claims)
    jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    return jwtToken.SignedString(l.PrivateKey)
}

//判斷數組包含
func Contains(array []string, val string) (index int) {
    index = -1
    for i,v:=range array  {
        if v==val{
            index=i
            return
        }
    }
    return
}


?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市涧狮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌么夫,老刑警劉巖者冤,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異档痪,居然都是意外死亡涉枫,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進店門腐螟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拜银,“玉大人,你說我怎么就攤上這事遭垛∧嵬埃” “怎么了?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵锯仪,是天一觀的道長泵督。 經常有香客問我,道長庶喜,這世上最難降的妖魔是什么小腊? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮久窟,結果婚禮上秩冈,老公的妹妹穿的比我還像新娘。我一直安慰自己斥扛,他們只是感情好入问,可當我...
    茶點故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著稀颁,像睡著了一般芬失。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上匾灶,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天棱烂,我揣著相機與錄音,去河邊找鬼阶女。 笑死颊糜,一個胖子當著我的面吹牛哩治,可吹牛的內容都是我干的。 我是一名探鬼主播衬鱼,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼锚扎,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了馁启?” 一聲冷哼從身側響起驾孔,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎惯疙,沒想到半個月后翠勉,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡霉颠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年对碌,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蒿偎。...
    茶點故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡朽们,死狀恐怖,靈堂內的尸體忽然破棺而出诉位,到底是詐尸還是另有隱情骑脱,我是刑警寧澤,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布苍糠,位于F島的核電站叁丧,受9級特大地震影響,放射性物質發(fā)生泄漏岳瞭。R本人自食惡果不足惜拥娄,卻給世界環(huán)境...
    茶點故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瞳筏。 院中可真熱鬧稚瘾,春花似錦、人聲如沸姚炕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽钻心。三九已至凄硼,卻和暖如春铅协,著一層夾襖步出監(jiān)牢的瞬間捷沸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工狐史, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留痒给,地道東北人说墨。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像苍柏,于是被迫代替她去往敵國和親尼斧。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,455評論 2 359