JSON Web Token (JWT)笔记(token实现单点登录功能)

前情提要

cookie(储存在用户本地终端上的数据)

百度百科-cookie(安全威胁)
cookie是客户端技术,存储在本地浏览器中,每次发送请求带着cookie值发送给web服务端。

Cookie,有时也用其复数形式Cookies。类型为“小型文本文件”,是某些网站为了辨别用户身份,进行Session跟踪而储存在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息

  • 简介

Cookie 并不是它的原意“甜饼”的意思, 而是一个保存在客户机中的简单的文本文件, 这个文件与特定的 Web 文档关联在一起,
保存了该客户机访问这个Web 文档时的信息, 当客户机再次访问这个 Web
文档时这些信息可供该文档使用。由于“Cookie”具有可以保存在客户机上的神奇特性, 因此它可以帮助我们实现记录用户个人信息的功能,
而这一切都不必使用复杂的CGI等程序 。

Cookie特点:

  • 客户端技术
  • 每次发送请求带着cookie值进行发送
  • cookie有默认会话级别,关闭浏览器cookie默认不存在了,默认cookies失效时间是直到关闭浏览器,cookies失效,也可以指定cookies时间。
  • 但是可以设置客户端cookie有效时长 setMaxAge(用户登录过期)
    setMaxAge

举例来说, 一个 Web 站点可能会为每一个访问者产生一个唯一的ID(数据库主键ID), 然后以 Cookie 文件的形式保存在每个用户的机器上。如果使用浏览器访问 Web, 会看到所有保存在硬盘上的 Cookie。在这个文件夹里每一个文件都是一个由“key/value”对组成的文本文件,另外还有一个文件保存有所有对应的 Web 站点的信息。在这里的每个 Cookie 文件都是一个简单而又普通的文本文件。透过文件名, 就可以看到是哪个 Web 站点在机器上放置了Cookie(当然站点信息在文件里也有保存) 。

  • 作用:

可以利用cookies跟踪统计用户访问该网站的习惯,比如什么时间访问,访问了哪些页面,在每个网页的停留时间等。利用这些信息,一方面是可以为用户提供个性化的服务,另一方面,也可以作为了解所有用户行为的工具,对于网站经营策略的改进有一定参考价值。

  • 用途:

存储用户在特定网站上的密码和 ID。另外,也用于存储起始页的首选项。在提供个人化查看的网站上,将利用计算机硬驱上的少量空间来储存这些首选项。这样,每次登录该网站时,浏览器将检查是否有cookie。如果有,浏览器将此 cookie 随网页的请求一起发送给服务器

  • 日常使用

网站的记住密码等操作都是使用cookie实现的,若是清除系统文件可能会将该cookie清除,导致无密码记录。

session(web服务端内存)

Session 是 用于保持状态的基于Web服务器的方法。Session允许通过将对象存储在Web服务器的内存中在整个用户会话过程中保持任何对象。
默认Session三十分钟后过期,web服务器将对应用户Session对象从内存中清除

  • 简介

Session:在计算机中,尤其是在网络应用中,称为“会话控制”。Session对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的Web页之间跳转时,存储在Session对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的Web页时,如果该用户还没有会话,则Web服务器将自动创建一个 Session对象。当会话过期或被放弃后,服务器将终止该会话。Session 对象最常见的一个用法就是存储用户的首选项。例如,如果用户指明不喜欢查看图形,就可以将该信息存储在Session对象中。

Session通常用于执行以下操作

  • 存储需要在整个用户会话过程中保持其状态的信息,例如登录信息或用户浏览Web应用程序时需要的其它信息。
  • 存储只需要在页面重新加载过程中或按功能分组的一组页之间保持其状态的对象。
  • Session的作用就是它在Web服务器上保持用户的状态信息供在任何时间从任何设备上的页面进行访问。因为浏览器不需要存储任何这种信息,所以可以使用任何浏览器,即使是像Pad或手机这样的浏览器设备。

持久性方法的限制
Sessions : 每次用户认证通过以后,服务器需要创建一条记录保存用户信息,通常是在内存中,随着认证通过的用户越来越多,服务器的在这里的开销就会越来越大。

随着越来越多用户登录,Session所需要的服务器内存量也会不断增加。
访问Web应用程序的每个用户都生成一个单独的Session对象。每个Session对象的持续时间是用户访问的时间加上不活动的时间。
如果每个Session中保持许多对象,并且许多用户同时使用Web应用程序(创建许多Session),则用于 Session持久性的服务器内存量可能会很大,从而影响了可伸缩性。

请添加图片描述
JWT与Session的差异 相同点是,它们都是存储用户信息;然而,Session是在服务器端的,而JWT是在客户端的。

Session方式存储用户信息的最大问题在于要占用大量服务器内存,增加服务器的开销。

而JWT方式将用户状态分散到了客户端中,可以明显减轻服务端的内存压力。

Session的状态是存储在服务器端,客户端只有session id;而Token的状态是存储在客户端。

cookie和session

cookie值保存在电脑什么地方_「前端面试」Cookie、Session和localStorage、sessionStorage…

Cookie:存储在用户本地终端上的数据主要包括:名字、值、过期时间、路径和域。如果不设置时间,默认关闭消除Cookie。会话Cookie保存在内存里,设置时间的保存在硬盘里。

session: 客户端请求创建session时,服务器先检测请求里是否包含了session id,如果存在就说明已为客户端创建过,如果没有就创建。而且session id一般都是保存在Cookie中。

Cookie和session的区别:

1、cookie数据存放在客户的浏览器上,session数据放在服务器上。

2、cookie不是很安全,session更安全。

3、session会在一定时间内保存在服务器上,当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie 。

4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。

5、session保存在服务器,客户端不知道其中的信心;cookie保存在客户端,服务器能够知道其中的信息 。

6、session中保存的是对象,cookie中保存的是字符串。

7、session不能区分路径,同一个用户在访问一个网站期间,所有的session在任何一个地方都可以访问到,而cookie中如果设置了路径参数,那么同一个网站中不同路径下的cookie互相是访问不到的。

单点登录(只登录一次,可使用账号下全部服务)三种方式

第二种单点登录的实现方式是基于redis可以实现跨服务存取值。
第三种单点登录的实现方式是基于本地存储token字符串,发送给不同服务端后,服务端可以解析识别出来用户信息(ID)
请添加图片描述

在这里插入图片描述

在这里插入图片描述

JWT(服务端签发给客户端的访问许可证)

token是按照一定规则生成字符串。(字符串可以包含用户信息)
token实质上就是加密的用户信息(ID)存储在客户端,每次客户端发送请求时token也会被发送出去,服务端解析token识别用户信息(ID)并提供用户对应数据,如此就可以实现单点登录了。
token作用:解决了不同微服务之间,session不能共享的问题
将服务端存储session记录用户信息(ID)转化为客户端cookie存储并发送token字符串服务端解析token字符串获得用户信息(ID)。

客户端接收服务器返回的JWT(服务端签发给客户端的访问许可证),将其存储在Cookie或localStorage中。
此后,客户端将在与服务器交互中都会带JWT。如果将它存储在Cookie中,就可以自动发送,但是不会跨域(不同协议,IP,端口无法通信),
需要跨域功能是因为前端项目端口和后端项目端口不一样属于跨域类型
因此一般是将它放入HTTP请求的Header Authorization字段中。 当跨域时,也可以将JWT被放置于POST请求的数据主体中。
JWT就是token的一种官方规则。

cookie不能实现跨域所以前后端分离的项目中不能通过cookie传值:因为前端项目端口和后端项目端口不一样属于跨域类型
JWT

jwt

JWT的组成

header (base64后的).payload (base64后的).signature
在这里插入图片描述

该对象为一个很长的字符串,字符之间通过"."分隔符分为三个子串。
每一个子串表示了一个功能块,总共有以下三个部分:JWT头、有效载荷和签名
请添加图片描述

JWT头(header)

JWT头部分是一个描述JWT元数据的JSON对象,通常如下所示。

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

在上面的代码中,alg属性表示签名使用的算法,默认为HMAC SHA256(写为HS256);typ属性表示令牌的类型,JWT令牌统一写为JWT。最后,使用Base64 URL算法将上述JSON对象转换为字符串保存。

有效载荷(payload)

有效载荷部分,是JWT的主体内容部分,也是一个JSON对象,包含需要传递的数据。 JWT指定七个默认字段供选择。

iss:发行人
exp:到期时间
sub:主题
aud:用户
nbf:在此之前不可用
iat:发布时间
jti:JWT ID用于标识该JWT

除以上默认字段外,我们还可以自定义私有字段,如下例:

{
"sub": "1234567890",
"name": "Helen",
"admin": true
}

请注意,默认情况下JWT是未加密的,任何人都可以解读其内容,因此不要构建隐私信息字段,存放保密信息,以防止信息泄露。
JSON对象也使用Base64 URL算法转换为字符串保存。

签名哈希(signature)

jwt的第三部分是一个签证信息,这个签证信息由三部分组成:

  • header (base64后的)
  • payload (base64后的)
  • secret

这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行secret组合加密,然后就构成了jwt的第三部分。

作者:Dearmadman 链接:https://www.jianshu.com/p/576dbf44b2ae 来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(claims), secret)

在计算出签名哈希后,JWT头,有效载荷和签名哈希的三个部分组合成一个字符串,每个部分用"."分隔,就构成整个JWT对象。

Base64URL算法
如前所述,JWT头和有效载荷序列化的算法都用到了Base64URL。该算法和常见Base64算法类似,稍有差别。
作为令牌的JWT可以放在URL中(例如api.example/?token=xxx)。 Base64中用的三个字符是"+“,”/“和”=“,由于在URL中有特殊含义,因此Base64URL中对他们做了替换:”=“去掉,”+“用”-“替
换,”/“用”_"替换,这就是Base64URL算法。

JWT的原则

JWT的原则是在服务器身份验证之后,将生成一个JSON对象并将其发送回用户,如下所示。

{
"sub": "1234567890",
"name": "Helen",
"admin": true
}

之后,当用户与服务器通信时,客户在请求中发回JSON对象。服务器仅依赖于这个JSON对象来标识用户。为了防止用户篡改数据,服务器将在生成对象时添加签名。
服务器不保存任何会话数据,即服务器变为无状态,使其更容易扩展。

JWT的用法

首先,某 client 使用自己的账号密码发送 post 请求 login,由于这是首次接触,服务器会校验账号与密码是否合法,如果一致,则根据密钥生成一个 token 并返回,client 收到这个 token 并保存在本地cookie。在这之后,需要访问一个受保护的路由或资源时,只要附加上 token(通常使用 Header 的 Authorization 属性)发送到服务器,服务器就会通过秘钥解密检查这个 token 是否有效(服务端根据秘钥,JWT头解密签名后比较有效载荷的信息是否一致),并做出响应。

客户端接收服务器返回的JWT(服务端签发给客户端的访问许可证),将其存储在Cookie或localStorage中。
此后,客户端将在与服务器交互中都会带JWT。如果将它存储在Cookie中,就可以自动发送,但是不会跨域(不同协议,IP,端口无法通信),
因此一般是将它放入HTTP请求的Header Authorization字段中。 当跨域时,也可以将JWT被放置于POST请求的数据主体中。

在这里插入图片描述
服务器验证JWT(许可证)时就是先参照JWT头和有效载荷的base64反转码后的信息,然后通过秘钥和加密算法对JWT的签名哈希进行解密,对比信息进行身份验证。
在这里插入图片描述

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

在这里插入图片描述

JWT问题和趋势

在这里插入图片描述

JWT实战

token实质上就是加密的用户信息(ID)存储在客户端,每次客户端发送请求时token也会被发送出去,服务端解析token识别用户信息(ID)并提供用户对应数据。
token作用:解决了不同微服务之间,session不能共享的问题
将服务端存储session记录用户信息(ID)转化为客户端cookie存储并发送token字符串服务端解析token字符串获得用户信息(ID)。

客户端接收服务器返回的JWT(服务端签发给客户端的访问许可证),将其存储在Cookie或localStorage中。
此后,客户端将在与服务器交互中都会带JWT。如果将它存储在Cookie中,就可以自动发送,但是不会跨域,
因此一般是将它放入HTTP请求的Header Authorization字段中。 当跨域时,也可以将JWT被放置于POST请求的数据主体中。

在这里插入图片描述
引入jwt依赖再cv驱动代码 JwtUtils。

  • 由JWT头,用户ID和昵称(有效载荷),秘钥合成token字符串
  • token或者request中header的信息判断token是否存在与有效
  • 根据token秘钥解析获取用户id
package com.qlugcl.commonutils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

public class JwtUtils {
    public static final long EXPIRE = 1000 * 60 * 60 * 24;//token过期时间
    public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO";//secret:秘钥

    public static String getJwtToken(String id, String nickname){

        String JwtToken = Jwts.builder()
                //设置JWT头
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")
                //设置过期时间
                .setSubject("qlugcl-user")
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
                //设置token主体部分,存储用户信息
                .claim("id", id)
                .claim("nickname", nickname)
                //秘钥加密部分
                .signWith(SignatureAlgorithm.HS256, APP_SECRET)
                .compact();

        return JwtToken;
    }

    /**
     * 判断token是否存在与有效
     * @param jwtToken
     * @return
     */
    public static boolean checkToken(String jwtToken) {
        if(StringUtils.isEmpty(jwtToken)) return false;
        try {
            Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 判断token是否存在与有效
     * @param request
     * @return
     */
    public static boolean checkToken(HttpServletRequest request) {
        try {
            String jwtToken = request.getHeader("token");
            if(StringUtils.isEmpty(jwtToken)) return false;
            Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 根据token获取会员id
     * @param request
     * @return
     */
    public static String getMemberIdByJwtToken(HttpServletRequest request) {
        String jwtToken = request.getHeader("token");
        if(StringUtils.isEmpty(jwtToken)) return "";
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        Claims claims = claimsJws.getBody();
        return (String)claims.get("id");
    }
}

service层
用户ID和用户昵称基于jwt规则生成token字符串,然后返回前端保存到Http的header中
在这里插入图片描述
controller层
根据token字符串解析得到用户ID,然后根据用户ID得到用户头像等信息。(只有服务端根据秘钥才能解析token)
因为token信息跟随Http的header中发送过来,所以可以通过request对象获取头信息并解析。
在这里插入图片描述

token的前后端流程

用户前端登录触发后端登录接口-》后端接口核实用户信息返回token字符串,前端将token字符串存储到cookie中-》创建前端拦截器将前端的每个请求都附带上token字符串-》前端发送请求携带token字符串到后端接口,然后获取用户信息并返回给前端,将用户信息放入cookie中-》在其他界面可以提取cookie中的值进行显示。

Cookie特点:

  • 客户端技术
  • 每次发送请求带着cookie值进行发送
  • cookie有默认会话级别,关闭浏览器cookie默认不存在了,
  • 但是可以设置cookie有效时长 setMaxAge

请添加图片描述
登录功能实现的流程:cookie(key:value)的跨界面传值
在这里插入图片描述

OAuth2解决方案(token令牌机制的跨应用授权登录和跨服务器单点登录)

登录的本质:服务端验证识别用户信息并返回对应的用户资源。
现代微服务安全
现代微服务中系统微服务化以及应用的形态和设备类型增多,不能用传统的登录方式
核心的技术不是用户名和密码,而是token,由AuthServer颁发token,用户使用token进行登录,服务端根据秘钥解析token并识别用户信息。
在这里插入图片描述

请添加图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
生活场景:QQ账号登录王者荣耀时,需要跳转到QQ授权登录,确认后王者荣耀才可以获取到玩家的QQ账号头像还有好友信息等等.
具体分配第三方应用专属秘钥以及分配token的验证等等则是资源服务器端处理的事务了。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
实质上就是加密的用户信息的跨应用授权登录和跨服务器单点登录。
在这里插入图片描述

总结(动态token字符串代替用户的name和password实现登录功能)

服务端生成识别token,用户端cookie保存发送token
相比较之前最大的优势:服务端将用户信息加密后存储到客户端cookie,减少了服务端内存保留无用会话时间的消耗,实现了什么时候用什么时候服务。
token实质上就是加密的用户信息(token字符串)存储在客户端cookie,每次客户端发送请求时token也会被发送出去,服务端解析token识别用户信息(ID)并根据需求提供用户对应数据(个人点赞信息和收藏等等)。
如此就是实现了一次登录就可使用账号下的全部服务(微服务运行在不同服务端)
工作流程:

  • 用户前端填写登录信息返回给服务端
  • 服务端接收到用户登录的信息,并验证用户是否存在。
  • 验证用户存在后,取出用户具体信息,然后根据用户ID和昵称以及服务端私有秘钥加密成token字符串的签名,token字符串返回给前端。
  • 前端接收到token字符串后存储到本地cookie中并且设置request拦截器,将前端的每次请求都拦截并在request的header中添加token字符串再发送给服务端。
  • 最后每次用户的前端请求都会附带token字符串由服务端解析并识别验证身份(ID)实现登录,返回请求用户对应的信息。

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

第一次用户登录的时候,服务端根据用户信息基于jwt规则和秘钥生成token字符串,返回给前端,前端将token字符串存储在cookie中并设置拦截器将前端的每次request请求都携带上token字符串,这样前端每次请求服务端提供服务前就可以先解析识别用户身份(ID)然后返回用户对应数据,从而代替session功能缓解服务器内存开销并且实现单点登录。

JWT与Session的差异 相同点是,它们都是存储用户信息;然而,Session是在服务器端的,而JWT是在客户端的。

Session方式存储用户信息的最大问题在于要占用大量服务器内存,增加服务器的开销。

而JWT方式将用户状态分散到了客户端中,可以明显减轻服务端的内存压力。

Session的状态是存储在服务器端,客户端只有session id;而Token的状态是存储在客户端。

遇见的cookie存值bug
存储用户信息到cookie中进行跨页面传值时注意cookie只能保存字符串的"key":“value”
JSON.stringify(response.data.data.item)进行类型转化(对象-》字符串)。
cookie只能存的是字符串,session保存的是对象
至于第一个为什么token存入cookie不用转为字符串,因为token本来就是字符串

  • 7
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值