zoukankan      html  css  js  c++  java
  • Go语言入门篇-jwt(json web token)权限验证

    一。token、cookie、session的区别

    1。cookie

    Cookie总是保存在客户端中,按在客户端中的存储位置,可分为内存Cookie和硬盘Cookie。
    
    内存Cookie由浏览器维护,保存在内存中,浏览器关闭后就消失了,其存在时间是短暂的。

    硬盘Cookie保存在硬盘里,有一个过期时间,除非用户手工清理或到了过期时间,硬盘Cookie不会被删除,其存在时间是长期的。

    所以,按存在时间,可分为非持久Cookie和持久Cookie。 cookie 是一个非常具体的东西,指的就是浏览器里面能永久存储的一种数据,仅仅是浏览器实现的一种数据存储功能。 cookie由服务器生成,发送给浏览器,浏览器把cookie以key
    -value形式保存到某个目录下的文本文件内,下一次请求同一网站时会把该cookie发送给服务器。

    由于cookie是存在客户端上的,所以浏览器加入了一些限制确保cookie不会被恶意使用,同时不会占据太多磁盘空间,所以每个域的cookie数量是有限的。

    2。session

    session 从字面上讲,就是会话。这个就类似于你和一个人交谈,你怎么知道当前和你交谈的是张三而不是李四呢?对方肯定有某种特征(长相等)表明他就是张三。
    
    session 也是类似的道理,服务器要知道当前发请求给自己的是谁。为了做这种区分,服务器就要给每个客户端分配不同的“身份标识”,

    然后客户端每次向服务器发请求的时候,都带上这个“身份标识”,服务器就知道这个请求来自于谁了。至于客户端怎么保存这个“身份标识”,

    可以有很多种方式,对于浏览器客户端,大家都默认采用 cookie 的方式。 服务器使用session把用户的信息临时保存在了服务器上,用户离开网站后session会被销毁。这种用户信息存储方式相对cookie来说更安全,

    可是session有一个缺陷:如果web服务器做了负载均衡,那么下一个操作请求到了另一台服务器的时候session会丢失。

    3。token

    token的意思是“令牌”,是用户身份的验证方式.

    最简单的token组成:

    【1】uid(用户唯一的身份标识)
    【2】time(当前时间的时间戳)
    【3】sign(签名,由token的前几位+盐以哈希算法压缩成一定长的十六进制字符串,
    可以防止恶意第三方拼接token请求服务器)。还可以把不变的参数也放进token,避免多次查库 这里的token是指SON Web Token

    用户注册之后, 服务器生成一个 JWT token返回给浏览器, 浏览器向服务器请求数据时将 JWT token 发给服务器,

    服务器用 signature 中定义的方式解码 

    WT 获取用户信息.

    一个 JWT token包含3部分: 
    【1】header: 告诉我们使用的算法和 token 类型 
    【2】Payload: 必须使用 sub key 来指定用户 ID, 还可以包括其他信息比如 email, username 等. 
    【3】Signature: 用来保证 JWT 的真实性. 可以使用不同算法 

    二。jwt(json web token)权限验证

    完整代码:

      1 package main
      2 
      3 import (
      4     "log"
      5     "net/http"
      6     "github.com/codegangsta/negroni"
      7     "encoding/json"
      8     "fmt"
      9     "strings"
     10     "github.com/dgrijalva/jwt-go"
     11     "time"
     12     "github.com/dgrijalva/jwt-go/request"
     13 )
     14 
     15 /**
     16 说明:
     17 客户端通过在request对象header里添加token参数,发送到服务端。
     18 服务端再拿出token进行比对。
     19 token的第一次产生是发生在login检查账户存在并且正确之后,为该用户赋予一块令牌(加密字符串)
     20 并将token放入response的header里。客户端登陆成功后,从response里取出token。并在以后操作request请求。
     21 都保持在header里添加该段令牌,令牌有效期失效后,只有重新login,才能获取新的令牌。
     22 */
     23 const (
     24     //SecretKey = "welcome to wangshubo's blog"
     25     SecretKey = "I have login"
     26 )
     27 
     28 func fatal(err error) {
     29     if err != nil {
     30         log.Fatal(err)
     31     }
     32 }
     33 
     34 type UserCredentials struct {
     35     Username string `json:"username"`
     36     Password string `json:"password"`
     37 }
     38 
     39 type User struct {
     40     ID       int    `json:"id"`
     41     Name     string `json:"name"`
     42     Username string `json:"username"`
     43     Password string `json:"password"`
     44 }
     45 
     46 type Response struct {
     47     Data string `json:"data"`
     48 }
     49 
     50 type Token struct {
     51     Token string `json:"token"`
     52 }
     53 
     54 func StartServer() {
     55 
     56     http.HandleFunc("/login", LoginHandler)
     57 
     58     http.Handle("/resource", negroni.New(
     59         negroni.HandlerFunc(ValidateTokenMiddleware),
     60         negroni.Wrap(http.HandlerFunc(ProtectedHandler)),
     61     ))
     62 
     63     log.Println("Now listening...")
     64     http.ListenAndServe(":8080", nil)
     65 }
     66 
     67 func main() {
     68     StartServer()
     69 }
     70 
     71 func ProtectedHandler(w http.ResponseWriter, r *http.Request) {
     72 
     73     response := Response{"Gained access to protected resource !"}
     74     JsonResponse(response, w)
     75 
     76 }
     77 
     78 //服务端生成token,并放入到response的header
     79 /**
     80 JWT由三部份组成:
     81 * Header:头部 (对应:Header)
     82 * Claims:声明 (对应:Payload)
     83 * Signature:签名 (对应:Signature)
     84 */
     85 func LoginHandler(w http.ResponseWriter, r *http.Request) {
     86 
     87     var u *User=new(User)
     88 
     89     var user UserCredentials
     90 
     91     err := json.NewDecoder(r.Body).Decode(&user)
     92 
     93     if err != nil {
     94         w.WriteHeader(http.StatusForbidden)
     95         fmt.Fprint(w, "Error in request")
     96         return
     97     }
     98 
     99     //验证是身份:若用户是someone,则生成token
    100     if strings.ToLower(user.Username) != "someone" {
    101         if user.Password != "p@ssword" {
    102             w.WriteHeader(http.StatusForbidden)
    103             fmt.Println("Error logging in")
    104             fmt.Fprint(w, "Invalid credentials")
    105             return
    106         }
    107     }
    108 
    109     //1。生成token
    110     token := jwt.New(jwt.SigningMethodHS256)
    111     claims := make(jwt.MapClaims)
    112     //2。添加令牌关键信息
    113     //添加令牌期限
    114     claims["exp"] = time.Now().Add(time.Hour * time.Duration(1)).Unix()
    115     claims["iat"] = time.Now().Unix()
    116     claims["id"]=u.ID
    117     claims["userName"]=u.Username
    118     claims["password"]=u.Password
    119     token.Claims = claims
    120 
    121     fmt.Println(claims)
    122 
    123     if err != nil {
    124         w.WriteHeader(http.StatusInternalServerError)
    125         fmt.Fprintln(w, "Error extracting the key")
    126         fatal(err)
    127     }
    128 
    129     //获取令牌
    130     tokenString, err := token.SignedString([]byte(SecretKey))
    131     if err != nil {
    132         w.WriteHeader(http.StatusInternalServerError)
    133         fmt.Fprintln(w, "Error while signing the token")
    134         fatal(err)
    135     }
    136 
    137     //2。将生成的token放入到header
    138     response := Token{tokenString}
    139     JsonResponse(response, w)
    140 
    141 }
    142 
    143 //验证Token
    144 func ValidateTokenMiddleware(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
    145     token, err := request.ParseFromRequest(r, request.AuthorizationHeaderExtractor,
    146         func(token *jwt.Token) (interface{}, error) {
    147             return []byte(SecretKey), nil
    148         })
    149 
    150     if err == nil {
    151         if token.Valid {
    152             next(w, r)
    153         } else {
    154             w.WriteHeader(http.StatusUnauthorized)
    155             fmt.Fprint(w, "Token is not valid")
    156         }
    157     } else {
    158         w.WriteHeader(http.StatusUnauthorized)
    159         fmt.Fprint(w, "Unauthorized access to this resource")
    160     }
    161 
    162 }
    163 
    164 func JsonResponse(response interface{}, w http.ResponseWriter) {
    165     json, err := json.Marshal(response)
    166     if err != nil {
    167         http.Error(w, err.Error(), http.StatusInternalServerError)
    168         return
    169     }
    170     w.WriteHeader(http.StatusOK)
    171     w.Header().Set("Content-Type", "application/json")
    172     w.Write(json)
    173 }
    View Code

    通过postman进行验证:

    Step1:发送登录请求

    Step2:使用服务端返回客户端的token去验证有效性(根据获得的token进行get请求)

    参考博客:https://blog.csdn.net/wangshubo1989/article/details/74529333

  • 相关阅读:
    《淘宝网》之系统质量属性分析
    《架构漫谈》读后感 之“关于软件架构师如何工作”
    《软件需求》读后感06
    《软件需求》读后感05
    Cforeach的详细用法--【转】
    事件(Event)(onclick,onchange,onload,onunload,onfocus,onblur,onselect,onmuse)【转载】
    十七、Mysql的主从(一)--主从原理
    十七、Mysql的主从(二)--主从复制部署
    十六、mysql的备份与恢复(三)--xtrabackup(XBK、Xbackup)
    十六、mysql的备份与恢复(二)--mysqldump
  • 原文地址:https://www.cnblogs.com/kaixinyufeng/p/9651304.html
Copyright © 2011-2022 走看看