作者:林冠宏 / 指尖下的幽灵

掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8

博客:http://www.cnblogs.com/linguanh/

GitHub : https://github.com/af913337456/

腾讯云专栏: https://cloud.tencent.com/developer/user/1148436/activities


一个基础性、模块完整且安全可靠的服务端框架

开源地址:https://github.com/af913337456/XGoServer

第一版介绍文章:基于 xorm 的服务端框架 XGoServer


新添加模块

  • 自定义路由接口
  • Token模块,jwt
  • 加解密模块,cipher-AES,可自行拓展其他
  • 各模块对应的单元测试例子

共具备的

  • 自定义路由接口
  • Token模块,jwt
  • 加解密模块,cipher-AES,可自行拓展其他
  • 日志模块,alecthomas/log4go
  • 路由模块,gorilla/mux
  • 硬存储 / 软存储 采用 xorm 框架
  • 服务端通用的输出数据结构的整合,例如 json
  • 各模块对应的单元测试例子

自定义路由接口

requireToken 标识该路由是否需要 token 验证

TokenData 是我们要组合到 token 里面的数据结构 struct

type Context struct {
TokenData TokenData
TokenStr string `json:"tokenStr"`
IpAddress string `json:"ipAddress"` // client 的 ip
RoutePath string `json:"routePath"`
}
type XHandler struct {
handleFunc func(*Context, http.ResponseWriter, *http.Request)
requireToken bool
}
func (x XHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
tokenStr := r.Header.Get(TokenAuth)
c := &Context{}
c.IpAddress = util.GetIpAddress(r)
c.RoutePath = r.URL.Path
if x.requireToken {
tokenData,err := ParseToken(tokenStr) // 使用 token 模块进行解析
if err != nil {
util.RenderJson(w,util.GetCommonErr(err.Error()))
return
}
c.TokenData = *tokenData
c.TokenStr = tokenStr
// util.RenderJson(w,c)
x.handleFunc(c,w,r)
return
}
// 不需要 token
util.LogInterface(c)
x.handleFunc(c,w,r)
}

用法

  • router.Handle("/get1",core.ApiNormalHandler(getToken)).Methods("GET")
  • router.Handle("/get2",core.ApiRequestTokenHandler(handleToken)).Methods("GET")
  • 搭配使用:
router.Handle("/getToken",core.ApiNormalHandler(getToken)).Methods("GET")
router.Handle("/handleToken",core.ApiRequestTokenHandler(handleToken)).Methods("GET")
router.HandleFunc("/enc",encOutput).Methods("GET")
router.HandleFunc("/dec",decOutput).Methods("POST")

例子集合

  • 直接输出一条 json 给客户端
  • 登陆成功生成 token 返回
  • 直接输出解析后的 Context
  • 加密输出
  • 与数据库交互 ----- important

直接输出一条 json 给客户端

func main()  {
router := new (mux.Router)
router.HandleFunc("/",test2).Methods("GET")
core.HttpListen(router)
}
func test2(w http.ResponseWriter,r *http.Request) {
// 非常简单的例子, 操作放在内部 , 可以使用 request 来获取自己的参数,再直接组织输出
core.HandlerMapWithOutputJson(w, func() map[string]interface{} {
m := map[string]interface{}{}
m["msg"] = "blow me a kiss"
return m
})
}
// 结果 : {"msg":"blow me a kiss"}

登陆成功生成 token 返回

token 是具备过期时间的,皆可自定义

func getToken(c *core.Context, w http.ResponseWriter, r *http.Request)  {
core.HandlerMapWithOutputJson(w, func() map[string]interface{} {
tokenStr,err := core.BuildDefaultToken(func(tokenData *core.TokenData) {
tokenData.UserId = "123456" // 用户 id
tokenData.Roles = "normal" // 用户角色
})
if err != nil {
return util.GetCommonErr(err.Error())
}
return util.GetCommonSuccess(tokenStr)
})
}
结果:
{
"msg": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiMTIzNDU2Iiwicm9sZXMiOiJub3JtYWwiLCJwcm9wcyI6bnVsbCwiZXhwIjoxNTE5MDA2Njg4LCJpYXQiOjE1MTkwMDY2Mjh9.NsBsQ3xpOJNZUXO5Dc-Yk4p4m6p4EeDWgEfc5BaNKd4",
"ret": "success"
}

直接输出解析后的 Context

tokenStr 是 Context 一变量

handleToken 方法对于的是 ApiRequestTokenHandler

func handleToken(c *core.Context, w http.ResponseWriter, r *http.Request)  {
util.RenderJson(w,context)
}

输出加密的数据

tokenStr 是 Context 一变量

handleToken 方法对于的是 ApiRequestTokenHandler

type IEncrypt interface {
AesEncrypt(origData, key []byte) ([]byte, error) // 加密
AesDecrypt(encrypted, key []byte) ([]byte, error) // 解密
}
// 加密输出
func encOutput(w http.ResponseWriter, r *http.Request) {
core.HandlerMapWithOutputJson(w, func() map[string]interface{} {
d := "狗年平安"
aes := encrypt.DefaultAES{}
return util.GetCommonSuccess(aes.AesEncryptStr(d))
})
}
输出:
{
"msg": "\ufffd\u0002\ufffd\u001eu\ufffd\u001c\ufffd\u0013m\ufffdM\\\ufffd\ufffd\u0011",
"ret": "success"
}

与数据库交互

func test3(w http.ResponseWriter,r *http.Request)  {
core.HandlerMapWithOutputJson(w, func() map[string]interface{} {
// 插入一条评论
item := &model.Comment{
Id :util.NewId(), // 评论 id
UserId :"123456", // 评论人 id
Name :"LinGuanHong", // 评论人名称
Content :"hello word", // 评论内容
}
affect,_ := core.Engine.Insert(item) // 执行插入,传入 struct 引用
m := map[string]interface{}{}
if affect > 0 {
m["ret"] = "insert success"
comments := make([]model.Comment, 0)
core.Engine.Find(&comments) // select 出来,获取所有评论输出
m["msg"] = comments
}else{
m["ret"] = "insert failed"
}
return m
})
} 输出的结果是:
{
"msg": [
{
"id": "1kubpgh9pprrucy11e456fyytw",
"UserId": "123456",
"name": "LinGuanHong",
"content": "hello word"
}
],
"ret": "insert success"
}

上述的功能结合使用,便可做到牢固的安全性。此外,可以再结合 https 级别的路由使用。

XGoServer 一个基础性、模块完整且安全可靠的服务端框架的更多相关文章

  1. 基于 xorm 的服务端框架 XGoServer

    作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.cnblogs.com/linguan ...

  2. 无框架完整搭建安卓app及其服务端(一)

    技术背景: 我的一个项目做的的是图片处理,用 python 实现图片处理的核心功能后,想部署到安卓app中,但是对于一个对安卓和服务器都一知半解的小白来说要现学的东西太多了. 而实际上,我们的项目要求 ...

  3. 一个3D的多人在线游戏, 服务端 + 客户端 【转】

    最近学院组织了一个实训,要求是利用Socket通信和D3D的知识, 写一个多人在线的游戏, 服务端是在linux下, 客户是在Windows下: 写这个的目的是想让大家给我找错, 欢迎大家的意见.我的 ...

  4. 基于NIO的同步非阻塞编程完整案例,客户端发送请求,服务端获取数据并返回给客户端数据,客户端获取返回数据

    这块还是挺复杂的,挺难理解,但是多练几遍,多看看研究研究其实也就那样,就是一个Selector轮询的过程,这里想要双向通信,客户端和服务端都需要一个Selector,并一直轮询, 直接贴代码: Ser ...

  5. 用.Net打造一个移动客户端(Android/IOS)的服务端框架NHM(四)——Android端Http访问类(转)

    本章目的 在上一章中,我们利用Hibernate Tools完成了Android Model层的建立,依赖Hibernate Tools的强大功能,自动生成了Model层.在本章,我们将继续我们的项目 ...

  6. qq2013 java版(完整工程源码 包含服务端 oracle数据库)毕业设计有用

    /** * 初始化组件 */ private void initComponent() { //提示面板 errorTipPane = new ErrorTipPane(); // 主面板 mainP ...

  7. 适合新手:从零开发一个IM服务端(基于Netty,有完整源码)

    本文由“yuanrw”分享,博客:juejin.im/user/5cefab8451882510eb758606,收录时内容有改动和修订. 0.引言 站长提示:本文适合IM新手阅读,但最好有一定的网络 ...

  8. 【翻译】DotNetMQ: 一个.NET版完整的消息队列系统

    在一个大型的分布式系统中,消息队列是不可缺少的中间件,能很好的解决异步消息.应用解耦.均衡并发等问题.在.net中,偶然发现一个效率不错.安全可靠.功能齐全的消息组件,忍不住翻译过来,供大家快速预览. ...

  9. IIS 错误:处理程序“PageHandlerFactory-Integrated”在其模块列表中有一个错误模块“ManagedPipelineHandler”

    导致这种问题的原因是ASP.NET没有成功注册到IIS中,很有可能是先安装.Net Framework,然后安装IIS.为了避免此问题发生,要先安装IIS再安装.Net Framework. 解决方案 ...

随机推荐

  1. 分布式监控系统--zabbix

    1Zabbix简介 Zabbix 是一个企业级的分布式开源监控方案. 2.监控系统架构 C/S架构 客户端/服务器端,这种架构适合规模较小,处于同一地域的环境 C/P/S 客户端/代理端/服务器端/, ...

  2. [国嵌攻略][104][Linux内核模块设计]

    内核模块示例 #inlcude <linux/init.h> #inlcude <linux/module.h> static int hello_init(){ printk ...

  3. Navicat连接阿里云Mysql遇到的的坑

    连上去那一刻,心态真是起飞了

  4. input事件中文触发多次问题研究

    我们在网页中经常会遇到实时搜索的情况,或者其他类似需要input实时响应的问题,一般情况下,我们是利用input和propertychange事件来监听input内容的变化来响应,但是有一个问题就是当 ...

  5. 用dedecms做网站时,空间服务器选择IIS还是apache???

    想做一个dedecms程序的网站,不知道要选择什么样的空间,windows还是linux的?多大的空间比较适合?求高人回答.   如果是基于Linux平台的话,那不必多说自然是Apache了,因为II ...

  6. Java中的对象Object方法之---wait()和notifiy()

    这一篇咋们继续,接着来介绍wait()和notify()方法,我们都知道这两个方法和之前介绍的方法不太一样,那就是这两个方法是对象Object上的,不属于Thread类上的.我们也知道这两个方法是实现 ...

  7. tomcat 部署war项目

    前提是 jdk环境已配好 把项目war包放到tomcat的webapps目录下 启动tomcat: 这里我把8080端口修改成了80 IP也修改了 如果没修改直接输入localhost:8080/te ...

  8. mysql-SQL优化总结

    1.查询首先考虑在where和order by设计的列上建立索引,尽量避免全表扫描. 2.尽量避免在where子句中对字段进行null值判断,否则将导致引擎放弃使用索引而进行全表扫描. select ...

  9. The server's host key is not cached in the registry. You have no guarantee that the server……

    使用putty中的pscp.exe ,可以通过脚本方式实现windows向linux上传文件,但pscp.exe第一次运行时必须手工输入确认信息,本文主要解决掉初次运行时的人工交互,彻底实现静默运行. ...

  10. linkin大话数据结构--字符串,数组,list之间的互转

    在实际开发中,我们经常会用到字符串,字符数组,字符list,当然也会不可避免的进行这3者之间的互相转换. 在使用到Apache和Google下的common包,可以这样子实现: package tz. ...