前言:日常项目中很多地方需要用到“用户身份认证”,比较常见的场景就是登陆,接下来本文将对常见场景进行分析并给出基于JWT的实现方案。
一、常见场景
1.1、基于session的认证方案
这种方案在早期项目比较常见,具体实现过程如下:
用户以账号密码登录,服务端对账号密码进行校验,如果通过检验,服务端则生成一个httpsession,其中包含sessionId,服务端会将sessionId写到浏览器cookie中。浏览器发起请求时会将sessionId放在header中,信息将会被带入服务端,服务端根据传入的sessionId与内存中的httpsession对象去比对,如果比对成功,则表明浏览器请求合法。
以上是基于session的认证方案的流程。
优点:
方案比较成熟,早期项目很多都用这种方案,实现起来较为简单。
缺点:
1) 用户信息存储在服务器内存中,用户量大的时候,内存开销会比较大。
2) 扩展性差,用户信息存在某一台服务器上,应用节点会有状态,分布式环境下,无法做到横向无限扩展。
如何解决呢?分布式节点下可以采用session共享的方式,将session信息存储到redis中实现共享。java中可以使用spring-session-data-redis包。
3) 普通的session认证不支持跨域,因为session需要配合cookie才能实现,由于cookie默认不支持跨域访问,当涉及到前端跨域请求后端接口时,需要做很多额外的配置,以springboot为例,需要配置拦截器,在拦截器中配置相关的属性,才能变相实现跨域session认证。
4) 容易被类似的CSRF(跨站请求伪造)攻击,因为是基于浏览器的cookie来进行用户识别的,cookie如果被截获,用户就会很容器受到跨站请求伪造的攻击。
适用场景:单节点部署应用,如果多节点部署情况下使用session共享/负载均衡端会话保持(SLB设置)
1.2、基于JWT认证方案
1)什么是JWT,
JWT(JSON Web Token)是目前最流行的跨域认证解决方案,是一种基于Token的认证授权机制。Token包含用户的认证信息,存储在客户端,不会存储在服务端,因此服务端不需要存储Session信心,增加了系统的可用性和伸缩性,大大减轻了服务端的压力。
2)JWT的格式及组成
Jwt是令牌的token,是一个String字符串,由三部分组成,中间用.隔开,连接在一起就是一个Jwt.token,如下所示:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ。
解释:
JWT令牌组成
标头(Header)
有效载荷(Payload)用来存放实际需要传递的数据,不可存放用户敏感信息,如密码,同样使用Base64编码
签名(Signature)Header和Payload部分使用base64进行编码,前端可以解开并得知里面的信息,Signature需要使用编码后的header和payload加上一个密钥,使用header中指定的签名算法(HS256)进行签名,签名的作用是保证JWT没有被篡改过。
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret);
注意:这里的secret私钥保存在服务端,非常重要,千万不能泄露,建议私钥做成可配置的,定期修改secret的值。
密钥建议存放在动态配置中心,比如nacos。
3)优缺点
优点:
- 跨平台实现,token是加密的形式保存在客户端,与语言无关,原则上任何web形式都支持。
- 不需要存储Session,服务端节点可水平无限扩展。
- 不依赖Cookie,使得其可以防止CSRF攻击。
- 性能好,只需要在header中携带token,即可实现认证,传递数据少,性能较好。
缺点:
- jwt生成的token在有效期内一直可用,因为主要存在客户端,无法在服务端删除。
- 用户登出,只能在客户端localStoage删除token,无法在服务端控制。
- jwt本身无法实现用户禁止登陆或拉黑用户,需要业务自己去实现。
适用场景:分布式集群。
1.3、JWT举例说明
分布式微服务如何基于JWT进行身份认证
以小程序H5为例,介绍JWT认证鉴权交互流程。
1)小程序端用户登录,输入用户名和密码。
2)请求鉴权,全局拦截器生效。
3)将用户名和密码传到用户服务模块,进行校验,若校验通过,则生成jwt token和refresh token。
4)通过校验,将token存储到小程序的缓存中。
5)浏览器发起请求,在header中携带token信息,请求到网关权限拦截器。
6)拦截器校验token合法性,合法则放行,不合法则阻止。
7)正常返回接口调用信息。
1.4、JWT的token有效时间设置
针对不同场景,对accessToken和refreshToken设置的有效期不同。
管理后台:
accessToken一般设置为30分钟,refreshToken设置为1小时。
小程序或APP:
accessToken一般设置为7天,refreshToken设置为30天。