beego基于ak和sk完成认证

客户端
1. 基于ak/sk和某个算法,计算请求内容对应的签名signature。
2. 发送包含ak和signature的请求到服务端。

package main

import (
	"crypto/sha1"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
)

const (
	AK = "myak"
	SK = "mysk"
)

func Sign(ak, sk, body string) string {
	expiration := 30
	info := fmt.Sprintf("%s_%d_%d", ak, time.Now().Unix(), expiration)
	signature := sha1.Sum([]byte(fmt.Sprintf("%s_%s", info, body)))
	return fmt.Sprintf("%s_%s", info, signature)
}

func main() {
	req, err := http.NewRequest("GET", "http://127.0.0.1:8080/v1/object/a", nil)
	if err != nil {
		panic(err)
	}
	query := req.URL.Query()
	sign := Sign(AK, SK, "")
	query.Set("sign", sign)
	req.URL.RawQuery = query.Encode()
	if err != nil {
		panic(err)
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	bodyBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(bodyBytes))
}

服务端
1. 基于请求中的ak/自己的sk和相同算法,计算请求内容对应的签名signature。
2. 比较请求中的signature和自己计算得到的signature,两者相同时认证通过,否则失败。

package routers

import (
	"beego-test/controllers"
	"crypto/sha1"
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/astaxie/beego"
	beego_context "github.com/astaxie/beego/context"
)

const (
	AK = "myak"
	SK = "mysk"
)

func Sign(ak, sk, body string) string {
	expiration := 30
	info := fmt.Sprintf("%s_%d_%d", ak, time.Now().Unix(), expiration)
	signature := sha1.Sum([]byte(fmt.Sprintf("%s_%s", info, body)))
	return fmt.Sprintf("%s_%s", info, signature)
}

func SignWithTime(ak, sk, body, nowUnixTimeStr string) string {
	expiration := 30
	info := fmt.Sprintf("%s_%s_%d", ak, nowUnixTimeStr, expiration)
	signature := sha1.Sum([]byte(fmt.Sprintf("%s_%s", info, body)))
	return fmt.Sprintf("%s_%s", info, signature)
}

func init() {
	ns := beego.NewNamespace("/v1",
		beego.NSCond(func(ctx *beego_context.Context) bool {
			req := ctx.Input.Context.Request
			query := req.URL.Query()
			reqSign := query.Get("sign")
			if reqSign == "" {
				return false
			}

			reqSigns := strings.Split(reqSign, "_")
			if len(reqSigns) != 4 {
				return false
			}
			if reqSigns[0] != AK {
				return false
			}

			len := req.ContentLength
			body := make([]byte, len)
			req.Body.Read(body)
			newSignResult := SignWithTime(AK, SK, string(body), reqSigns[1])
			if reqSign != newSignResult {
				return false
			}

			reqTime, err := strconv.ParseInt(reqSigns[1], 10, 64)
			if err != nil {
				return false
			}
			expiration, err := strconv.ParseInt(reqSigns[2], 10, 64)
			if err != nil {
				return false
			}
			reqExpireTime := reqTime + expiration
			if time.Now().Unix() > reqExpireTime {
				return false
			}

			return true
		}),
		beego.NSNamespace("/object",
			beego.NSRouter("/a", &controllers.ObjectController{}, "get:Get"),
		),
	)
	beego.AddNamespace(ns)
}

 

package controllers

import (
	"github.com/astaxie/beego"
)
 
type ObjectController struct {
	beego.Controller
}

func (o *ObjectController) Get() {
	o.Data["json"] = map[string]string{"ObjectId": "a"}
	o.ServeJSON()
}

 

image

签名过期时间是30s,是req的URL params key=sign对应的value,内容是ak_请求时间戳_30_哈希值。

posted on 2025-03-07 08:48  王景迁  阅读(28)  评论(0)    收藏  举报

导航