【Gin-API系列】Gin中间件之鉴权访问(五)
在完成中间件的介绍和日志中间件的代码后,我们的程序已经基本能正常跑通了,但如果要上生产,还少了一些必要的功能,例如鉴权、异常捕捉等。本章我们介绍如何编写鉴权中间件。
鉴权访问,说白了就是给用户的请求增加一些限制条件,过滤掉不符合要求的请求。完善的鉴权模块可以让我们的服务跑得更加安全,特别是面向公共的服务。
常用的无状态鉴权方式
- 网络鉴权
通常有IP白名单方式,通过获取客户端的真实IP来对请求进行过滤
- 用户鉴权
通过账号密码或者分配的密钥、Token等方式进行认证,常用的cookies、oauth2.0都是这种方式
- 加密算法鉴权
客户端使用加密算法对用户的参数进行计算加密得到Token,并将参数和Token一起发送;服务端使用同样的加密算法对请求参数进行加密后比较Token的值是否一致。
Gin-IPs 鉴权访问
为了让我们的服务更加安全,我们通常是混合多种鉴权方式使用。本文采取“用户鉴权”和“加密算法鉴权”混合方式。
- 鉴权算法介绍
通过某种方式生成或者手动指定分配公钥和私钥对给用户,用户使用公钥和请求参数组成消息内容,使用私钥对消息内容进行哈希计算,得到固定长度的字符串。
服务器使用同样的方式对用户请求的参数进行哈希计算后比较。由于这里面的算法和密钥对都是私有的,所以安全性较高,适用于大多数场景。
- 加密代码
// 签名算法如下
/*
Signature = HMAC-SHA1('SecretKey', UTF-8-Encoding-Of( StringToSign ) ) );
StringToSign = method + "\n" +
URL + "\n" +
Sort-UrlParams + "\n" +
Content-MD5 + "\n" + // md5(params)
Expires + "\n" +
AccessKey;
*/
func genSignature(accessKey, secretKey, uri, method, urlParams, params, nowTS string) (string, error) {
if params != "" {
md5Ctx := md5.New()
_, _ = io.WriteString(md5Ctx, params)
params = fmt.Sprintf("%x", md5Ctx.Sum(nil))
}
// HTTP-Verb + "\n" +URL + "\n" +Parameters + "\n" +Content-Type + "\n" +Content-MD5 + "\n" +Date + "\n" +AccessKey;
strSign := method + "\n" + uri + "\n" + urlParams + "\n" + "\n" + params + "\n" + nowTS + "\n" + accessKey
sign := hmacSHA1Encrypt(strSign, secretKey)
return sign, nil
}
// hmacSHA1Encrypt encrypt the encryptText use encryptKey
func hmacSHA1Encrypt(encryptText, encryptKey string) string {
key := []byte(encryptKey)
mac := hmac.New(sha1.New, key)
mac.Write([]byte(encryptText))
var str = hex.EncodeToString(mac.Sum(nil))
return str
}
- Gin鉴权中间件使用
func Validate() gin.HandlerFunc {
return func(c *gin.Context) {
response := route_response.Response{}
response.Data.List = []interface{}{} // 初始化为空切片,而不是空引用
uri := c.Request.URL.Path
contentType := c.Request.Header.Get("Content-Type")
accessKey := c.DefaultQuery("accesskey", "")
expires := c.DefaultQuery("expires", "")
signature := c.DefaultQuery("signature", "")
secret, err := dao.FetchSecret(accessKey)
if err != nil || "valid" != secret.State {
c.Abort()
response.Code, response.Message = configure.RequestKeyNotFound, "无效的Token"
c.JSON(http.StatusUnauthorized, response)
return
}
secretKey := secret.SecretKey
if nowTs, err := strconv.ParseInt(expires, 10, 64); err != nil {
c.Abort()
response.Code, response.Message = configure.RequestParameterTypeError, "有效期参数类型错误"
c.JSON(http.StatusUnauthorized, response)
return
} else {
passTime := time.Now().Unix() - nowTs
if passTime < 0 || passTime >= configure.GinConfigValue.Expires {
c.Abort()
response.Code, response.Message = configure.RequestExpired, "请求已过期"
c.JSON(http.StatusUnauthorized, response)
return
}
}
method := strings.ToUpper(c.Request.Method)
var urlParams, params string
if "POST" == method || "PUT" == method {
body, _ := ioutil.ReadAll(c.Request.Body)
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body)) // 重设body
params = string(body)
} else if "GET" == method || "DELETE" == method {
queryParams := c.Request.URL.Query()
allParams := make(map[string]string)
for k, v := range queryParams {
if k != "accesskey" && k != "expires" && k != "signature" {
allParams[k] = v[0] // 如果某个key传入了2个,只用第一个的值
}
}
keys := getMapKeysSorted(allParams)
for _, k := range keys {
urlParams += k + allParams[k]
}
}
if signatureString, err := genSignature(accessKey, secretKey, uri, method, urlParams, params, expires); err != nil {
c.Abort()
response.Code, response.Message = configure.ApiGenSignatureError, "API内部错误"
c.JSON(http.StatusUnauthorized, response)
return
} else {
if signature != signatureString {
c.Abort()
response.Code, response.Message = configure.RequestAuthorizedFailed, "API认证失败"
c.JSON(http.StatusUnauthorized, response)
return
}
}
c.Next()
}
}
本文关于鉴权访问的介绍和使用到此为止,下一章我们将使用异常捕捉中间件来完善我们的程序。
Github 代码
请访问 Gin-IPs 或者搜索 Gin-IPs
【Gin-API系列】Gin中间件之鉴权访问(五)的更多相关文章
- 微服务从代码到k8s部署应有尽有系列(三、鉴权)
我们用一个系列来讲解从需求到上线.从代码到k8s部署.从日志到监控等各个方面的微服务完整实践. 整个项目使用了go-zero开发的微服务,基本包含了go-zero以及相关go-zero作者开发的一些中 ...
- SpringCloud 2020.0.4 系列之 JWT用户鉴权
1. 概述 老话说的好:善待他人就是善待自己,虽然可能有所付出,但也能得到应有的收获. 言归正传,之前我们聊了 Gateway 组件,今天来聊一下如何使用 JWT 技术给用户授权,以及如果在 Gate ...
- Go+gRPC-Gateway(V2) 微服务实战,小程序登录鉴权服务(五):鉴权 gRPC-Interceptor 拦截器实战
拦截器(gRPC-Interceptor)类似于 Gin 中间件(Middleware),让你在真正调用 RPC 服务前,进行身份认证.参数校验.限流等通用操作. 系列 云原生 API 网关,gRPC ...
- 自定义分布式RESTful API鉴权机制
微软利用OAuth2为RESTful API提供了完整的鉴权机制,但是可能微软保姆做的太完整了,在这个机制中指定了数据持久化的方法是用EF,而且对于用户.权限等已经进行了封装,对于系统中已经有了自己的 ...
- SpringBoot系列: Web应用鉴权思路
==============================web 项目鉴权============================== 主要的鉴权方式有:1. 用户名/密码鉴权, 然后通过 Sess ...
- Go+gRPC-Gateway(V2) 微服务实战,小程序登录鉴权服务(六):客户端基础库 TS 实战
小程序登录鉴权服务,客户端底层 SDK,登录鉴权.业务请求.鉴权重试模块 Typescript 实战. 系列 云原生 API 网关,gRPC-Gateway V2 初探 Go + gRPC-Gatew ...
- # RESTful登录(基于token鉴权)的设计实例
使用场景 现在很多基于restful的api接口都有个登录的设计,也就是在发起正式的请求之前先通过一个登录的请求接口,申请一个叫做token的东西.申请成功后,后面其他的支付请求都要带上这个token ...
- 深入理解k8s中的访问控制(认证、鉴权、审计)流程
Kubernetes自身并没有用户管理能力,无法像操作Pod一样,通过API的方式创建/删除一个用户实例,也无法在etcd中找到用户对应的存储对象. 在Kubernetes的访问控制流程中,用户模型是 ...
- 👮 Golang Gin/Ace/Iris/Echo RBAC 鉴权库
GRBAC 项目地址: https://github.com/storyicon/grbac Grbac是一个快速,优雅和简洁的RBAC框架.它支持增强的通配符并使用Radix树匹配HTTP请求.令人 ...
随机推荐
- 4.9 省选模拟赛 划分序列 二分 结论 树状数组优化dp
显然发现可以二分. 对于n<=100暴力dp f[i][j]表示前i个数分成j段对于当前的答案是否可行. 可以发现这个dp是可以被优化的 sum[i]-sum[j]<=mid sum[i] ...
- 服务治理框架dubbo中zookeeper的使用
Zookeeper提供了一套很好的分布式集群管理的机制,就是它这猴子那个几月层次型的目录树的数据结构,并对书中的节点进行有效的管理,从而可以设计出多种多样的分布式的数据管理模型:下面简要介绍下zook ...
- .net core下获取自身服务器地址
网上的例子千篇一律都是Request.HttpContext.Connect.Connection.XX这种 或者依赖于IHttpContextAccessor的 而我的场景是在非控制器流程获取自身服 ...
- ios迅雷上架成功的秘密 背后的“苹果TF签名”
距离ios迅雷从App Store下架已经过去很久了,小微经常看到知乎里有很多迅雷用户到处寻找可以下载应用的渠道.近期迅雷被爆“好消息”iOS 迅雷(官方版)正式上架 App Store,此消息一出可 ...
- resultMap的用法以及关联结果集映射
resultType resultType可以把查询结果封装到pojo类型中,但必须pojo类的属性名和查询到的数据库表的字段名一致. 如果sql查询到的字段与pojo的属性名不一致,则需要使用res ...
- python的单下划线和双下划线
python 类中的单下划线开头的变量表示:该方法为类的私有方法,原则上外部不能访问,但是用._XX是可以访问到的 双下划线开头则是强制外部不能直接访问的用.__XX是访问不到的,它内部其实是将变量名 ...
- Socket 由浅入深,开发一个真正的通信应用
在说socket之前.我们先了解下相关的网络知识: 端口 在Internet上有很多这样的主机,这些主机一般运行了多个服务软件,同时提供几种服务.每种服务都打开一个Socket,并绑定到一个端口上, ...
- 2020-03-27:JDK1.8中在数据结构上,对HashMap做了什么样的改进?为什么?
福哥答案2020-04-04:头插改尾插,解决链表成环的问题.链表改成链表和红黑树.
- C#开发笔记,点点细微,处处真情,记录开发中的难言之隐
该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/956 访问. 概述 本系列文章将会向大家介绍本人实际开发过程中所遇到技术 ...
- Vuex mapAction的基本使用
mapAction-store中的异步方法 import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new ...