教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 JWT Token认证

JWT Token认证

发布时间:2022-01-10   编辑:jiaochengji.com
教程集为您提供JWT Token认证等资源,欢迎您收藏本站,我们将为您提供最新的JWT Token认证资源
<h2>什么是JWT?</h2>

JWT是JSON Web Token的缩写,定义了一种简介自暴寒的方法用于通信双方之间以Json对象的形式安全的传递信息。因为特定的数字签名,所以这些通信的信息能够被校验和信任。 JWT可以使用HMAC算法或者RSA的公钥私钥对进行签名。

让我们进一步的解释下关于JWT的定义:

<ul><li>简约(Compact): JWT通信中使用的数据量比较小,JWT可以通过URL、POST参数,或者直接在HTTP header进行传递。 并且,因为比较小的数据量,这也意味着传输速度会更加快速。</li> <li>自包含(Self-contained): 负载(payload)中(可以)包含所需的所有用户部分的信息,可以避免对服务端数据库的多次查询。</li> </ul><h2>JWT组成</h2>

JWT由三部分组成,使用<code>.</code>分隔:

<ul><li>头部(Header)</li> <li>载荷(Payload)</li> <li>签名(Signature)</li> </ul>

所以,JWT最终样式为:<code>XXXXX.XXXXX.XXXXX</code>

<h3>Header</h3>

JWT的头部包含描述该JWT的最基本的信息:token的类型, 如JWT, 以及token使用的加密算法, 如 HMAC SHA256或者RSA.。可以被表示为一个JSON对象:

<pre><code class="json">{ "typ": "JWT", "alg": "HS256" }</code></pre> <h3>Payload</h3>

JWT token的第二部分是payload, Payload包含claims. Claims是一些实体(通常指用户)的状态信息和其他元数据。

<pre><code class="json">{ "iss": "sysu", "iat": 1233458243, "exp": 1448333419, "aud": "sysu-ss", "sub": "sysu-ss", }</code></pre>

iss(issuer 签发者),是否使用是可选的;
iat(issued at签发时间),这里是一个Unix时间戳,是否使用是可选的;
exp(expiration time 过期时间) ,这里是一个Unix时间戳,是否使用是可选的;
aud(audience 接收方 ),是否使用是可选的;
sub(subject 面向的用户),是否使用是可选的;

关于更多有关Payload字段的介绍,请查看JWT官网

<h3>Signature</h3>

要创建签名部分,需要使用经过编码后的头部(header)和负载(payload)以及一个密钥,将header和payload用<code>.</code>连接起来后,使用header中制定的算法进行签名。
该签名是用户验证JWT的请求发送者以及确保数据信息在传输过程中的消息是未经篡改的。

<h2>JWT使用(golang)</h2>

我使用的是jwt-go、negroni web中间件以及mux搭建服务。关于这三个库的使用请自行谷歌。

<ul><li>首先定义自己的Token:</li></ul><pre><code class="go">// service/jwt.go var tokens []Token // 作为全局变量存储登录用户的token,可以存储到数据库中 const TokenName = "SW-TOKEN" const Issuer = "Go-GraphQL-Group" const SecretKey = "StarWars" type Token struct { SW_TOKEN string `json:"SW-TOKEN"` } type jwtCustomClaims struct { jwt.StandardClaims Admin bool `json:"admin"` } func CreateToken(secretKey []byte, issuer string, isAdmin bool) (token Token, err error) { claims := &jwtCustomClaims{ jwt.StandardClaims{ ExpiresAt: int64(time.Now().Add(time.Hour * 1).Unix()), Issuer: issuer, }, isAdmin, } tokenStr, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString(secretKey) token = Token{ tokenStr, } return } func ParseToken(tokenStr string, secretKey []byte) (claims jwt.Claims, err error) { var token *jwt.Token token, err = jwt.Parse(tokenStr, func(*jwt.Token) (interface{}, error) { return secretKey, nil }) claims = token.Claims return }</code></pre> <ul><li>之后生成服务并注册路由:</li></ul><pre><code class="go">// main.go func NewServer() *negroni.Negroni { router := mux.NewRouter() initRoutes(router) n := negroni.Classic() // negroni.Classic() 返回带有默认中间件的Negroni实例指针 n.UseHandler(router) // 将router中http.Handler加入到negroni的中间件栈中 return n } func initRoutes(router *mux.Router) { router.HandleFunc("/login", service.LoginHandler).Methods("POST") // 使用中间件进行token认证 router.Use(service.TokenMiddleware) // query服务 router.HandleFunc("/query", handler.GraphQL(GraphQL_Service.NewExecutableSchema(GraphQL_Service.Config{Resolvers: &GraphQL_Service.Resolver{}}))) // 退出路由 router.HandleFunc("/logout", service.LogoutHandler).Methods("POST", "GET") }</code></pre> <ul><li>login路由处理函数签发Token:</li></ul><pre><code class="go">func LoginHandler(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() fmt.Println(r.Form.Get("username")) if err != nil { w.WriteHeader(http.StatusForbidden) fmt.Fprint(w, "Error in request") return } // 使用固定的username和password做测试 if strings.ToLower(r.Form.Get("username")) != "admin" || r.Form.Get("password") != "password" { w.WriteHeader(http.StatusForbidden) fmt.Println("Error logging in") fmt.Fprint(w, "Invalid credentials") return } token, err := CreateToken([]byte(SecretKey), Issuer, false) if err != nil { w.WriteHeader(http.StatusInternalServerError) fmt.Fprintln(w, "Error extracting the key") log.Fatal(err) } w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "application/json") tokenBytes, err := json.Marshal(token) if err != nil { w.WriteHeader(http.StatusInternalServerError) fmt.Fprintln(w, "Error marshal the token") log.Fatal(err) } tokens = append(tokens, token) w.Write(tokenBytes) }</code></pre> <ul><li>中间件定义如下:</li></ul><pre><code class="go">func TokenMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // 不是login的请求需要进行token认证 if r.RequestURI[1:] != "login" { /* // token位于Authorization中,用此方法 token, err := request.ParseFromRequest(r, request.AuthorizationHeaderExtractor, func(token *jwt.Token) (interface{}, error) { return []byte(SecretKey), nil }) */ tokenStr := "" for k, v := range r.Header { if strings.ToUpper(k) == TokenName { tokenStr = v[0] break } } validToken := false for _, token := range tokens { if token.SW_TOKEN == tokenStr { validToken = true } } if validToken { ctx := context.WithValue(r.Context(), TokenName, tokenStr) next.ServeHTTP(w, r.WithContext(ctx)) } else { w.WriteHeader(http.StatusUnauthorized) w.Write([]byte("Unauthorized access to this resource")) //fmt.Fprint(w, "Unauthorized access to this resource") } } else { next.ServeHTTP(w, r) } }) }</code></pre> <ul><li>logout路由处理函数(删除token):</li></ul><pre><code class="go">func LogoutHandler(w http.ResponseWriter, r *http.Request) { tokenStr := "" for k, v := range r.Header { if strings.ToUpper(k) == TokenName { tokenStr = v[0] break } } for i, token := range tokens { if token.SW_TOKEN == tokenStr { tokens = append(tokens[:i], tokens[i 1:]...) break } } w.Write([]byte("logout")) }</code></pre> <ul><li>启动服务</li></ul><pre><code class="go">// main.go func main() { port := os.Getenv("PORT") if port == "" { port = defaultPort } server := NewServer() server.Run(":" port) log.Printf("connect to http://localhost:%s/ for GraphQL playground", port) }</code></pre> <ul><li>测试服务</li></ul><ol><li>未登录,query</li></ol>

<span class="img-wrap"></span>

<ol><li>登录login</li></ol>

<span class="img-wrap"></span>

<ol><li>query</li></ol>

<span class="img-wrap"></span>

<ol><li>登出logout</li></ol>

<span class="img-wrap"></span>

<ol><li>query</li></ol>

<span class="img-wrap"></span>

代码源地址:Github

到此这篇关于“JWT Token认证”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
Golang 实现JWT认证
JWT 在 Gin 中的使用
JWT Token认证
JWT实现用户认证原理与实现(golang)
Flask如何实现HTTP令牌token认证
nsqd解析:nsqd-channel
php的token怎么生成的
Golang map 三板斧第二式:注意事项
golang sync.Mutex互斥锁的实现原理
Go 方法接收器与接口

[关闭]
~ ~