jwt和传统session的区别?

传统的session认证

1、用户向服务器发送用户名和密码。

2、服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。

3、服务器向用户返回一个 session_id,写入用户的 Cookie。

4、用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。

5、服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。

基于session认证所显露的问题。

这种模式的问题在于,扩展性(scaling)不好。单机当然没有问题,如果是服务器集群,或者是跨域的服务导向架构,就要求 session 数据共享,每台服务器都能够读取 session。

举例来说,A 网站和 B 网站是同一家公司的关联服务。现在要求,用户只要在其中一个网站登录,再访问另一个网站就会自动登录,请问怎么实现?

一种解决方案是 session 数据持久化,写入数据库或别的持久层。各种服务收到请求后,都向持久层请求数据。这种方案的优点是架构清晰,缺点是工程量比较大。另外,持久层万一挂了,就会单点失败。

另一种方案是服务器索性不保存 session 数据了,所有数据都保存在客户端,每次请求都发回服务器。JWT 就是这种方案的一个代表。

基于token的鉴权机制

基于token的鉴权机制类似于http协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息。这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。

流程上是这样的:

  • 用户使用用户名密码来请求服务器
  • 服务器进行验证用户的信息
  • 服务器通过验证发送给用户一个token
  • 客户端存储token,并在每次请求时附送上这个token值
  • 服务端验证token值,并返回数据
这个token必须要在每次请求时传递给服务端,它应该保存在请求头里, 另外,服务端要支持CORS(跨来源资源共享)策略,一般我们在服务端这么做就可以了Access-Control-Allow-Origin: *。

JWT长什么样?

JWT是由三段信息构成的,将这三段信息文本用.链接一起就构成了Jwt字符串。就像这样:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

  • 第一部分我们称它为头部(header)
  • 第二部分我们称其为载荷(payload, 类似于飞机上承载的物品)
  • 第三部分是签证(signature).

header


jwt的头部承载两部分信息:

   {'typ': 'JWT','alg': 'HS256'}

声明类型,这里是jwt
声明加密的算法 通常直接使用 HMAC SHA256

然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分.

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

playload


载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分

  • 标准中注册的声明
  • 公共的声明
  • 私有的声明
  • 标准中注册的声明 (建议但不强制使用) :

iss: jwt签发者
sub: 主题
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 生效时间
iat: 签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

  • 公共的声明 :
    公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.
  • 私有的声明 :
    私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。

定义一个payload:

{"sub": "1234567890","name": "John Doe","admin": true
}

然后将其进行base64加密,得到Jwt的第二部分。

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
signature

Signature


  • header (base64后的)
  • payload (base64后的)
  • secret
    这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。
    将这三部分用.连接成一个完整的字符串,构成了最终的jwt
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。

jjwt如何应用


我们如果把token理解问一个携带信息的加密字符,那大致可以分为3个步骤

  • 向token中加入信息
  • 把信息加密
  • 解密获取信息
项目结构

jwt核心代码
public class JwtHelper {/*** token 过期时间, 单位: 秒. 这个值表示 30 天*/private static final long TOKEN_EXPIRED_TIME = 30 * 24 * 60 * 60;/*** jwt 加密解密密钥*/private static final String JWT_SECRET = "MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY=";public static final String jwtId = "tokenId";/*** 创建JWT*/public static String createJWT(Map<String, Object> claims, Long time) {SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; //指定签名的时候使用的签名算法,也就是header那部分,jjwt已经将这部分内容封装好了。Date now = new Date(System.currentTimeMillis());SecretKey secretKey = generalKey();long nowMillis = System.currentTimeMillis();//生成JWT的时间//下面就是在为payload添加各种标准声明和私有声明了JwtBuilder builder = Jwts.builder() //这里其实就是new一个JwtBuilder,设置jwt的body.setClaims(claims)          //如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的.setId(jwtId)                  //设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为一次性token,从而回避重放攻击。.setIssuedAt(now)           //iat: jwt的签发时间.signWith(signatureAlgorithm, secretKey);//设置签名使用的签名算法和签名使用的秘钥if (time >= 0) {long expMillis = nowMillis + time;Date exp = new Date(expMillis);builder.setExpiration(exp);     //设置过期时间}return builder.compact();}/*** 验证jwt*/public static Claims verifyJwt(String token) {//签名秘钥,和生成的签名的秘钥一模一样SecretKey key = generalKey();Claims claims;try {claims = Jwts.parser()  //得到DefaultJwtParser.setSigningKey(key)         //设置签名的秘钥.parseClaimsJws(token).getBody();} catch (Exception e) {claims = null;}//设置需要解析的jwtreturn claims;}/*** 由字符串生成加密key** @return*/public static SecretKey generalKey() {String stringKey = JWT_SECRET;byte[] encodedKey = Base64.decodeBase64(stringKey);SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");return key;}/*** 根据userId和openid生成token*/public static String generateToken(String openId, Integer userId) {Map<String, Object> map = new HashMap<>();map.put("userId", userId);map.put("openId", openId);return createJWT(map, TOKEN_EXPIRED_TIME);}}
Controller层

@RestController
public class LoginController {@RequestMapping("/user/login")public String login() {String jwtToken = JwtHelper.generateToken("123",456);return jwtToken;}@RequestMapping("user/hello")public String user(){return   "hello";}
}
过滤器的使用

public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request =(HttpServletRequest)servletRequest;HttpServletResponse response = (HttpServletResponse)servletResponse;String token = request.getHeader("authorization"); //获取请求传来的tokenClaims claims = JwtHelper.verifyJwt(token); //验证tokenif (claims == null) {  response.getWriter().write("token is invalid");}else {filterChain.doFilter(request,response);}}@Overridepublic void destroy() {}
}
过滤器的加载

@Configuration
public class BeanRegisterConfig {@Beanpublic FilterRegistrationBean createFilterBean() {//过滤器注册类FilterRegistrationBean registration = new FilterRegistrationBean();registration.setFilter(new MyFilter());registration.addUrlPatterns("/user/hello"); //需要过滤的接口return registration;}
}

启动项目: 访问localhost:8080/user/hello
如下图:

携带token访问/user/hello

on = new FilterRegistrationBean();
registration.setFilter(new MyFilter());
registration.addUrlPatterns("/user/hello"); //需要过滤的接口
return registration;
}
}


`启动项目:` 访问`localhost:8080/user/hello`
如下图:[外链图片转存中...(img-fH69CdgR-1621396178496)]

携带token访问/user/hello


![img](https://img-blog.csdnimg.cn/img_convert/511780e64c485ad8a259fc8fcdb5e244.png)

jwt和传统session的区别?相关推荐

  1. Token ,Cookie和Session的区别

    Cookie cookie 是一个非常具体的东西,指的就是浏览器里面能永久存储的一种数据,仅仅是浏览器实现的一种数据存储功能. cookie由服务器生成,发送给浏览器,浏览器把cookie以kv形式保 ...

  2. cookie 和session 的区别详解

    转自 https://www.cnblogs.com/shiyangxt/archive/2008/10/07/1305506.html 这些都是基础知识,不过有必要做深入了解.先简单介绍一下. 二者 ...

  3. 图解Nosql(hbase)与传统数据库的区别

    图解Nosql(hbase)与传统数据库的区别 http://www.aboutyun.com/thread-7804-1-1.html (出处: about云开发) 问题导读: 1.nosql数据库 ...

  4. 大数据统计分析毕业设计_大数据分析与传统统计分析的区别

    大数据分析与传统统计分析的区别:其一是数据分析时不再进行抽样,而是采用全样本(n=all):其二是分析方法,不再采用传统的假设检验. 一.统计方法: 大数据的应用,解决了一般统计方法上主要误差来源:抽 ...

  5. Cookie 与Session 的区别

    Cookie 与Session 的区别(转载) 原地址: http://www.cnblogs.com/shiyangxt/archive/2008/10/07/1305506.html 两个都可以用 ...

  6. cookie,session的区别和联系(补充token)

    文章目录 1 http为什么是无状态的 2 cookie 和session 的区别详解 3 token 参考: 备注: 博客文章仅限于学习,禁止商用 1 http为什么是无状态的 2 cookie 和 ...

  7. cookie 和session 的区别

    session是保存在服务器端的,cookie是保存在客户端的. 二者的定义: 当你在浏览网站的时候,WEB 服务器会先送一小小资料放在你的计算机上,Cookie 会帮你在网站上所打的文字或是一些选择 ...

  8. nodejs的koa中cookie和session的使用,cookie和session的区别

    1.cookie是存储于访问者的计算机中的数据,用于同一浏览器访问同一域的时候共享数据 2.HTTP是无状态协议.也就是说:当你浏览了一个页面,然后跳转到同一个网站的另一个页面,服务器无法认识到这是同 ...

  9. 知识图谱·概念与技术--第1章学习笔记--知识图谱概述--知识图谱的概念,与传统语义网络的区别

    知识图谱·概念与技术--第1章学习笔记--知识图谱概述--知识图谱的概念,与传统语义网络的区别 知识图谱的概念,与传统语义网络的区别 狭义概念 作为语义网络的内涵 与传统语义网络的区别 优点 缺点 与 ...

  10. UEFI和传统引导的区别有哪些

    背景 前两天装机时,用U盘启动进行安装系统时,发现还原ghost系统后怎么也进入不了windows10开机界面,一直显示: 在U盘中去使用引导修复,也失败了,后来重新将系统盘进行分区,变成MBR格式, ...

最新文章

  1. Laravel5中Cookie的使用
  2. HTML5新增表单验证
  3. 如何对加载的数个模型只进行transform呢
  4. nginx中js修改不生效的问题
  5. java+arrayblockquene_java集合(五)Queue集合之ArrayBlockingQueue 详解
  6. Effective Java之避免创建不必要的对象(五)
  7. php基础小结,PHP基础学习小结
  8. matlab eval 不显示,matlab中 eval(command); 运算符无效的问题
  9. json怎么读取数据库_如何:使用Json插入数据库并从中读取
  10. python小测验3_python基础小测试
  11. css 清空ios端_H5移动端开发常见的问题处理
  12. [转载] python中count()、values_counts()、size()函数
  13. Opera的一个神奇功能
  14. python库之SnowNLP(自然语言处理)
  15. 解决Windows11能登录QQ微信,但不可以使用浏览器上网
  16. Transaction-based classification and detection approach for Ethereum smart contract
  17. 有监督学习、无监督学习、半监督学习、强化学习
  18. NSSCTF部分复现
  19. 2022年全球市场柠檬酸酯总体规模、主要生产商、主要地区、产品和应用细分研究报告
  20. 研究7——发展与应用

热门文章

  1. c语言详解  蔡勒(Zeller)公式计算某一天是星期几  极其方便
  2. 谈谈持久连接——HTTP权威指南读书心得(五)
  3. 39万的一节课:让你悟透“近朱者赤,近墨者黑”的道理
  4. 值-结果参数(socket编程中的函数举例)
  5. java for语句
  6. 利用Oracle Enterprise Manager Cloud Control 12c创建DataGuard Standby
  7. 如何利用【百度地图API】,制作房产酒店地图?(上)——制作自定义标注和自定义信息窗口...
  8. 8.业务架构·应用架构·数据架构实战 --- 技术方案书
  9. 12.微服务设计 --- 总结
  10. 21.实例 --- location