golang iris 学习二:添加Jwt验证

Jwt科普

在开始之前

先把

1
import "github.com/kataras/iris"

这个为库替换成

1
import "github.com/kataras/iris/v12"

要不然在使用Jwt中间件的时候会报错

先加个配置

config.yml

1
2
3
4
jwt:
SecretKey: sdfadfasdfdas
exp: 480
...

定义一个Key和过期时间(以分钟为单位)

解析配置

config/config.go

1
2
3
4
5
6
7
8
9
10
11
...
type jwtConfig struct {
SecretKey string `yaml:"SecretKey"`
Exp int `yaml:"exp"`
}

type globalConfig struct {
Mongo mongoConfig `yaml:"mongo"`
Jwt jwtConfig `yaml:"jwt"`
}
...

撸个生成Token、解析Token及验证Toke的方法

middleware/jwt_middleware.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import (
"github.com/dgrijalva/jwt-go"
jwtmiddleware "github.com/iris-contrib/middleware/jwt"
"github.com/kataras/iris/v12/context"
"goms/config"
"goms/datamodels"
"time"
)

var (
secretKey = []byte(config.GConfig.Jwt.SecretKey)
exp = config.GConfig.Jwt.Exp
)

// 生成token
func CreateToken(userId, username string) (tokenString string, err error) {
token := jwt.New(jwt.SigningMethodHS256)

claims := make(jwt.MapClaims)
claims["exp"] = time.Now().Add(time.Minute * time.Duration(exp)).Unix()
claims["iat"] = time.Now().Unix()
claims["username"] = username
claims["userId"] = userId

token.Claims = claims
tokenString, err = token.SignedString(secretKey)
return
}

// 解析token
func ParseToken(tokenSrt string) (claims jwt.MapClaims, err error) {
token, err := jwt.Parse(tokenSrt, func(*jwt.Token) (interface{}, error) {
return secretKey, nil
})
if err != nil {
return nil, err
}
claims = token.Claims.(jwt.MapClaims)
return
}

// jwt验证失败返回内容
func OnError(ctx context.Context, err error) {
if err == nil {
return
}

ctx.StopExecution()
response := &datamodels.Response{
Code: 50008,
Msg: err.Error(),
}
ctx.JSON(response)
}

// 验证Token
func JwtHandler() *jwtmiddleware.Middleware {
return jwtmiddleware.New(jwtmiddleware.Config{
ValidationKeyGetter: func(token *jwt.Token) (i interface{}, e error) {
return secretKey, nil
},
ErrorHandler: OnError,
SigningMethod: jwt.SigningMethodHS256,
})
}

业务逻辑

因为还没有用户表,就不做验证了,随便返回先
services/login_service.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package services

import (
"fmt"
"goms/datamodels"
"goms/middleware"
)

type LoginService interface {
Login(userId, username string) (response datamodels.Response)
Info(username string) (response datamodels.Response)
Logout() (response datamodels.Response)
}

type loginService struct {
}

func NewUserService() LoginService {
return &loginService{}
}

func (u *loginService) Login(userId, username string) (response datamodels.Response) {
token, err := middleware.CreateToken(userId, username)
if err != nil {
response.Code = 50001
response.Msg = fmt.Sprintf("用户登陆失败:%v", err)
}
response.Code = 20000
response.Msg = "Login success"
data := map[string]string{
"token": token,
}
response.Data = data
return
}

func (u *loginService) Info(tokenString string) (response datamodels.Response) {
claims, _ := middleware.ParseToken(tokenString)
username := claims["username"].(string)

response.Code = 20000
response.Msg = "success"
response.Data = map[string]interface{}{
"avatar": "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif",
"id": "5d917402a0096e54c0140f07",
"username": username,
"roles": []string{"admin"},
}
return
}

func (u *loginService) Logout() (response datamodels.Response) {
response.Code = 20000
response.Msg = "Logout success"
return
}

Web请求

暂时还没有验证用户信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package controllers

import (
"github.com/kataras/iris/v12"
"goms/datamodels"
services2 "goms/services"
)

type LoginController struct {
Ctx iris.Context
Service services2.LoginService
}

func NewLoginController() *LoginController {
return &LoginController{
Service: services2.NewUserService(),
}
}

func (u *LoginController) PostLogin() (response datamodels.Response) {
return u.Service.Login("xxxx", "wisp")
}

func (u *LoginController) PostLogout() (response datamodels.Response) {
return u.Service.Logout()
}

func (u *LoginController) GetInfo() (response datamodels.Response) {
tokenString := u.Ctx.URLParam("token")
return u.Service.Info(tokenString)
}

路由添加Jwt验证

route/route.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package route

import (
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/mvc"
"goms/controllers"
"goms/middleware"
)

func InitRoute(app *iris.Application) {
mvc.Configure(app.Party("/user"), func(m *mvc.Application) {
m.Handle(controllers.NewLoginController())
})

bathPath := "/api/v1"
mvc.Configure(app.Party(bathPath+"/games"), func(m *mvc.Application) {
m.Router.Use(middleware.JwtHandler().Serve)
m.Handle(controllers.NewGameController())
})
}

来一波测试

main_test.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package main

import (
"encoding/json"
"fmt"
"github.com/kataras/iris/v12/httptest"
"goms/datamodels"
"testing"
)

func getJwtHeaders(t *testing.T) map[string]string {
app := newApp()
e := httptest.New(t, app)
response := datamodels.Response{}
body := e.POST("/user/login").Expect().Status(httptest.StatusOK).Body().Raw()
json.Unmarshal([]byte(body), &response)
token := response.Data.(map[string]interface{})["token"].(string)
tokenHeaders := map[string]string{
"Authorization": fmt.Sprintf("Bearer %s", token),
}
return tokenHeaders
}

func TestNewApp(t *testing.T) {
app := newApp()
e := httptest.New(t, app)
e.POST("/user/login").Expect().Status(httptest.StatusOK).JSON().
Object().ContainsKey("code").ValueEqual("code", 20000)

tokenHeaders := getJwtHeaders(t)

e.POST("/api/v1/games").Expect().Status(httptest.StatusOK).JSON().
Object().ContainsKey("code").ValueEqual("code", 50008)
e.POST("/api/v1/games").WithHeaders(tokenHeaders).Expect().Status(httptest.StatusOK).JSON().
Object().ContainsKey("code").ValueEqual("code", 20000)
}

go test验证一下

1
2
3
4
5
wisp@wisp-System-Product-Name:~/go/src/goms$ go test -v
=== RUN TestNewApp
--- PASS: TestNewApp (0.00s)
PASS
ok goms 0.012s