在实际项目中一般会使用jwt鉴权方式。
jwt,全称json web token ,JSON Web令牌是一种开放的行业标准RFC 7519方法,用于·在两方安全地表示声明。具体网上有许多文章介绍,这里做简单的使用。
JSON Web Token 由三部曲组成,他们之间用圆点 .进行分割,一个标准的JWT形如xxx.yyy.zzz
头部,由两部分组成;token的类型( JWT)和算法名称(HMAC 、SHA256、RSA......)。
实例:
- {
- "alg": "HS256"
- "typ": "JWT"
- }
然后通过Base64对这个JSON编码就得到JWT得第一部分
第二部分具体得实体,可以写入自定义的数据信息,有三种类型
实例:
- {
- "iss": "加油",
- "exp": 182309645,
- "uname": "妮甲"
- }
对payload进行Base64编码就得到JWT的第二部分
为了得到签名部分,你必须有编过码的header、编过码的payload、一个密钥,签名算法是header中指定的那个,然后对他们签名即可
签名是用于验证消息在传递过程中有没有被更改,并且,对于使用私钥签名的token,它还可以验证JWT的发送方式是否为它所称的发送方式。
下面给出一个基于java-jwt生成的具体实例
- public static void main(String[] args){
-
- String token = JWT.create().withIssuer("加油").withExpiresAt(new Date(System.currentTimeMillis() + 86400_000))
- .withPayload(MapUtils.create("uname" , "妮甲" ))
- .sign(Alogorithm.HMAC256("helloWorld"));
-
- System.out.println(token);
-
-
- }
一个简单的基于jwt的身份验证方案如下图
基本流程分三步:
说明:项目采用session的方案,将jwt写入到coolik中
接下来看在技术派中的实际使用场景,核心逻辑在
我们直接在之前session的基础上进行优化,这里主要借助开源项目java-jwt来实现JWT的生成管理
我们定义了签发者、有效期,指定了签名算法,然后实体类中,携带两个信息
上面的实现中,有几个通用的成员属性,我们通过自定义的配置,再启动项目时进行初始化,避免后续的重复创建
自定义的jwt三个配置属性
- paicoding:
- jwt:
- issuer: pai_coding #签发者
- secret:hello_world #签名密钥
- expire: 2592000000 #jwt有效期 ,默认30天
用户每次请求时,依然是沿用之前的session方式的校验逻辑,在Filter层,从请求头中,获取Cookie,找到对应的jwt,然后尝试根据jwt获取对应的用户信息。
注意上面的实现,即便是jwt校验通过了,我们也依然从redis中查了一下,判断是否有效
为啥这样设计?
因为jwt本身无状态,后端完全可以将redis这一层的存储都直接干掉,纯依赖jwt的特性来完成身份鉴权,但由于它的无状态,后端减少存储压力是一个好处,同样也是一个弊端,后端失去了token的管控权,如果我们希望提前失效某些用户身份,则无法持续,鉴于此,这里依然保留了redis中存储jwt的方案。
接下来我们实际体验一下,线上运行技术派的jwt,登录之后,找到一个请求,找到cookie中的f-session
我们解析一下这个是啥?
站在用户的角度,说实话你用session还是jwt,没啥实质的感受差异,那为啥还有两种不同的技术方案?
jwt | session |
前端存储,通用的校验规则,后端再获取jwt时校验是否有效 | 前端存索引,后端判断session是否有效 |
验签,不可篡改 | 无签保障,安全性有后端保障 |
可存储非敏感信息,如头像,用户名 | 一般不存储业务信息 |
jwt生成时,指定了有效期,本身不支持续期以及提前失效 | 后端控制有效期,可提前失效或者自动续期 |
通常以请求头方式传递 | 通常以cookie方式传递 |
可预防csrf攻击 | session-cookie方式存在csrf风险 |
注:csrf攻击
如在网站页面上,添加如下内容
然后当你访问此网站时,结果发现你在技术派上登录的用户被注销啦
使用jwt预防csrf攻击的主要原理就是jwt通过请求头,由js主动塞进去传递给后端,而非cookie的方式,从而避免csrf漏洞攻击,技术派的jwt也是采用cookie进行携带jwt,并不能解决上面这个个问题;同样,session方案,也可以将sessionId通过请求头的方式传递,按照这个说法也能避免csrf。
通常的方案由;
session-cookie方案
jwt-requestHeader方案
。