文章目录
##理论知识
前言:本人承诺,本文是在查阅了大量资料并且实践了之后的用心写作。
###Token
理论参考: SSO单点登录使用token机制来验证用户的安全性
###JWT
JWT: 官网
每次您使用令牌对用户进行身份验证时,您的服务器必须验证令牌是否使用您的密钥签名。
摘要:
什么时候应该使用JSON Web令牌?
以下是JSON Web Tokens有用的一些场景:
- 如果你的用户数据可能需要和第三方共享,或者允许第三方调用 API 接口,用 Token 。
- 身份验证:这是使用JWT最常见的情况。一旦用户登录,每个后续请求都将包含JWT,允许用户访问该令牌允许的路由,服务和资源。单点登录是当今广泛使用JWT的一项功能,因为它的开销很小,并且能够轻松地跨不同域使用。
- 信息交换:JSON Web令牌是在各方之间安全传输信息的好方法。因为JWT可以签名 - 例如使用公钥/私钥对,所以可以确定发件人是他们自称的人。此外,由于使用标头和有效载荷计算签名,因此您还可以验证内容是否未被篡改。
- Cookie配合Session的机制,使得服务端维护”状态“,这与现在无状态后台设计思路相悖,比如RESTful设计,鼓励无状态;Session的存在也使得后端服务负载均衡相对麻烦,session粘连或者session复制都不是特别好的方案,个人觉得中小型项目,JWT配合RESTful相当方便。[4]
什么是JSON Web令牌结构?
在紧凑的形式中,JSON Web Tokens包含三个由点(.)分隔的部分,它们是:
Header(头)
Payload(有效载荷)
Signature(签名)
因此,JWT通常看起来如下所示。
xxxxx.yyyyy.zzzzz
代码形式解释生成token:
String base64Header = Base64.encodeBase64URLSafeString(header.getBytes());
String base64Claim = Base64.encodeBase64URLSafeString(claim.getBytes());
String signature = ShaUtil.Hmacsha256(base64Header + "." + base64Claim, secret);
String jwt = base64Header + "." + base64Claim + "." + signature;
hearder:
令牌的类型,即JWT和正在使用的散列算法,如HMAC SHA256或RSA。
{
“alg”: “HS256”,
“typ”: “JWT”
}
然后,这个JSON被Base64Url编码,形成JWT的第一部分。
源码为:
String header = Base64.encodeBase64URLSafeString(this.headerJson.getBytes(StandardCharsets.UTF_8));
Payload
令牌的第二部分是包含声明的Payload。声明是关于实体(通常是用户)和其他元数据。有三种类型的申明:
registered, public,private claims.
- registered:
这些是一组预先定义的申明,这些申明不是强制性的,但建议提供一套有用的,可互操作的申明。其中一些是: iss(发行者), exp(到期时间), sub(用户是谁), scope(这个用户可以做什么)等.- 公共的声明 :
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.- 私有的声明 :
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。
然后将有效载荷Base64Url编码以形成JSON Web令牌的第二部分。
源码为:
String payload = Base64.encodeBase64URLSafeString(this.payloadJson.getBytes(StandardCharsets.UTF_8));
请注意,对于已签名的令牌,此信息尽管受到篡改保护,但任何人都可以阅读。除非加密,否则不要将秘密信息放在JWT的有效内容或标题元素中。
Signature
base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。
##干货
###如何存储token,前后端如何用token进行“交流”
1.html5存储:localStorage or sessionStorage (Web Storage)
1.后端将token通过response返回,像这样:
HTTP/1.1 200 OK { "token": "eyJhbGciOiJIUzI1NiIsI.eyJpc3MiOiJodHRwczotcGxlL.mFrs3Zo8eaSNcxiNfvRh9dqKP4F1cB", "expires_in":3600 }
2.然后前端存储,像这样:
function tokenSuccess(err, response) { if(err){ throw err; } $window.sessionStorage.accessToken = response.body.token; }
3.请求api时,将访问令牌传回给受保护的API ( 我们需要使用HTTP Authorization 头和Bearer 模式):
HTTP/1.1 GET /****/**** Host: *****.com Authorization: Bearer eyJhbGciOiJIUzI1NiIsI.eyJpc3MiOiJodHRwczotcGxlL.mFrs3Zo8eaSNcxiNfvRh9dqKP4F1cB
2.放置cookies中
1.后端通过response 的 Set-Cookie传回token
HTTP/1.1 200 OK Set-Cookie: access_token=eyJhbGciOiJIUzI1NiIsI.eyJpc3MiOiJodHRwczotcGxlL.mFrs3Zo8eaSNcxiNfvRh9dqKP4F1cB; Secure; HttpOnly;
2.做请求时,浏览器会自动包含cookie值
两种方式比较:
相同点:都是无状态的,因为api所需要的验证信息都在token中
不同点:
1.前者可使用跨站点脚本(XSS)进行攻击,cross-site scripting (XSS) attacks。所以,Web存储在传输过程中不执行任何安全标准。
2.Cookie与HttpOnly cookie标志一起使用时,不能通过JavaScript访问