Json web token (JWT) 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。 JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
JWT包括了三部分:header, payload,signature。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJBY2NvdW50IjoiZTY5YTRmNjU5ZjZiZWM5NWE0MGRhNmUyMDc1OGUyOTciL
CJleHAiOjE2MTUyNTczMjcsImlhdCI6MTYxNTI1NzI5NywiaXNzIjoiYXBwX3
YxLjAuMSIsIm5iZiI6MTYxNTI1NzI5Nywic3ViIjoibG9naW4ifQ.
Vvoipb7i-BcoNjjbvnrVA2AXKK1JsGd19rZnUVGLzfg
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
base64解密后内容: {"alg":"HS256","typ":"JWT"}
eyJBY2NvdW50IjoiZTY5YTRmNjU5ZjZiZWM5NWE0MGRhNmUyMDc1OGUyOTciL
CJleHAiOjE2MTUyNTczMjcsImlhdCI6MTYxNTI1NzI5NywiaXNzIjoiYXBwX3
YxLjAuMSIsIm5iZiI6MTYxNTI1NzI5Nywic3ViIjoibG9naW4ifQ
base64解密后内容:
{ "Account":"e69a4f659f6bec95a40da6e20758e297",
"exp":1615257327,
"iat":1615257297,
"iss":"app_v1.0.1",
"nbf":1615257297,
"sub":"login"
}
Vvoipb7i-BcoNjjbvnrVA2AXKK1JsGd19rZnUVGLzfg
生成规则;
base64(head)+ '.'+base64(payload)+ 服务端自定义的secret串,通过header中声明的加密方式进行加盐secret组合加密
package utils
import (
"crypto/md5"
"encoding/hex"
jwt "github.com/dgrijalva/jwt-go"
"time"
)
var jwtSecret = []byte("testV3")
var md5Salt = []byte("salt001")
type Token struct {
Account string
jwt.StandardClaims
}
func CreateJwtToken(account string) (string, error) {
var token Token
token.StandardClaims = jwt.StandardClaims{
Audience: "", // 受众群体
ExpiresAt: time.Now().Add(30 * time.Second).Unix(), // 到期时间
Id: "", // 编号
IssuedAt: time.Now().Unix(), // 签发时间
Issuer: "app_v1.0.1", // 签发人
NotBefore: time.Now().Unix(), // 生效时间
Subject: "login", // 主题
}
h := md5.New()
h.Write([]byte(account))
h.Write(md5Salt)
cipherStr := h.Sum(nil)
accountAuthStr := hex.EncodeToString(cipherStr)
token.Account = accountAuthStr
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, token)
return tokenClaims.SignedString(jwtSecret)
}
func ParseToken(token string) (jwt.MapClaims, error) {
jwtToken, err := jwt.ParseWithClaims(token, jwt.MapClaims{}, func(token *jwt.Token) (i interface{}, err error) {
return jwtSecret, nil
})
if err != nil || jwtToken == nil {
return nil, err
}
claim, ok := jwtToken.Claims.(jwt.MapClaims)
if ok && jwtToken.Valid {
return claim, nil
} else {
return nil, nil
}
}
service.go
func (s baseService) Login(ctx context.Context, in LoginRequest) (resp LoginResponse, err error) {
reqId := ctx.Value(utils.BaseRequestId).(string)
log.GetLogger().Info("service layer: do Login handler, reqId=" + reqId)
if in.Account != "ggr" || in.PassWord != "12345" {
return resp, err
}
resp.Token, err = utils.CreateJwtToken(in.Account)
if err != nil {
return resp, err
}
return
}
endpoint.go
package endpoint
import (
"context"
"github.com/go-kit/kit/endpoint"
"go-kit-microservice/internal/pkg/log"
"go-kit-microservice/internal/pkg/utils"
"go-kit-microservice/internal/service"
)
type EndPoints struct {
MultiplyEndPoint endpoint.Endpoint
LoginEndPoint endpoint.Endpoint
}
func NewEndpoints(svc service.Service) EndPoints {
var multiplyEndpoint endpoint.Endpoint
{
multiplyEndpoint = makeMultiplyMultiplyEndPoint(svc)
multiplyEndpoint = AuthMiddleware()(multiplyEndpoint)
}
var loginEndpoint endpoint.Endpoint
{
loginEndpoint = makeLoginEndPoint(svc)
}
return EndPoints{MultiplyEndPoint: multiplyEndpoint, LoginEndPoint: loginEndpoint}
}
func makeMultiplyMultiplyEndPoint(s service.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
reqId := ctx.Value(utils.BaseRequestId).(string)
log.GetLogger().Info("endpoint layer: reqId=" + reqId)
req := request.(service.MultiplyRequest)
resp := s.Multiply(ctx, req)
return resp, nil
}
}
func makeLoginEndPoint(s service.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
reqId := ctx.Value(utils.BaseRequestId).(string)
log.GetLogger().Info("endpoint layer: reqId=" + reqId)
req := request.(service.LoginRequest)
resp, err := s.Login(ctx, req)
return resp, err
}
}
token验证中间件auth_milddleware.go:
package endpoint
import (
"context"
"errors"
"github.com/go-kit/kit/endpoint"
"go-kit-microservice/internal/pkg/utils"
)
func AuthMiddleware() endpoint.Middleware {
return func(next endpoint.Endpoint) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
token := ctx.Value(utils.JwtTokenKey).(string)
if token == "" {
return "nil", errors.New("请先登录")
}
jwtInfo, err := utils.ParseToken(token)
if err != nil {
return "", err
}
if v, ok := jwtInfo["Account"]; ok {
ctx = context.WithValue(ctx, "account", v)
}
return next(ctx, request)
}
}
}
transport.go
package transport
import (
"context"
"encoding/json"
"fmt"
"github.com/go-kit/kit/endpoint"
httptransport "github.com/go-kit/kit/transport/http"
uuid "github.com/satori/go.uuid"
endpoints "go-kit-microservice/internal/endpoint"
log "go-kit-microservice/internal/pkg/log"
"go-kit-microservice/internal/pkg/utils"
"go-kit-microservice/internal/service"
"net/http"
"strconv"
)
func MewHttpHandler(endpoints endpoints.EndPoints) http.Handler {
options := []httptransport.ServerOption{
// Unified exception handling
httptransport.ServerErrorEncoder(errorEncoder),
// before request set request id
httptransport.ServerBefore(func(ctx context.Context, request *http.Request) context.Context {
reqId := uuid.NewV5(uuid.NewV4(), "req_id").String()
ctx = context.WithValue(ctx, utils.BaseRequestId, reqId)
ctx = context.WithValue(ctx, utils.JwtTokenKey, request.Header.Get("Authorization"))
return ctx
}),
}
m := http.NewServeMux()
m.Handle("/multiply", httptransport.NewServer(
endpoints.MultiplyEndPoint,
decodeMultiplyRequest,
encodeGeneralResponse,
options...,
))
m.Handle("/login", httptransport.NewServer(
endpoints.LoginEndPoint,
decodeLoginRequest,
encodeGeneralResponse,
options...,
))
return m
}
// decode the request to service layer request params
func decodeMultiplyRequest(ctx context.Context, r *http.Request) (interface{}, error) {
reqId := ctx.Value(utils.BaseRequestId).(string)
msg := fmt.Sprintf("%s\t%s\t%s\treqId=%s\t%s\t%s\t",
utils.RemoteIp(r),
r.Method,
r.RequestURI,
reqId,
r.Proto,
r.Header.Get("User-Agent"))
log.GetLogger().Info("decode request:" + msg)
var (
in service.MultiplyRequest
err error
)
if in.A, err = strconv.Atoi(r.FormValue("a")); err != nil {
log.GetLogger().Error("decode request param a failed:" + err.Error())
return in, err
}
if in.B, err = strconv.Atoi(r.FormValue("b")); err != nil {
log.GetLogger().Error("decode request param b failed:" + err.Error())
return in, err
}
return in, nil
}
// encode the response data to user
func encodeGeneralResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
if f, ok := response.(endpoint.Failer); ok && f.Failed() != nil {
errorEncoder(ctx, f.Failed(), w)
return nil
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
return json.NewEncoder(w).Encode(response)
}
// decode the request to service layer request params
func decodeLoginRequest(ctx context.Context, r *http.Request) (interface{}, error) {
var req service.LoginRequest
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
return nil, err
}
return req, nil
}
// error EncodeHandler
func errorEncoder(ctx context.Context, err error, w http.ResponseWriter) {
w.WriteHeader(http.StatusOK)
log.GetLogger().Error(err.Error())
e := json.NewEncoder(w).Encode(errorWrapper{Error: err.Error()})
if e != nil {
log.GetLogger().Error("json encode failed: " + e.Error())
}
}
type errorWrapper struct {
Error string `json:"error"`
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。