【JavaWeb】cookie、session、token(jwt)全部完成,简单理解下吧

本文介绍了JavaWeb中的Token,将其与Session进行了对比,并详细讲解了JWT(JSON Web Token)的工作原理和使用方法,包括JWT的构成、生成与解析。通过示例展示了如何在登录时使用JWT生成和验证Token,以及如何通过请求头传递Token。

【JavaWeb】token

前言

前面我么们学习了cookie、session今天我们来理解token,其实token很像session那其实都是衍生过来的,所以简单理解下吧,如果现在理解不了,慢慢往后就会理解了,那看前点个赞,养成好习惯👍

书接上回:
【JavaWeb】-Tomcat、Eclipse使用项目搭建(一)
【JavaWeb】-mysql、jdbc、dbcp使用(二)
【JavaWeb】-MVC、Servlet学习(三)
【JavaWeb】-Cookie、Session学习(四)

介绍

目前已经有很多都用到了token,那如果我们说了解cookie和session那token绝对是个新概念,其实我也是后面才了解,而且也不是很了解,这里既然都说到了,就拿目前自己了解的说下吧;

我们首先看看token是什么(来自百度百科):

在这里插入图片描述

就是信息加密技术,我们这里叫做令牌,作为交互对话的唯一身份标识,当用户第一次过来登录过后,我们验证身份会给用户发一个令牌,也就是token;

当用户再来访问的时候,只需要携带令牌,可以存放在cookie或请求头header中,这里注意我们session是通过session跟踪只能在cookie而令牌可以放到请求头中,这样可以防止一些攻击,大家可以自行去百度更多的文章去理解,这里我也不会这些攻击,等哪天会了再来跟大家说吧,这样我们与我们这里已经存在的令牌做对比,就可以得知用户是不是合法用户;

我们发现其实token跟session差不多,那其实token也可以理解成session,但是我们可以通过加密把信息全部存储在token中,服务端只需要留下token令牌只需要进行比对,需要的时候拿出token中的信息,这样我们就可以解放了服务端,同时信息的存储又交给了客户端;哈哈,是不是来来回回,还是来来回回,大家说会不会下一个技术出现,就又还给服务端了呢;

这样token虽然省出了空间,但是又要把用户的信息解密出来又是利用了cpu,那我们知道没办法,想要时间就浪费空间,想要空间就得浪费时间,就是这样

那token怎么实现呢,其实就是把信息加密成令牌就可以了,如果自己愿意做,自己可以做,那这里我们不做,就了解下jwt;

jwt

那什么又是jwt呢?

  • JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用 JWT 在用户和服务器之间传递安全可靠的信息。

  • 一个 JWT 实际上就是一个字符串,它由三部分组成,头部、载荷与签名。前两部分需要经过 Base64 编码,后一部分通过前两部分 Base64 编码后再加密而成。

三部分组成:

header(头部)

{
    'typ':'jwt',    #类型是jwt
    'alg':'HS256'   #加密算法,这里还有很多加密算法,大家自行了解
} 

payload(载荷)

{
    'sub':'42342342342',
    'name':'john',
    'admin':ture
}

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

signature(签名)

这里是我们做一个签名数据,放在我们后端,对数据进行加密,如果别别人知道了,那这些token数据无疑全部暴露;

添加依赖

<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

编写测试代码

package Test;

import java.util.Date;
import java.util.UUID;

import io.jsonwebtoken.*;

public class TestJwt {

	// 这是我们后端对数据的加密签名,密钥
	private String signature = "xuexiriji";
	
	
	public String encryption() {
		// 通过建造者模式创建一个jwt构造器
		JwtBuilder jwtBuilder = Jwts.builder();

		// 过期时间24小时
		long time = 1000 * 60 * 60 * 24;



		// 设置头部
		String token = jwtBuilder
				// 头部header
				.setHeaderParam("typ", "JWT").setHeaderParam("alg", "HS256")
				// 载荷payload,也就是数据
				.claim("name", "root")
				.claim("pass", "root")
				// 主题
				.setSubject("user")
				// 有效时间,重当前算起,到什么时候
				.setExpiration(new Date(System.currentTimeMillis() + time))
				// 再设置一个id
				.setId(UUID.randomUUID().toString())
				// signature,加一个签名
				.signWith(SignatureAlgorithm.HS256, this.signature)
				// 拼接
				.compact();

		System.out.println(token);

		return token;
	}
	
	
	public void parse(String token){
		JwtParser jwtParser = Jwts.parser();
		Jws<Claims> claimsJws =  jwtParser.setSigningKey(this.signature).parseClaimsJws(token);
		
		Claims claims = claimsJws.getBody();
		
		System.out.println(claims);
		
		//获取载荷信息
		System.out.println(claims.get("name"));
		System.out.println(claims.get("pass"));
		
		//可以获取id
		System.out.println(claims.getId());
		
		//获取subject
		System.out.println(claims.getSubject());
		//有效期
		System.out.println(claims.getExpiration());
	}
	
	
	

	public static void main(String[] args) {
		TestJwt testJwt = new TestJwt();
		testJwt.parse(testJwt.encryption());
	
		
	}
}

输出内容

我们通过生成可以看到生成的由三部分组成,通过.分隔,前两个分别对应header和payload的base64加密,最后一个是通过前两个内容加上密钥也就是signature再一次加密:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoicm9vdCIsInBhc3MiOiJyb290Iiwic3ViIjoidXNlciIsImV4cCI6MTY1MTU0ODI0MSwianRpIjoiZWYxM2RhMTktYzM1ZS00MjNiLTkxZTEtZGYxMTE5MjI4MWI0In0.Kf7pwcDhRRnhZrZRJYodDsB3DJmh05ege-Qri7iCNdc
这是我们输出的数据
{name=root, pass=root, sub=user, exp=1651548241, jti=ef13da19-c35e-423b-91e1-df11192281b4}
root
root
ef13da19-c35e-423b-91e1-df11192281b4
user
Tue May 03 11:24:01 CST 2022

我们不妨做给简单的tokenUtil:

package util;

import java.util.Date;
import java.util.Map;
import java.util.UUID;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

public class TokenUtil {
	
	// 这是我们后端对数据的加密签名,密钥
	private static String signature = "xuexiriji";
	// 过期时间24小时
	private static long time = 1000 * 60 * 60 * 24;
	
	public static String getToken(Map<String, Object> map) {
		// 通过建造者模式创建一个jwt构造器
		JwtBuilder jwtBuilder = Jwts.builder();
		
		// 设置头部
				String token = jwtBuilder
						// 头部header
						.setHeaderParam("typ", "JWT").setHeaderParam("alg", "HS256")
						// 载荷payload,也就是数据
						.setClaims(map)
						// 主题
						.setSubject("user")
						// 有效时间,重当前算起,到什么时候
						.setExpiration(new Date(System.currentTimeMillis() + time))
						// 再设置一个id
						.setId(UUID.randomUUID().toString())
						// signature,加一个签名
						.signWith(SignatureAlgorithm.HS256, signature)
						// 拼接
						.compact();
		
		
		return token;
	}

	public static Claims parseToken(String token) {
		JwtParser jwtParser = Jwts.parser();
		Jws<Claims> claimsJws =  jwtParser.setSigningKey(signature).parseClaimsJws(token);
		
		Claims claims = claimsJws.getBody();
		
/*		System.out.println(claims);
		
		//获取载荷信息
		System.out.println(claims.get("name"));
		System.out.println(claims.get("pass"));
		
		//可以获取id
		System.out.println(claims.getId());
		
		//获取subject
		System.out.println(claims.getSubject());
		//有效期
		System.out.println(claims.getExpiration());*/
		
		return claims;
	}

}

token尝试

我们了解了jwt的加密这里我们尝试下jwt对登录信息的保存,做个小例子:

改变我们的MyLoginServlet:

package servlet;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.collections.map.HashedMap;

import com.mysql.cj.Session;
import com.sun.org.apache.bcel.internal.generic.NEW;

import Dao.BaseDao;
import util.TokenUtil;

/**
 * Servlet implementation class MyLoginServlet
 */
@WebServlet("/MyLoginServlet")
public class MyLoginServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public MyLoginServlet() {
		super();
		// TODO Auto-generated constructor stub
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		String name = request.getParameter("username");
		String pass = request.getParameter("password");
		
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("name", name);
		map.put("pass", pass);
		//生成token,使用token放入请求头中,那就是前后端分离的项目了,或者前端使用异步方式请求,带上请求头
		String token = TokenUtil.getToken(map);
		//将token放入cookie
		response.addCookie(new Cookie("token", token));
		//将token放入请求头
		//response.addHeader("token", token);
		response.sendRedirect("index.jsp");
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

index.jsp页面

<%@page import="Dao.BaseDao"%>
<%@page import="com.sun.javafx.collections.MappingChange.Map"%>
<%@page import="util.TokenUtil"%>
<%@page import="io.jsonwebtoken.*"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>主界面</title>
</head>
<body>
	<%
		 Cookie[] cookies = request.getCookies();

		if (cookies != null) {
			// 我们可以遍历下我们的cooike看看
			for (Cookie cookie : cookies) {
				if(cookie.getName().equals("token")){
					Claims user = TokenUtil.parseToken(cookie.getValue());
					out.print(user.get("name")+"<br/>");
					out.print(user.get("pass")+"<br/>");
				}
			}
		} 		
	%>
	这里是主界面
</body>
</html>

效果

在这里插入图片描述

在这里插入图片描述

我们发现,这里我们并没有存储用户信息而是将信息放到了token中进行存储,我们只需要后面拿过来token然后通过密钥解析,就可以拿到用户的信息;

我们这里还可以用请求头测试下:

改变下代码:

MyLoginServlet.java


@WebServlet("/MyLoginServlet")
public class MyLoginServlet extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		String name = request.getParameter("username");
		String pass = request.getParameter("password");
		
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("name", name);
		map.put("pass", pass);
		//生成token,使用token放入请求头中,那就是前后端分离的项目了,或者前端使用异步方式请求,带上请求头
		String token = TokenUtil.getToken(map);
		//将token放入cookie
		//response.addCookie(new Cookie("token", token));
		//将token放入请求头
		response.addHeader("token", token);
		//response.sendRedirect("index.jsp");
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(request, response);
	}

}

index.jsp页面

<%@page import="Dao.BaseDao"%>
<%@page import="com.sun.javafx.collections.MappingChange.Map"%>
<%@page import="util.TokenUtil"%>
<%@page import="io.jsonwebtoken.*"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>主界面</title>
</head>
<body>
	<%
		/*  Cookie[] cookies = request.getCookies();
		
		if (cookies != null) {
			// 我们可以遍历下我们的cooike看看
			for (Cookie cookie : cookies) {
				if(cookie.getName().equals("token")){
					Claims user = TokenUtil.parseToken(cookie.getValue());
					out.print(user.get("name")+"<br/>");
					out.print(user.get("pass")+"<br/>");
				}
			}
		} 		 */
		if (request.getHeader("token") != null) {
			Claims user = TokenUtil.parseToken(request.getHeader("token"));
			out.print(user.get("name") + "<br/>");
			out.print(user.get("pass") + "<br/>");
		}
	%>
	这里是主界面
</body>
</html>

我们再次运行执行登录请求,打开检查,我们发现已经从请求头中响应了过来:

在这里插入图片描述

这里我们用postman测试下,通过请求头测试,测试成功:

在这里插入图片描述

而用户只要是携带了token,我们后端有这个token只需要判断有没有就知道这个用户是否登录过;这里我们放在了cookie中,token我们还可以放在请求头中,可以防止很多攻击,对于前后端项目来说,很好,但是这里尽量不要存放用户敏感信息,因为token也不是安全的;

包括token如果存放在请求头中,这里我们没有办法刷新用户的token只能是到时间之后自动过期;

具体使用场景看具体业务,这里只是简单的了解下,并没有什么业务代码,也是对于自己的理解,好就这样吧,那占位符 {jsp}

小结

通过cookie、session、以及token的学习相信已经了解了,那这只是很简单的了解,之后可以更加深入的学习,进行业务操作,所以到这里还不三连点个关注吗

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学习日记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值