前提知识点
Base64
- 当你有一串[]byte比特流
[147 197 186 115 211 31 19 30 154 217 56 217 164 58 46 16 152 115 32 226]
- 你想看这个比特流,于是你转换成字符串你发现:
?{��$�EL;Q������S```
- 这是因为使用UTF-8(或其他任何编码方式)解码这个比特流时发现部分bytes不能找到对应的字符,于是会使用
�
代替 - ACSII编码方式是最基础的一种编码方式,几乎所有主流编码方式都兼容ASCII
所以:我们把这个bytes流转换为ASCII可解码、编码的bytes流,这样也就可以被其他的编码方式编码、解码了! - 而负责转换的就是base64:主要用于将不可打印的字符转换成可打印字符
- 上述bytes流被base64美化后:
[66 103 43 73 87 117 106 98 112 56 51 105 120 82 85 108 84 99 90 67 90 50 89 81 70 121 52 61]
- 然后打印:
Bg+IWujbp83ixRUlTcZCZ2YQFy4=
Http中的编码
URL编码方式:URL编码
URL只采用ASCII字符集! URL会进行URL编码(百分号编码) 后发送。
请求头
请求头只会保证ASCII字符正常工作,而其他可能出错,所以我们在请求头中定义的数据往往需要Base64编码!
Body编码方式【请求头中Content-Type】
- 表单:application/x-www-form-urlencoded
- 文件:multipart/form-data
- json:application/json
浏览器存储
共同点:
- 都是根据域名分类存储的
- 都是key - value形式存储的
Cookie
- 有过期时间
- 会随浏览器每次请求都携带
本地存储(localStorage)
- 没有过期时间,数据永久保
- 不会随浏览器每次发送
会话存储(sessionStorage)
- 仅当前页面有效一旦关闭就会被释放
- 也不会随浏览器发送给服务器
Session登录策略【SessionID+redis】
Login
- 用户登录产生token【因为token要存在头部 所以要进行】
key := make([]byte, 30)
_, err := rand.Read(key)
SessionID := base64.StdEncoding.EncodeToString(key)
- 存储到redis:key:SessionID value:用户账号
- 返回SessionID给客户端
- 客户端存储到Local Storage 或Session Storage里
- 每次请求将使用Cookie携带SessionID,或者放到请求头(Authorization:SessionID)都可以
- 后端获取SessionID,从redis中查询用户账号,然后进行业务逻辑处理(中间件middleware做)
Logout
- 客户端删除token
- redis中删除token
SSO单点登录
概念: SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。
前提
有一个公司,由多个系统,这些系统相互信任,都使用同一个认证系统(注册、登录):SSO认证中心
Login
注: 在重定向过程中往往会有签名,以保证URL中途不会被篡改。
- 系统1
- 用户请求登录业务系统1
- 回调路径为SSO登录成功后重定向到系统1的路径(Base64编码)
callback := "http:www.baidu.com/callback"
- 生成SSO登录路径
var qs url.Values
qs.Add("callback",callback)
loginURL := SSO.Client.LoginURL + qs.Encode()
loginURL = loginURL + sign(loginURL)//签名算法生成签名
- 302重定向到SSO认证中心(302:临时重定向;301:永久重定向)
c.Redirect(http.StatusFound,loginURL)
- SSO认证中心
- 进行用户登录/注册,生成全局唯一Token,并保存
token:用户账号
key := make([]byte, 30)
_, err := rand.Read(key)
token := base64.StdEncoding.EncodeToString(tokenBytes)
- 解析回调路径
callback
,并携带Token重定向系统1的callback
路径
- 系统1
- 回调路径
callback
利用签名算法验证Token是否有效 - 设置Cookie根域名存放Token
Logout
- 拿着token去用户中心注销
- 删除cookie中的token
JWT实现
就不用在服务器存储token:account
了
- Header
{
'typ': 'JWT',
'alg': 'HS256'
}
- payload
{
"sub": "1234567890",
"account": "John",
"admin": true
}
- signature
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
var signature = HMACSHA256(encodedString, '密钥');
JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ