web会话跟踪(JWT是什么)

web会话跟踪(JWT是什么):

一.使用会话跟踪的原因:

因为http请求是无状态,一次请求响应结束后,就结束了,下一次再向服务器端发送请求,服务器并不知道是谁向他发送的

所以我们需要对整个会话过程进行跟踪

二.token:

● token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后, 服务器生成一个token便将此token返回给客户端,以后客户端只需带上这个token前来 请求数据即可。token保存在客户端,并且进行了加密,保证了数据的安全性.

● 目的:token的目的是为了减轻服务器的压力,使服务器更加健壮。

三.过程:

1.当登录时,后端验证账号密码是否正确,如果账号正确,就需要在后端为当前登录的用户生成一个令牌(token),将令牌信息响应给前端。

2.前端存储token

3.后面每次从前端向后端发送请求,都要携带token

4.后端验证令牌,如果令牌有效,继续向后执行。如果令牌无效,向前端响应认证失败,让重新登录。

JWT:

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).定义了一种简洁的,自包含的方法用于通信双方之间以JSON**对象的形式安全的传递信息。**因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名。

Id–>token 秘钥-签名 abc

JWT就是用来生成token的一种方式,一种可以携带用户信息,并且可以设置秘钥加密的字符串,是安全的.**

流程:

1. 用户使用账号和密码发出post请求;
2. 服务器使用私钥创建一个jwt;
3. 服务器返回这个jwt给浏览器;
4. 浏览器将该jwt串在请求头中像服务器发送请求;
5. 服务器验证该jwt;
6. 返回响应的资源给浏览器。

JWT的主要应用场景

身份认证在这种场景下,一旦用户完成了登陆,在接下来的每个请求中包含JWT,可以用来验证用户身份以及对路由,服务和资源的访问权限进行验证。由于它的开销非常小,可以轻松的在不同域名的系统中传递,所有目前在单点登录中比较广泛的使用了该技术。 信息交换在通信的双方之间使用JWT对数据进行编码是一种非常安全的方式,由于它的信息是经过签名的,可以确保发送者发送的信息是没有经过伪造的。

优点

1.简洁(Compact): 可以通过**URLPOST参数或者在HTTP header发送,因为数据量小,传输速度也很快
2.自包含(Self-contained):负载中包含了所有用户所需要的信息,避免了多次查询数据库
3.因为
Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言的,原则上任何web形式都支持。
4.不需要在服务端保存会话信息,特别适用于分布式微服务。

JWT的构成:

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

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 用户的信息),第三部分是签证(signature).

第一部分

header

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

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

完整的头部就像下面这样的JSON:

{‘typ’: ‘JWT’,‘alg’: ‘HS256’}–>重新进行编码(不是加密)

然后将头部进行base64转码,构成了第一部分.

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

第二部分

playload

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

· 标准中注册的声明

· 公共的声明

· 公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务 需要的必要信息.但不建议添加敏感信息(例如密码),因为该部分在客户端可解密. id,用户名,头像名

· 私有的声明

定义一个payload

{ “sub”: “1234567890”, “name”: “John Doe”,“admin”: true}

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

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

第三部分

signature

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

· header (base64后的)

· payload (base64后的)

· secret

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

TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

JWT搭建

引入JWT依赖,由于是基于Java,所以需要的是java-jwt
<dependency>

   <groupId>com.auth0</groupId>

   <artifactId>java-jwt</artifactId>

   <version>3.8.2</version>

  </dependency>
创建生成token的方法:
 * jwt生成token
	 * @param id
	 * @param account
	 * @return
	 */
	public static String token (Integer id, String account){
        String token = "";
        try {
            //过期时间 为1970.1.1 0:0:0 至 过期时间  当前的毫秒值 + 有效时间
        	Date expireDate = new Date(new Date().getTime() + 10*1000);
            //秘钥及加密算法
            Algorithm algorithm = Algorithm.HMAC256("xxxxxxxxxxxxxxxx");
            //设置头部信息
            Map<String,Object> header = new HashMap<>();
            header.put("typ","JWT");
            header.put("alg","HS256");
            //携带id,账号信息,生成签名
            token = JWT.create()
                    .withHeader(header)
                    .withClaim("id",id)
                    .withClaim("account",account)
                    .withExpiresAt(expireDate)
                    .sign(algorithm);
        }catch (Exception e){
            e.printStackTrace();
            return  null;
        }
        return token;
    }
验证token是否有效的方法:
public static boolean verify(String token){
         	try {
         		//验签
                Algorithm algorithm = Algorithm.HMAC256("xxxxxxxxxxxxxxxxxx");
                JWTVerifier verifier = JWT.require(algorithm).build();
                DecodedJWT jwt = verifier.verify(token);
                return true;
			} catch (Exception e) {//当传过来的token如果有问题,抛出异常
				 return false;
			}
     }
获得token 中playload部分数据:
 /**
  * 获得token 中playload部分数据,按需使用
  * @param token
  * @return
*/
public static DecodedJWT getTokenInfo(String token){
return JWT.require(Algorithm.HMAC256("xxxxxxxxxxxxxxxx")).build().verify(token);
}

用户登录成功后将用户id和账号存储到token中返回给客户端,之后客户端每次请求将token发送到服务器端验证, 在服务器中进行验证.

前端此时发送请求:
var token=sessionstorage.getItem('token');
this.$http.get("/test?token="+token).then((resp)=>{
})
后端此时接收请求:
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("test doget");
        String token=req.getParameter("token");
        System.out.println(token);
        boolean verify= JWTUtil.verify(token);
        System.out.println(verify);
        if(verify){

        }else {

        }
    }

优化:

但如果我们每次在前端发送一次请求,后端总是使用verify来验证的话过于麻烦,所以我们需要在前端的过滤器中把token在每次请求后直接默认给请求头,然后在后端的过滤器中验证一次请求头中的token。

后端过滤器:

经过过滤器验证完token后直接跳转相应的servlet,没有这个过滤器的话就需要在每个servlet中添加验证

// 登录login的servlrt中不加api,需要验证登录没的servlet都加api前缀
// 这样子token之类的过滤器不会在login时加载
@WebFilter(urlPatterns="/api/*")
public class TokenFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // getHeader是HttpServletRequst中的
        HttpServletRequest request=(HttpServletRequest)servletRequest;//向下转型
        String token=request.getHeader("token");    //接收请求头中的token
        System.out.println("token验证过滤器");
        //验证token
        boolean res= JWTUtil.verify(token);
        if(res){//token验证成功,继续向后执行,到达目标servlet程序
            filterChain.doFilter(servletRequest,servletResponse);
        }else {//token验证失败,向前端响应401
            Result result=new Result(401,"token认证失败",null);   //权限认证失败
            servletResponse.getWriter().print(new ObjectMapper().writeValueAsString(result));
        }

    }
}
前端拦截器:

接下来我们需要在main.js里添加请求拦截,每当我们使用axios把框架向后端发送请求时,都会经过拦截器。把浏览器的token给请求头进行验证是否相同,相同则请求通过。

//axios 请求拦截,每当我们使用axios框架向后端发送请求时,都会经过拦截器
axios.interceptors.request.use(config=>{
	//为请求头对象,添加token验证的token字段
	//c.h.token的token是请求头中设置的token名
config.headers.token=window.sessionStorage.getItem('token');
	return config;
})
前端添加响应拦截器:

当后端响应回来的状态为401和500的时候需要拦截器拦截同意进行操作,不然就要在每次可能会出现401和500的情况下做出相应的操作,这样很麻烦。

//添加响应拦截器
axios.interceptors.response.use((resp)=>{	//正常响应拦截
	if(resp.data.code==401){
		ElementUI.Message({message:resp.data.desc,type:"error"})
		router.replace("/login");//用replace跳转返回不回去
	}
	if(resp.data.code==500){
		ElementUI.Message({message:resp.data.desc,type:"error"})
	}
	return resp;
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值