基于iris-xorm-casbin-jwt 的权限管理项目2

编写路由及中间件

    • 上面一篇主要介绍到 orm的设计
    • 这一篇说到路由及中间件的设计
      • 1. 先贴出main的代码
      • 2. 路由设计
      • 3. 贴出login 和logout 的代码,供参考
        • 1. login
        • 4. logout
      • 4. casbin
    • 通过上述直接贴代码的方法,能更好的作为我学习笔记吧
    • 注意事项
    • github地址 只写了登录,退出,user管理,但是架构已经搭起来,可供于参考

上面一篇主要介绍到 orm的设计

这一篇说到路由及中间件的设计

所使用的中间件有 yaag,jwt,casbin,logger

1. 先贴出main的代码

app := iris.New()
	app.Logger().SetLevel("debug")
	//初始化中间件,API文档
	yaag.Init(&yaag.Config{
		On:       true, //是否开启自动生成API文档功能
		DocTitle: "Iris",
		DocPath:  "./api/apidoc.html", //生成API文档名称存放路径
		BaseUrls: map[string]string{"Production": "", "Staging": ""},
	})
	// 初始化中间件,xorm 引擎
	configs.MysqlEngine()
	// 请求日志记录
	customLogger := logger.New(logger.Config{
		//状态显示状态代码
		Status: true,
		// IP显示请求的远程地址
		IP: true,
		//方法显示http方法
		Method: true,
		// Path显示请求路径
		Path: true,
		// Query将url查询附加到Path。
		Query: true,
		//Columns:true,
		// 如果不为空然后它的内容来自`ctx.Values(),Get("logger_message")
		//将添加到日志中。
		MessageContextKeys: []string{"logger_message"},
		//如果不为空然后它的内容来自`ctx.GetHeader(“User-Agent”)
		MessageHeaderKeys: []string{"User-Agent"},
	})
	app.Use(customLogger)
	//加载模板文件
	app.RegisterView(iris.HTML("./web/views/", ".html"))
	//加载静态资源
	app.HandleDir("/", "./web/static")
	// 添加路由
	routers.Routers(app)

	app.Run(
		//开启web服务
		iris.Addr("localhost:8080"),
		//实现更快的json序列化和更多优化
		iris.WithOptimizations,
		iris.WithCharset("utf-8"),
	)

我这里为了方便,并没有重构代码,可以一次性将代码展示出来,可以看到 写出以下功能:

  1. iris 的设置日志级别
  2. yaag 的配置
  3. 初始化xorm引擎
  4. logger 的设计
  5. 加载静态资源
  6. 添加路由
  7. 最后是运行的配置设置
    上述有专门的注释,讲述的很细节,这里不再说明

2. 路由设计

func Routers(api *iris.Application){
	app := api.Party("/", middleware.CrsAuth()).AllowMethods(iris.MethodOptions)
	{
		app.Get("/", func(ctx iris.Context) { // 首页模块
			_ = ctx.View("login.html")
		})

		back := app.Party("/back")
		{
			back.HandleDir("/", "./web/static")
			back.Post("/doAJAXLogin",controllers.DoAJAXLogin).Name = "登录"
			//back.Use(irisyaag.New())
			casbin := middleware.InitCasbin()
			casbinMiddleware := middleware.New(casbin)               //casbin for xorm
			back.Use(middleware.JWTMiddleware().Serve,casbinMiddleware.ServeHTTP) //登录验证
			back.Get("/logout",controllers.Logout).Name = "退出"
			back.Get("/main",controllers.Main).Name = "back 主页"
			back.PartyFunc("/user", func(p router.Party) {
				//后台之 user管理
				p.Post("/deletes",controllers.Deletes).Name = "user deletes"
				p.Post("/delete",controllers.Delete).Name = "user delete"
				p.Post("/update",controllers.Update).Name = "user update"
				p.Get("/edit",controllers.Edit).Name = "user edit"
				p.Get("/assign",controllers.Assign).Name = ""
				p.Post("/doAssign",controllers.DoAssign).Name = ""
				p.Post("/dounAssign",controllers.DounAssign).Name = ""
				p.Post("/insert",controllers.Insert).Name = ""
				p.Post("/add",controllers.Add).Name = ""
				p.Post("/pageQuery",controllers.PageQuery).Name = ""
				p.Post("/Index",controllers.Index).Name = ""
				p.Post("/Index1",controllers.Index1).Name = ""
			})
		}
	}
}

在上一文章中说到iris没有采用mvc的模式,所有路由这里都是采用方法 当做 handle,通过party 来进行分组。
需要特别注意的是: 加入的权限管理中间件的加载

	casbin := middleware.InitCasbin()
			casbinMiddleware := middleware.New(casbin)               //casbin for xorm
			back.Use(middleware.JWTMiddleware().Serve,casbinMiddleware.ServeHTTP) //登录验证

在那个party下加载,那么这个party 下的所有请求,都会受到权限验证的操作。

3. 贴出login 和logout 的代码,供参考

1. login

var (
		loginAcct = ctx.FormValue("loginAcct")
		password = ctx.FormValue("userPsWd")
	)
	loginers:= models.User{
		LoginAcct: loginAcct,
		UserPsWd: password,
	}
	login, err := dao.QueryLogin(&loginers)
	if err != nil{
		ctx.JSON(models.AJAXResult{
			Success: false,
			Msg: "error",
		})
		return
	}
	if login.Id == 0 {
		ctx.JSON( models.AJAXResult{
			Success: false,
		})
		return
	} else {
		// 账号密码正确,得到用户
		token := jwt.NewTokenWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
			"exp": time.Now().Add(time.Hour * time.Duration(1)).Unix(),
			"iat": time.Now().Unix(),
		})
		tokenString, _ := token.SignedString([]byte("HS2JDFKhu7Y1av7b"))

		oauthToken := new(dao.OauthToken)
		oauthToken.Token = tokenString
		oauthToken.UserId = login.Id
		oauthToken.Secret = "secret"
		oauthToken.Revoked = false
		oauthToken.ExpressIn = time.Now().Add(time.Hour * time.Duration(1)).Unix()

		response := oauthToken.OauthTokenCreate()

		ctx.JSON(models.AJAXResult{
			Success: true,
			Data: response,
		})
		return

在整个代码代码中,因为我比较懒,没有写service 模式,直接调用dao 中的方法,但是有个区别就是jwt是采用的结构体的方法-----相当于每一个用户都会创建一个oauthToken 的结构体实例,调用结构体中方法,去验证token 和创建token保存到数据库中。

4. logout

userId, _ := strconv.Atoi(ctx.FormValue("userId"))
	ot := dao.OauthToken{}
	ot.UpdateOauthTokenByUserId(userId)

	ctx.JSON(models.AJAXResult{
		Success: true,
		Msg: "user exit",
	})

当退出,调用dao中的方法,删除数据库保存的token

4. casbin

通过查看手册,可以看到基本的操作逻辑和实现的方法,直接贴代码


func InitCasbin() *casbin.Enforcer {

	a, _ := xormadapter.NewAdapterByEngine(configs.Engine)
	e, _ := casbin.NewEnforcer("./rbac_model.conf", a)
	_ = e.LoadPolicy()
	// Check the permission.
	// Modify the policy.
	// e.AddPolicy(...)
	// e.RemovePolicy(...)

	// Save the policy back to DB.
	e.SavePolicy()

	return e
}

func New(e *casbin.Enforcer) *Casbin {
	return &Casbin{enforcer: e}
}

// 判断token
func (c *Casbin) ServeHTTP(ctx context.Context) {
	value := ctx.Values().Get("jwt").(*jwt.Token)
	token := dao.OauthToken{}
	token.GetOauthTokenByToken(value.Raw) //获取 access_token 信息
	if token.Revoked || token.ExpressIn < time.Now().Unix() {
		//无权限
		ctx.StopExecution()
		return
	} else if !c.Check(ctx.Request(), strconv.FormatUint(uint64(token.UserId), 10)) {
		// Status Forbidden
		ctx.StopExecution()
		return
	} else {
		ctx.Values().Set("auth_user_id", token.UserId)
	}
	ctx.Next()
}

// Casbin is the auth services which contains the casbin enforcer.
type Casbin struct {
	enforcer *casbin.Enforcer
}

// Check checks the username, request's method and path and
// returns true if permission grandted otherwise false.
func (c *Casbin) Check(r *http.Request, userId string) bool {
	method := r.Method
	path := r.URL.Path
	ok, _ := c.enforcer.Enforce(userId, path, method)
	return ok
}

通过上述直接贴代码的方法,能更好的作为我学习笔记吧

注意事项

一定注意导入的依赖 是一致性的
例如iris,就存在两个版本,一个github一个xorm官网。
其他中间件也分为 v2 等两个版本,相互之间,版本依赖不是互通的。

github地址 只写了登录,退出,user管理,但是架构已经搭起来,可供于参考

你可能感兴趣的:(GO)