Golang:BasicAuth + JWT 校验用户权限

为什么需要权限

在平常浏览网页中,大多数网站对用户分为游客和普通用户,还有会员,那么游客浏览一些网页需要登录才能看到,普通用户查看一些帖子需要积分,而会员则像是开了一条绿色通道,什么都能访问,这就是权限的作用

使用 BasicAuth 认证

BasicAuth 是开放平台的认证方式,每次访问 API 都会携带 用户的 username 和 password 认证,那么 BasicAuth 会对 username 和 password 进行加密,那我们可以使用 PostMan 这个工具来测试 BasicAuth 的加密效果。为了测试,使用如下代码,这里,我用了echo这个框架(当然也可以使用ginirisbeego等框架)搭建了一个 login 的接口,在 login 这个接口中,我们从请求头中获取 BasicAuth 的加密信息(在 http 请求中,对请求认证的信息是放在请求头的 Authorization 中)

// main.go
package main

import (
	"fmt"

	"github.com/labstack/echo"
)

func main() {
   
   
	e := echo.New()
	e.GET("/login", login)
	e.Logger.Fatal(e.Start(":1323"))
}

func login(c echo.Context) error {
   
   
	fmt.Println(c.Request().Header.Get("Authorization"))
	return nil
}

运行这段代码,会在 1323 端口上进行监听,那么需要在 PostMan 中发起请求:

我们点击 Send 后,在运行 go 总端中会打印出, username 和 password 加密后的结果

那么我们怎么拿到加密后的用户名和密码?在 echo 框架中内置了简单 BasicAuth 中间件,我们可以直接使用官方的实例代码改造:

// 官方示例
// 这里的 username 和 password 就是我们传过来的 username 和 password
e.Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) {
   
   
	// Be careful to use constant time comparison to prevent timing attacks
	if subtle.ConstantTimeCompare([]byte(username), []byte("joe")) == 1 &&
		subtle.ConstantTimeCompare([]byte(password), []byte("secret")) == 1 {
   
   
		return true, nil
	}
	return false, nil
}))

改造我们的代码:

// main.go
package main

import (
	"fmt"

	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
)

func main() {
   
   
	e := echo.New()
	e.Use(middleware.BasicAuth(auth))
	e.GET("/login", login)
	e.Logger.Fatal(e.Start(":1323"))
}

func auth(username, password string, c echo.Context) (bool, error) {
   
   
	fmt.Println("username", username)
	fmt.Println("password", password)
	return false, nil
}

func login(c echo.Context) error {
   
   
	fmt.Println(c.Request().Header.Get("Authorization"))
	return nil
}

那么再运行代码,监听 1323 端口,再用 PostMan 发一次请求:

此时运行的结果为

我们可以看到,直接把加密的结果给解密出来了,使用 BasicAuth 中间件,解密过程就不需要我们来做了,直接交给 BasicAuth 中间件就好了。那么由于我们在 auth 中返回的是false,所以这个中间件会一直认证不通过,还会给 PostMan 返回一个 json 信息:

{
   
   
  "message": "Unauthorized"
}

之后,我们就可以使用 BasicAuth 做认证,改下 auth 的代码

func auth(username, password string, c echo.Context) (bool, error) {
   
   
	if username != "startdusk" || password != "root" {
   
   
		return false, nil
	}
	return true, nil
}

使用 BasicAuth + JWT 认证

在 BasicAuth 中直接传递用户的 username 和 password 显然是不安全的,那么用户的 username 和 password 只会在用户登录的时候传递一次,那么,可以用户登录过后给用户颁发一个令牌(这个令牌里边可以写入用户的 id 等不容易被识别的东西),然后 BasicAuth 就传递这个令牌,用户可以拿着这个令牌去访问其他接口,这样我们就避免了传递 username 和 password 的风险。
这里推荐使用 jwt-go 这个库,具体的生成 JWT 令牌代码如下:


// 拓展我们要写入token的信息
type Claims struct {
   
   
	Uid int `json:"uid"` // 扩展写入用户的id
	jwt.StandardClaims
}

func genToken(uid int) (string, error) {
   
   
	secretKey := "secretKey" // 加密的key
	expiresIn := time.Duration(24 * 30) // 设置过期时间
	claims := Claims{
   
   
		Uid: uid,
		StandardClaims: jwt.StandardClaims{
   
   
			ExpiresAt: time.Now().Add(time.Hour.Truncate(expiresIn)).Unix(),
			Issuer:    "startdusk", // 签发的用户(自定义名字)
		},
	}
	tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) // 使用sha256进行加密claims这个结构体
	token, err := tokenClaims.SignedString([]byte(secretKey)) // 生成签名
	return token, err
}

那我们的用户请求流程变为:

更据流程,我们将 login 部分的代码修改(访问 login 也改为POST的方式):



// 定义一个用户的结构体,接收用户数据
type User struct {
   
   
	Username string `json:"username"`
	Password string `json:"password"`
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值