云原生学习路线导航页(持续更新中)
本文是 golang语言系列 文章,主要对编程通用技能 Authentication、OAuth、JWT 认证策略 进行学习
1.Basic Authentication认证
- 每个请求都需要将 用户名+密码 进行base64编码后,放在请求头的Authorization中,携带到服务端,实现HTTP基本认证
- HTTP明码传输,不安全。一般会用HTTPS传输
- HTTPS 在 HTTP 基础上面添加了 SSL 安全证书。但如果有人伪造CA证书,也可能造成不安全,用户名和密码直接放在请求里,太不安全了
2.OAuth认证
-
OAuth(Open Authorization)是一个用于授权的开放网络标准,允许用户授权第三方应用去访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容。
-
目前主流的 第三方应用登陆,都是使用OAuth标准做的
-
OAuth标准目前大多使用2.0版本
-
OAuth2.0授权模式(授权码模式和密码模式比较常用)
- 授权码模式(authorization code)
- 简化模式(implicit)
- 密码模式(resource owner password credentials)
- 客户端模式(client credentials)
-
更多知识学习博客
- OAuth2.0协议流程与授权模式、协议流程
- http基本认证Authentication OAuth JWT
3.JWT认证
3.1.JWT是什么
- JSON Web Token (JWT) 是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。
- 本质上来说,jwt 就是规定了一种token的格式,按照 jwt 标准生成的 token,包含3部分:header、playload、signature,每一部分都有自己的功能,因此这种token自身就携带了多种特性。
3.2.JWT的3个组成部分
- JWT包含3部分:
- header
- 头部,公开的,表示这是jwt的数据。这部分会使用base64url编码,会把编码成base64后的数据中的 “+、=、/” 替换掉,这样就可以把jwt生成的token拼接在 请求的url 参数上,用于浏览器禁止cookie时使用
- playload
- 有效载荷,可以携带一些数据,但是不要放私密数据。这部分都是base64编码,可以解密,相当于明文
- signature
- 验证签名,是用来验证发送者的JWT,同时也能确保客户端传来的JWT没有被篡改
- signature 如何鉴别客户端带过来的Token是正确的?
- signature 是 服务端在生成token时,使用 密钥secret,对header+playload进行加密,得到的验证签名。
- 如果 下一次请求带来的token,拿着header+playload再次进行密钥加密,得到的signature不同,说明 数据被别人篡改了。如果加密后值相等,说明没有篡改。
- header
- 因此,JWT标准生成的Token,实际上并不是安全的,内部都使用base64编码,也相当于明文,但是有
signature
判断数据是否被修改过
3.3.JWT的优缺点
- JWT优点:
- json的通用性,所以JWT是可以进行跨语言支持的。很多语言都可以使用 json 传输
- 有了payload部分,所以JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息。
- 便于传输,jwt的构成非常简单,字节占用很小
- 不需要在服务端保存会话信息, 所以它易于应用的扩展,不用考虑服务器之间的同步问题
- JWT缺点:
- 不应该在jwt的payload部分存放敏感信息,因为该部分是客户端可解密的部分。
- 一定得保护好服务端的secret私钥,该私钥非常重要。
3.4.使用 JWT + Redis 验证用户信息的过程
- 在用户登陆成功时,服务端使用 JWT 的密钥,为该用户生成一个token。把userId存入载荷中,将token返回给前端。同时,我们会在redis中维护一个Hash表,键为token值,值为user的从数据库中查到的详细信息。
- 下次用户再访问其他资源的时候,将token以
cookie
、请求头的Authorization字段
或url参数
的 方式一起发给服务端。 - 服务端中,我们会在网关Gateway验证用户的登录状态。
- 从request中取出token,使用 jwt 密钥尝试解密,如果发现 token 的 header+playload 再次加密后得到的 signature 与 token 中的 signature不再一样,说明数据被篡改了,就会拒绝服务
- 如果验证通过,就会从载荷中取出我们事先放入的userId,将userId存到请求中,再把该请求放行。
- 后续如果需要使用用户的详细信息,直接从请求头中获取userId,就可以到redis中查到详细信息。