一、开启https支持
做法:在engine中添加RunTLS方法
测试:(密码123456)
-
生成私钥文件:
openssl genrsa -des3 -out my.key 2048
-
创建证书请求:
openssl req -new -key my.key -out my.csr
-
生成csr文件:
bash openssl x509 -req -days 365 -in my.csr -signkey my.key -out my.crt
-
同级目录下加入openssl.cnf修改文件内容如下
[ v3_req ] subjectAltName = @alt_names [ alt_names ] IP.1 = 127.0.0.1 DNS.1 = *.zy.com DNS.2 = *.org.zy.com
-
生成证书私钥server.key:
openssl genpkey -algorithm RSA -out server.key
-
通过server.key生成证书请求文件
server.csr:openssl req -new -nodes -key server.key -out server.csr -days 3650 -config ./openssl.cnf -extensions v3_req
-
生成SAN证书:
sudo openssl x509 -req -days 365 -in server.csr -out server.pem -CA my.crt -CAkey my.key -CAcreateserial -extfile ./openssl.cnf -extensions v3_req
-
客户端生成私钥:
openssl genpkey -algorithm RSA -out client.key
-
客户端生成证书:
openssl req -new -nodes -key client.key -out client.csr -days 3650 -config ./openssl.cnf -extensions v3_req
-
客户端生成SAN证书:
sudo openssl x509 -req -days 365 -in client.csr -out client.pem -CA my.crt -CAkey my.key -CAcreateserial -extfile ./openssl.cnf -extensions v3_req
二、认证支持
1.基础认证
1.1介绍
Basic 认证(基础认证),是最简单的认证方式。它简单地将用户名:密码进行 base64 编码后,放到 HTTP Authorization Header 中。HTTP 请求到达后端服务后,后端服务会解析出 Authorization Header 中的 base64 字符串,解码获取用户名和密码,并将用户名和密码跟数据库中记录的值进行比较,如果匹配则认证通过。
当然base64并不是加密技术,所以这种认证方式并不安全,即使密码进行加密,攻击者也可以进行重放攻击。
1.2流程
- 给ctx加入名为Keys的map[string]any作为负载信息的结构,同时加入Set和Get方法
- 实现中间件,在执行业务之前,鉴权
1.3代码
1.4效果
2.摘要认证
Digest 认证(摘要认证),是另一种 HTTP 认证协议,它与基本认证兼容,但修复了基本认证的严重缺陷。Digest 具有如下特点:
- 绝不会用明文方式在网络上发送密码。
- 可以有效防止恶意用户进行重放攻击。
- 可以有选择地防止对报文内容的篡改。
完成摘要认证需要下面这四步:
- 客户端请求服务端的资源。
- 在客户端能够证明它知道密码从而确认其身份之前,服务端认证失败,返回401Unauthorized,并返回WWW-Authenticate头,里面包含认证需要的信息。
- 客户端根据WWW-Authenticate头中的信息,选择加密算法,并使用密码随机数 nonce,计算出密码摘要response,并再次请求服务端。
- 服务器将客户端提供的密码摘要与服务器内部计算出的摘要进行对比。如果匹配,就说明客户端知道密码,认证通过,并返回一些与授权会话相关的附加信息,放在Authorization-Info 中。
虽然使用摘要可以避免密码以明文方式发送,一定程度上保护了密码的安全性,但是仅仅隐藏密码并不能保证请求是安全的。因为请求(包括密码摘要)仍然可以被截获,这样就可以重放给服务器,带来安全问题。
为了防止重放攻击,服务器向客户端发送了密码随机数 nonce,nonce 每次请求都会变化。客户端会根据== nonce ==生成密码摘要,这种方式,可以使摘要随着随机数的变化而变化。服务端收到的密码摘要只对特定的随机数有效,而没有密码的话,攻击者就无法计算出正确的摘要,这样我们就可以防止重放攻击。
摘要认证可以保护密码,比基本认证安全很多。但摘要认证并不能保护内容,所以仍然要与 HTTPS 配合使用,来确保通信的安全。
3.令牌认证
3.1介绍
Bearer 认证,也称为令牌认证,是一种 HTTP 身份验证方法。Bearer 认证的核心是 bearer token。bearer token 是一个加密字符串,通常由服务端根据密钥生成。客户端在请求服务端时,必须在请求头中包含Authorization: Bearer 。服务端收到请求后,解析出 ,并校验 的合法性,如果校验通过,则认证通过。跟Basic认证一样,Bearer 认证需要配合 HTTPS 一起使用,来保证认证安全性。
当前最流行的 token 编码方式是 JSON Web Token
3.2JWT
3.2.1简介
JWT(全称:Json Web Token)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。
简单点说就是一种认证机制。
JWT一般是这样一个字符串,分为三个部分,以"."隔开:
A.B.C
Header-A部分:
JWT第一部分是头部分,它是一个描述JWT元数据的Json对象
{
“alg”: “HS256”,
“typ”: “JWT”
}
alg属性表示签名使用的算法,默认为HMAC SHA256(写为HS256),typ属性表示令牌的类型,JWT令牌统一写为JWT。
最后,使用Base64 URL算法将上述JSON对象转换为字符串保存。
Payload-B部分:
JWT第二部分是Payload,也是一个Json对象,除了包含需要传递的数据,还有七个默认的字段供选择。
分别是
iss:发行人、exp:到期时间、sub:主题、aud:用户、nbf:在此之前不可用、iat:发布时间、jti:JWT ID用于标识该JWT。
{
//默认字段
“sub”:“Go手写微服务框架教程”,
//自定义字段
“name”:“go框架”,
“isAdmin”:“true”,
“loginTime”:“2022-06-28 12:00:03”
}
这部分是可以被解密的,并不安全,所以不要存敏感信息。
使用Base64 URL算法转换为字符串保存
Signature-C部分:
JWT第三部分是签名。
首先需要指定一个secret,该secret仅仅保存在服务器中,保证不能让其他用户知道。然后使用Header指定的算法对Header和Payload进行计算,然后就得出一个签名哈希。也就是Signature。
- 那么Application Server如何进行验证呢?
可以利用JWT前两段,用同一套哈希算法和同一个secret计算一个签名值,然后把计算出来的签名值和收到的JWT第三段比较,如果相同则认证通过。
使用JWT进行认证的步骤:
- 客户端使用用户名和密码请求登录
- 服务端收到请求后,会去验证用户名和密码。如果用户名和密码跟数据库记录不一致,则验证失败;如果一致则验证通过,服务端会签发一个 Token 返回给客户端
- 客户端收到请求后会将 Token 缓存起来,比如放在浏览器 Cookie 中或者 LocalStorage 中,之后每次请求都会携带该 Token
- 服务端收到请求后,会验证请求中的 Token,验证通过则进行业务逻辑处理,处理完后返回处理后的结果。
3.2.2token的签发实现
- 由调用者指定认证方法,返回data(map[string]any)的信息
- A部分:指定Alg加密方法,获得签名方法,利用签名方法创建令牌
- B部分:从token中拿到与B部分有关的claims,将data的信息加入B部分,设置签发时间和过期时间
- C部分:用token与调用者设定的Key联合获得token字符串,用2中的令牌签发过期时间不同的refreshToken
- 发送到存储cookie
3.2.3token刷新
- 从ctx获得refreshToken的字符串,利用jwt检查tokenstring的合法性,并获得token
- 利用token签发新的令牌,返回jwtResponse
3.2.3token中间件拦截
- 从ctx的Header或是cookie中获得tokenString
- 检验tokenString的有效性
- 以及将token携带的B部分添加到ctx中
- 以上任意部分出错,进行错误处理,不再进行下面的逻辑,返回401