会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。在一次会话中可以包含多次请求和响应
会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据
cookie
// 设置cookies
@GetMapping("/c1")
public Result cookiel(HttpServletResponse response)
{
response.addCookie(new Cookie("login_username","ztt"));
return Result.success();
}
// 获取cookies
@GetMapping("/c2")
public Result cookies(HttpServletRequest request)
{
Cookie[] cookie2 = request.getCookies();
for (Cookie cookie:cookie2)
{
if (cookie.getName().equals("login_username"))
System.out.println("login_username:"+cookie.getValue());
}
return Result.success();
}
cookie优点:
HTTP协议支持的技术
cookie缺点:
1.移动端APP无法使用cookie
2.cookies不支持跨域
3.不安全,同时用户可以自己禁用cookie
Session
//往HTTPsession存储值
@GetMapping("/s1")
public Result session1(HttpSession session)
{
log.info("HttpSession-s1:{}",session.hashCode());
session.setAttribute("loginUser","tom");
return Result.success();
}
//从HTTPsession中获取值
public Result session2(HttpServletRequest request)
{
HttpSession session = request.getSession();
log.info("HttpSession-s2{}",session.hashCode());
Object loginUser = session.getAttribute("loginUser");
log.info("loginUser:{}",loginUser);
return Result.success(loginUser);
}
session优点:
存储在服务器上,安全
session缺点:
1.服务器集群环境下无法直接使用session
2.cookie的缺点
令牌技术
JWT 令牌
JSON web Token
其定义了一种简洁、自包含的格式,用于在通信双方以JSON数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。
一般的JWT如下所示:
第一部分: Header(头),记令牌类型、签名算法等,例如{“alg”:HS256,“type”:“JWT”)
第二部分: Payload(有效载荷)携带一些自定义信息默认信息等。 例如{“id”:“1”,“username”:“Tom”}
第三部分: Signature(签名)防止Token被篡改、确保安全性。将header、payload并加入指定秘钥,通过指定签名算计算而来。
使用场景:
在登录任务中,用户登录成功后会服务器会为用户生成令牌;后续每个请求用户都要携带JWT令牌,系统在每次请求处理之前,需要先校验令牌,令牌通过后再进行处理。
令牌技术优点:
支持PC、移动端
解决集群环境下的认证问题
减轻服务端存储压力
令牌技术缺点:
需要自己开发与实现
<!--JWP令牌依赖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.1</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.2</version>
</dependency>
@Test
public void testGenjwt()
{
Map<String,Object> claims = new HashMap<>();
claims.put("id",1);
claims.put("name","tom");
// ztt1232dksjhfskjdfmksjfksjdnfsdnfsfdsfaslkfdjskdjmfksjmadjcfk这个是key
String jwt = Jwts.builder()
.signWith(SignatureAlgorithm.HS256,"ztt1232dksjhfskjdfmksjfksjdnfsdnfsfdsfaslkfdjskdjmfksjmadjcfk") //签名算法
.setClaims(claims) //用户自定义内容,载荷部分
.setExpiration(new Date(System.currentTimeMillis()+3600*1000)) // 设置有效日期,定义为1h内有效
.compact();
System.out.println(jwt);
}
// jwt解析
@Test
public void testParseJWT()
{
Claims claims = Jwts.parser()
.setSigningKey("ztt1232dksjhfskjdfmksjfksjdnfsdnfsfdsfaslkfdjskdjmfksjmadjcfk")
.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoidG9tIiwiaWQiOjEsImV4cCI6MTY5MjU0MTMxOH0.jr3pjQ9SxObgxzljrF5fpMP_A0zPLyk73yFuFd8sI2U")
.getBody();
System.out.println(claims);
}
输出
eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoidG9tIiwiaWQiOjEsImV4cCI6MTY5MjU0MTMxOH0.jr3pjQ9SxObgxzljrF5fpMP_A0zPLyk73yFuFd8sI2U
同时这段编码也可以在JWT官网下解析出来,exp表示的是时间
注意:新版本的JWT对签名密钥长度做了要求;JWT 使用签名算法来保证 token 的完整性和认证,而对于 HS256 签名算法来说,密钥的长度必须 >= 256 位(32 字节),以确保安全性。
如果长度不足就会报这样的错误:
io.jsonwebtoken.security.WeakKeyException: The signing key’s size is 16 bits which is not secure enough for the HS256 algorithm. The JWT JWA Specification (RFC 7518, Section 3.2) states that keys used with HS256 MUST have a size >= 256 bits (the key size must be greater than or equal to the hash output size). Consider using the io.jsonwebtoken.security.Keys class’s ‘secretKeyFor(SignatureAlgorithm.HS256)’ method to create a key guaranteed to be secure enough for HS256. See https://tools.ietf.org/html/rfc7518#section-3.2 for more information.