go iris+jwt-go +redis+mysql 实现账号登录功能(二)

一、 redis 的链接

在myapp 里面创建 redis 文件夹,文件夹里面创建一个redis_manage.go 文件。redis 使用的是garyburd 的rdigo 模块。redis 安装时,需要配置运行远程链接才行,具体步骤可以查看网上教程。

package redismanage

import (
	"fmt"

	redigo "github.com/garyburd/redigo/redis"
)


type redismanage struct {}
type Conn = redigo.Conn; // 透传redigo.Conn 类型定义
type Pool = *redigo.Pool;
var RedisString = redigo.String;
var pool Pool;

//创建redismanage实例的函数
func NewRedisManage () *redismanage{
return &redismanage{}
}

// 获取链接redis 的句柄
func (*redismanage) RedigoConnGet() Conn {
return pool.Get()
}

// 设置redis 连接池
func (*redismanage) RedigoConnInit() {
redis_host := "xx.xx.xx.xx" //redis 安装的服务器ip 或者域名
redis_port := 6379 //redis 使用的端口号
pool_size := 20 //连接池的大小
pool = redigo.NewPool(func() (redigo.Conn, error) {
c, err := redigo.Dial("tcp", fmt.Sprintf("%s:%d", redis_host, redis_port),redigo.DialPassword("password")) //redis 如果配置了密码,这里就要配置对应的密码
if err != nil {
return nil, err
}
return c, nil
}, pool_size)
}

二、 gojwt 模块的创建
在myapp 里面创建一个gojwt 文件夹,文件夹里面创建一个gojwt.go的文件

package gojwt

import (
	"github.com/dgrijalva/jwt-go"
	jwtmiddleware "github.com/iris-contrib/middleware/jwt"
)

//参考的链接网站 http://studyiris.com/example/exper/jwt.html
type gojwt struct{}
type StandardClaims = jwt.StandardClaims;
type JwtToken = jwt.Token;
func NewGoJwt() *gojwt{
    return &gojwt{}
}

//加密密钥
var JwtSecret=[]byte("secret")


//Claim是一些实体(通常指的用户)的状态和额外的元数据
type Claims struct{
	Username string `json:"username"`
	Password string `json:"password"`
	jwt.StandardClaims
}
//RefreshClaims
type RefreshClaims struct{
	Token string ``
	jwt.StandardClaims
}




// 生成token
func (*gojwt) GenerateToken(secret []byte, claims Claims) (tokenString string, err error) {
// 创建一个新的令牌对象,指定签名方法和声明
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

// 使用密码签名 并获得完整的编码令牌作为字符串
tokenString, err = token.SignedString(secret)
return tokenString, err
}




// 生成refreshoken
func (*gojwt) GenerateRefreshToken(secret []byte, refreshClaims RefreshClaims) (refreshTokenString string, err error) {
// 创建一个新的令牌对象,指定签名方法和声明
token := jwt.NewWithClaims(jwt.SigningMethodHS256, refreshClaims)




// 使用密码签名并获得完整的编码令牌作为字符串
refreshTokenString, err = token.SignedString(secret)
	return refreshTokenString ,err
}




func (*gojwt) CreateJwtMiddleware() *jwtmiddleware.Middleware {
jwtHandler := jwtmiddleware.New(jwtmiddleware.Config{
	//这个方法将验证jwt的token
	ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
	//自己加密的秘钥或者说盐值
	return JwtSecret, nil
},
//设置后,中间件会验证令牌是否使用特定的签名算法进行签名
//如果签名方法不是常量,则可以使用ValidationKeyGetter回调来实现其他检查
//重要的是要避免此处的安全问题:https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
//加密的方式
SigningMethod: jwt.SigningMethodHS256,
//验证未通过错误处理方式
//ErrorHandler: func(context.Context, string)


//debug 模式
//Debug: bool
});
return jwtHandler
}

三、 创建login 接口
login接口需要实现,账号登录成功后,生成token 和refresh token,写入redis 和mysql 里面,同时设置redis 的有效时限。最后把token 返回给前端。

package main

import (
	"fmt"
	gojwt "main/gojwt"
	mysqlmanage "main/mysql"
	redismanage "main/redis"
	"strings"
	"time"

	"github.com/garyburd/redigo/redis"
	"github.com/kataras/iris/v12"
)
var MysqlManage = mysqlmanage.NewMysqlManage();
var RedisManage = redismanage.NewRedisManage();
var Gojwt = gojwt.NewGoJwt();
// 设置redis 连接池
func init() {
	RedisManage.RedigoConnInit();
	MysqlManage.MysqlmanageInit();
}
func main() {
	//链接redis
	defer RedisManage.RedigoConnGet().Close();
	defer MysqlManage.MysqlConnGet().Close();
	app := iris.New()
	app.OnErrorCode(iris.StatusNotFound, notFound)
	app.Post("/login", loginHandle)
	app.Run(iris.Addr(":8080"),iris.WithCharset("UTF-8"))
}
func notFound(ctx iris.Context){
	code := ctx.GetStatusCode()
	msg := "not found"
	ctx.JSON(iris.Map{
	"Message": msg,
	"Code": code,
	})
}
func index(ctx iris.Context) {
    fmt.Println("compeleted")
    ctx.JSON(iris.Map{
		"Message": "ok",
	}); 
}
func status(ctx iris.Context) {
	ctx.JSON(iris.Map{"Message": "OK"})
}
func loginHandle (ctx iris.Context){
    var name = ctx.PostValue("name");
	var password = ctx.PostValue("password");
    fmt.Printf("%s %s",name,password);
    var users []mysqlmanage.User;   
    MysqlManage.MysqlConnGet().Where(&mysqlmanage.User{Name: name, Password: password}).First(&users)

if len( users) == 0 {
    ctx.JSON(iris.Map{
        "Message": "账号或者密码不正确!"})
        return
}


    claims := gojwt.Claims{
		Username:name,
		Password:password,
		StandardClaims: gojwt.StandardClaims{
				IssuedAt:time.Now().Unix(), // 过期时间,必须设置
		Issuer:"wang", // 可不必设置,也可以填充用户名,
		},
	}
	if token,err :=Gojwt.GenerateToken(gojwt.JwtSecret, claims); err == nil {


	refreshClaims := gojwt.RefreshClaims{
		Token:token,
		StandardClaims:gojwt.StandardClaims{
		ExpiresAt:time.Now().Add(72*time.Hour).Unix(), // 过期时间,必须设置
		Issuer:"wang", // 可不必设置,也可以填充用户名,
		},
	}
	refreshToken,_ := Gojwt.GenerateRefreshToken(gojwt.JwtSecret,refreshClaims)
	tokenString := strings.Split(token,".")[2]
	refreshTokenString:= strings.Split(refreshToken,".")[2]
	//往redis 里面填写token 和 refreshToken
	conn:= RedisManage.RedigoConnGet();
	conn.Do("SET", tokenString, token,"EX", 60*5)
	conn.Do("SET", refreshTokenString,refreshToken,"EX",60*60*24*7)
	MysqlManage.MysqlmanageAlterRecord(name,password,tokenString,refreshTokenString);
	ctx.JSON(iris.Map{
		"data":iris.Map{
		"token":tokenString,
		"refreshToken":refreshTokenString},
		"Message": "OK",
		"responseCode":1000000,
	})
	} else {
	fmt.Printf("%s",token)
	ctx.JSON(iris.Map{
	"Message": "error"})
	}
}

成功运行后的结果:
在这里插入图片描述

四、后续调用的接口的token 验证

func main() {
	//链接redis
	defer RedisManage.RedigoConnGet().Close();
	defer MysqlManage.MysqlConnGet().Close();
	app := iris.New()
	app.OnErrorCode(iris.StatusNotFound, notFound)
	app.Get("/",myHandler,index)
	app.Run(iris.Addr(":8080"),iris.WithCharset("UTF-8"))
}
func index(ctx iris.Context) {
    fmt.Println("compeleted")
    ctx.JSON(iris.Map{
		"Message": "ok",
	}); 
}
//获取request header 里面的 Authorization 字段
func FromAuthHeader(ctx iris.Context) (string, error) {
    authHeader := ctx.GetHeader("Authorization")
    if authHeader == "" {
        return "", nil // No error, just no token
    }
    authHeaderParts := strings.Split(authHeader, " ")
    if len(authHeaderParts) != 2 || strings.ToLower(authHeaderParts[0]) != "bearer" {
        return "", fmt.Errorf("Authorization header format must be Bearer {token}")
    }
    return authHeaderParts[1], nil
}

// 中间件写法,验证token是否有效
func myHandler(ctx iris.Context) {

    token,_ :=FromAuthHeader(ctx)

	conn:= RedisManage.RedigoConnGet();
    _, err := redis.String(conn.Do("GET", token))
    if err != nil {
        fmt.Println("redis get failed:", err)
        ctx.JSON(iris.Map{
            "Message": "token is invalid"})
    } else {
        conn.Do("SET", tokenString, token,"EX", 60*5) //重新刷新token 的时效
        ctx.Next();
    }
}

五、refreshToken 接口

func refreshTokenHandle(ctx iris.Context){
    var refreshToken = ctx.PostValue("refreshToken");
    conn:= RedisManage.RedigoConnGet();
    _, err := redis.String(conn.Do("GET",  refreshToken))
    if err != nil {
	
		ctx.JSON(iris.Map{
			"Message": "refreshToken is invalid"})
	} else {
        mysqlconn := MysqlManage.MysqlConnGet();
	    var users []mysqlmanage.User;	
         mysqlconn.Where("refreshToken = ?", refreshToken).First(&users)
         if len(users)>0 {
             token:= users[0].Token;
             tokenString:= strings.Split(token,".")[2];
            conn:= RedisManage.RedigoConnGet();
            conn.Do("SET", tokenString, token,"EX", 60*1);
            ctx.JSON(iris.Map{
                "Message": "token is updated"})
         }else {
            ctx.JSON(iris.Map{
                "Message": "refreshToken is invalid"})
         }
       
	
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值