145 lines
3.7 KiB
Go
145 lines
3.7 KiB
Go
package token
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"time"
|
||
|
||
"github.com/dgrijalva/jwt-go"
|
||
"google.golang.org/grpc/metadata"
|
||
)
|
||
|
||
// 创建token
|
||
func CreateToken(userName string) (tokenString string) {
|
||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||
"iss": "grpc-token",
|
||
"aud": "grpc-token",
|
||
"nbf": time.Now().Unix(),
|
||
"exp": time.Now().Add(time.Hour).Unix(),
|
||
"sub": "user",
|
||
"username": userName,
|
||
"timestamp": time.Now().String(),
|
||
})
|
||
|
||
//根据key值签名token
|
||
tokenString, err := token.SignedString([]byte("verysecret"))
|
||
if err != nil {
|
||
panic(err)
|
||
}
|
||
|
||
return tokenString
|
||
}
|
||
|
||
// AuthTokenn 自定义认证
|
||
type AuthToken struct {
|
||
Token string
|
||
}
|
||
|
||
// 实现了PerRPCCredentials接口,获取payload
|
||
func (c AuthToken) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
|
||
return map[string]string{
|
||
"authorization": c.Token,
|
||
}, nil
|
||
}
|
||
|
||
func (c AuthToken) RequireTransportSecurity() bool {
|
||
return false
|
||
}
|
||
|
||
// Claims defines the struct containing the token claims.
|
||
type Claims struct {
|
||
jwt.StandardClaims
|
||
|
||
// 添加自定义字段
|
||
Username string `json:"username"`
|
||
Timestamp string `json:"timestamp"`
|
||
}
|
||
|
||
// Step1. 从 context 的 metadata 中,取出 token
|
||
func getTokenFromContext(ctx context.Context) (string, error) {
|
||
md, ok := metadata.FromIncomingContext(ctx)
|
||
if !ok {
|
||
return "", fmt.Errorf("ErrNoMetadataInContext")
|
||
}
|
||
|
||
// md 的类型是 type MD map[string][]string
|
||
token, ok := md["authorization"]
|
||
if !ok || len(token) == 0 {
|
||
return "", fmt.Errorf("ErrNoAuthorizationInMetadata")
|
||
}
|
||
// 因此,token 是一个字符串数组,只用了 token[0]
|
||
return token[0], nil
|
||
}
|
||
|
||
func CheckAuth(ctx context.Context) (username string) {
|
||
// 从上下文中获取JWT令牌字符串
|
||
tokenStr, err := getTokenFromContext(ctx)
|
||
|
||
if err != nil {
|
||
panic("get token from context error") // 如果获取令牌出错,则抛出错误
|
||
}
|
||
|
||
// 定义用于解析JWT令牌的自定义声明结构体
|
||
var clientClaims Claims
|
||
|
||
// 解析JWT令牌,并将声明解析到自定义声明结构体中
|
||
token, err := jwt.ParseWithClaims(tokenStr, &clientClaims, func(token *jwt.Token) (interface{}, error) {
|
||
// 检查JWT令牌的算法是否为HS256,如果不是,则抛出错误
|
||
if token.Header["alg"] != "HS256" {
|
||
panic("ErrInvalidAlgorithm")
|
||
}
|
||
// 返回用于验证签名的密钥,这里是一个固定的密钥 "verysecret"
|
||
return []byte("verysecret"), nil
|
||
})
|
||
fmt.Println(token)
|
||
if err != nil {
|
||
panic("jwt parse error") // 如果解析JWT出错,则抛出错误
|
||
}
|
||
|
||
// 检查JWT令牌是否有效,如果无效,则抛出错误
|
||
if !token.Valid {
|
||
panic("ErrInvalidToken")
|
||
}
|
||
|
||
// 返回从JWT令牌中提取的用户名
|
||
return clientClaims.Username
|
||
}
|
||
|
||
// 用于验证token
|
||
func Check(ctx context.Context) bool {
|
||
// 从上下文中获取JWT令牌字符串
|
||
tokenStr, err := getTokenFromContext(ctx)
|
||
|
||
if err != nil {
|
||
panic("get token from context error")
|
||
}
|
||
|
||
// 定义用于解析JWT令牌的自定义声明结构体
|
||
var clientClaims Claims
|
||
|
||
// 解析JWT令牌,并将声明解析到自定义声明结构体中
|
||
token, err := jwt.ParseWithClaims(tokenStr, &clientClaims, func(token *jwt.Token) (interface{}, error) {
|
||
// 检查JWT令牌的算法是否为HS256,如果不是,则抛出错误
|
||
if token.Header["alg"] != "HS256" {
|
||
panic("ErrInvalidAlgorithm")
|
||
}
|
||
// 返回用于验证签名的密钥,这里是一个固定的密钥 "verysecret"
|
||
return []byte("verysecret"), nil
|
||
})
|
||
fmt.Println(token)
|
||
if err != nil {
|
||
return false
|
||
}
|
||
|
||
// 检查JWT令牌是否有效,如果无效,则抛出错误
|
||
if !token.Valid {
|
||
return false
|
||
}
|
||
|
||
if clientClaims.Username != "Wuxinyu" {
|
||
return false
|
||
}
|
||
|
||
return true
|
||
}
|