首页 > 其他分享 >go使用jwt生成token

go使用jwt生成token

时间:2023-08-04 15:34:09浏览次数:37  
标签:rw return jwt token 用户 Token go

常见的认证方式

一般用户认证主流的方式大致上分为基于 session 和基于 token 这两种。

基于 sesion 的认证方式

  1. 用户向服务器发送用户名和密码。
  2. 服务器验证通过后,在当前对话(sesion)里面保存相关数据,比如用户角色、登录时间等等。
  3. 服务器向用户返回一个 session_id,写入用户的 Cookie 或其他存储。
  4. 用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。
  5. 服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。
  6. 用户退出登录,服务器将对应 session_id 的数据清除。

这种方式服务端需要将 session_id 及相关的数据保存起来,在接收到用户请求时进行校验,比如可以存储到 Redis 中。

基于 token 的认证方式

  1. 用户向服务器发送用户名和密码。
  2. 服务器将相关数据,比如用户 ID,认证有效期等信息签名后生成 token 返回给客户端。
  3. 客户端将 token 写入本地存储。
  4. 用户随后的每一次请求,都将 token 附加到 header 中。
  5. 服务端获取到用户请求的 header,拿到用户数据并且做签名校验,如果校验成功则说明数据没有被篡改,是有效的,确认 token 在有效期内,用户数据就是有效的。

jwt 是基于 token 的认证方式的一种。这里我们使用 jwt-go 在 Golang 项目中使用 jwt。以下代码均为示例代码,部分内容有所删减,仅供参考。

生成 Token

服务器端需要提供一个登录接口用于用户登录。客户端提供用户名和密码,服务器端进行校验,如果校验通过,则生成 Token 返回给客户端。

import (
    jwt "github.com/dgrijalva/jwt-go"
)

func GenerateToken(uid string, role int, expireDuration time.Duration) (string, error) {
    expire := time.Now().Add(expireDuration)
    // 将 uid,用户角色, 过期时间作为数据写入 token 中
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, util.LoginClaims{
        Uid:  uid,
        Role: role,
        StandardClaims: jwt.StandardClaims{
            ExpiresAt: expire.Unix(),
        },
    })
    // SecretKey 用于对用户数据进行签名,不能暴露
    return token.SignedString([]byte(util.SecretKey))
}

func (ctl *LoginController) Login(rw http.ResponseWriter, req *http.Request) {
    var u loginRequest
    json.NewDecoder(req.Body).Decode(&u)

    // 将用户传入的用户名和密码和数据库中的进行比对
    user, err := ctl.db.GetUserByName(req.Context(), u.User)
    if err != nil {
        log.Warn("get user from db by name error: %v", err)
        httputil.Error(rw, errors.ErrInternal)
        return
    }

    if common.EncodePassowrd(u.Password, u.User) != user.Password {
        log.Warn("name [%s] password incorrent", u.User)
        httputil.Error(rw, errors.ErrLoginFailed)
        return
    }

    // 生成返回给用户的 token
    token, err := GenerateToken(user.UID, user.Role, 3*24*time.Hour)
    if err != nil {
        log.Warn("name [%s] generateToken error: %v", u.User, err)
        httputil.Error(rw, errors.ErrInternal)
        return
    }

    res := struct {
        Token string `json:"token"`
    }{
        Token: token,
    }
    httputil.Reply(rw, &res)
}

校验 Token

这里要求客户端每次将通过登录接口获取到的 token 设置在发送请求的 Authorization header 中。

func (a *AuthFilter) Filter(next http.Handler) http.Handler {
    return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
        tokenStr := req.Header.Get("Authorization")
        token, err := jwt.ParseWithClaims(tokenStr, &util.LoginClaims{}, func(token *jwt.Token) (interface{}, error) {
            return []byte(util.SecretKey), nil 
        }   
        if err != nil {
            httputil.Error(rw, errors.ErrUnauthorized)
            return
        }   

        if claims, ok := token.Claims.(*util.LoginClaims); ok && token.Valid {
            log.Infof("uid: %s, role: %v", claims.Uid, claims.Role)
        } else {
            httputil.Error(rw, errors.ErrUnauthorized)
            return
        }   
        next.ServeHTTP(rw, req)
    }   
}

注意点

  • 由于 jwt 返回的 Token 中的数据仅做了 Base64 处理,没有加密,所以不应放入重要的信息。
  • jwt Token 由于是无状态的,任何获取到此 Token 的人都可以访问,所以为了减少盗用,可以将 Token 有效期设置短一些。对一些重要的操作,尽量再次进行认证。
  • 网站尽量使用 HTTPS,可以减少 Token 的泄漏。

标签:rw,return,jwt,token,用户,Token,go
From: https://www.cnblogs.com/ccdr/p/17606061.html

相关文章

  • chromedp+goquery简易抓取百度热搜
    安装gogetgithub.com/wms3001/datacrawling抓取百度热搜信息varbnBaiDuHotNewsres:=bn.GetBaiDuHostNews()log.Println(res)......
  • [缓存] Google Guava Cache本地缓存框架一览
    1序言上一次使用GuavaCache框架还是在2年前浙江某大学的数据服务平台项目中,用于缓存用户的数据服务购物小车数据;参见:[缓存]缓存技术初探-博客园/千千寰宇而这一次,是在基于GoogleGuavaCache+refreshAfterWrite特性来缓存Influxdb的物联网信号数据表的信号字段信......
  • go语言基础-指针
    不像Java和.NET,Go语言为程序员提供了控制数据结构的指针的能力;但是,你不能进行指针运算。通过给予程序员基本内存布局,Go语言允许你控制特定集合的数据结构、分配的数量以及内存访问模式,这些对构建运行良好的系统是非常重要的:指针对于性能的影响是不言而喻的,而如果你想要做的是......
  • go语言基础-时间和日期
    time 包为我们提供了一个数据类型 time.Time(作为值使用)以及显示和测量时间和日期的功能函数。当前时间可以使用 time.Now() 获取,或者使用 t.Day()、t.Minute() 等等来获取时间的一部分;你甚至可以自定义时间格式化字符串,例如: fmt.Printf("%02d.%02d.%4d\n",t.Day(),t.Mon......
  • go语言基础-strings和strconv包
    作为一种基本数据结构,每种语言都有一些对于字符串的预定义处理函数。Go中使用 strings 包来完成对字符串的主要操作。前缀和后缀HasPrefix() 判断字符串 s 是否以 prefix 开头:strings.HasPrefix(s,prefixstring)boolHasSuffix() 判断字符串 s 是否以 suffix......
  • go语言基础-基本类型和布尔
    这部分讲解有关布尔型、数字型和字符型的相关知识。表达式是一种特定类型的值,它可以由其他的值以及运算符组合而成。每个类型都定义了可以和自己结合的运算符集合,如果你使用了不在这个集合中的运算符,在编译时获得编译错误。一元运算符只可以用于一个值的操作(作为后缀),而二元运算......
  • 4 抽象工厂方法 -- go语言设计模式
    工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。因此,可以考虑将一些相关的产品组成一个“产品族”,由同一个工厂来统一生产,这就是本文将要学习的......
  • linux上使用yum部署mongodb4.2+分片副本
    来源:https://blog.51cto.com/wutengfei/5937039系统配置Linux是有文件句柄限制的,而且默认不是很高,一般都是1024,作为一台生产服务器,其实很容易就达到这个数量。为防止服务因toomanyopenfiles错误出现宕机,这里需要对linux系统句柄数进行调整。##临时调整,系统重启即失效ulimit......
  • go语言基础-基础数据类型之常量
    常量使用关键字const定义,用于存储不会改变的数据。存储在常量中的数据类型只能是布尔型、数字型(整数型、浮点型和复数)和字符串型。常量的定义格式:constidentifier[type]=value,例如:constPi=3.14159在Go语言中,你可以省略类型说明符[type],因为编译器可以根据变量的值来......
  • go语言基础-语言的核心结构与技术之基本结构要素
    packagemainimport"fmt"funcmain(){fmt.Println("hello,world")}上述伪代码可以看到,学习go语言的基本语法,接下来,针对这段伪代码分析packagemain封装的概念,导入与可见性包是构造代码的一种方式:每个程序都由包(通常简称为pkg)的概念组成,可以使用自身的包或者......