赞
踩
服务器会接收很多的请求,但是服务器是需要识别出这些请求是不是同一个浏览器发出来的。比如:1和2这两个请求是不是同一个浏览器发出来的,3和5这两个请求不是同一个浏览器发出来的。如果是同一个浏览器发出来的,就说明是同一个会话。如果是不同的浏览器发出来的,就说明是不同的会话。而识别多次请求是否来自于同一浏览器的过程,我们就称为会话跟踪。
我们使用会话跟踪技术就是要完成在同一个会话中,多个请求之间进行共享数据。 由于HTTP是无状态协议,在后面请求中怎么拿到前一次请求生成的数据呢?此时就需要在一次会话的多次请求之间进行数据共享
重点
cookie 是客户端会话跟踪技术,它是存储在客户端浏览器的,我们使用 cookie 来跟踪会话,我们就可以在浏览器第一次发起请求来请求服务器的时候,我们在服务器端来设置一个cookie。
比如第一次请求了登录接口,登录接口执行完成之后,我们就可以设置一个cookie,在 cookie 当中我们就可以来存储用户相关的一些数据信息。比如我可以在 cookie 当中来存储当前登录用户的用户名,用户的ID。
服务器端在给客户端在响应数据的时候,会自动的将 cookie 响应给浏览器,浏览器接收到响应回来的 cookie 之后,会自动的将 cookie 的值存储在浏览器本地。接下来在后续的每一次请求当中,都会将浏览器本地所存储的 cookie 自动地携带到服务端。
接下来在服务端我们就可以获取到 cookie 的值。我们可以去判断一下这个 cookie 的值是否存在,如果不存在这个cookie,就说明客户端之前是没有访问登录接口的;如果存在 cookie 的值,就说明客户端之前已经登录完成了。这样我们就可以基于 cookie 在同一次会话的不同请求之间来共享数据。
为什么这一切都是自动化进行的?
是因为 cookie 它是 HTP 协议当中所支持的技术,而各大浏览器厂商都支持了这一标准。在 HTTP 协议官方给我们提供了一个响应头和请求头:
示例
@Slf4j @RestController public class SessionController { //登录接口:设置Cookie @GetMapping("/c1") public Result cookie1(HttpServletResponse response){ response.addCookie(new Cookie("login_username","itheima")); //设置Cookie/响应Cookie return Result.success(); } //其它接口:获取Cookie @GetMapping("/c2") public Result cookie2(HttpServletRequest request){ Cookie[] cookies = request.getCookies(); for (Cookie cookie : cookies) { if(cookie.getName().equals("login_username")){ System.out.println("login_username: "+cookie.getValue()); //输出name为login_username的cookie } } return Result.success(); } }
Session,它是服务器端会话跟踪技术,所以它是存储在服务器端的。而 Session 的底层其实就是基于我们刚才所介绍的 Cookie 来实现的。
不重要
令牌就是用户身份的标识,其本质就是一个字符串。jwt就是将原始的json数据格式进行了安全的封装,这样就可以直接基于jwt在通信双方安全的进行信息传输了。
JWT令牌由三个部分组成,三个部分之间使用英文的点来分割
第一部分:Header(头), 记录令牌类型、签名算法等。 例如:{“alg”:“HS256”,“type”:“JWT”}
第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。 例如:{“id”:“1”,“username”:“Tom”}
第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。
签名的目的就是为了防jwt令牌被篡改,而正是因为jwt令牌最后一个部分数字签名的存在,所以整个jwt 令牌是非常安全可靠的。一旦jwt令牌当中任何一个部分、任何一个字符被篡改了,整个令牌在校验的时候都会失败,所以它是非常安全可靠的。
其实在生成JWT令牌时,会对JSON格式的数据进行一次编码:进行base64编码
在JWT登录认证的场景中我们发现,整个流程当中涉及到两步操作:
<!-- JWT依赖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
在引入完JWT依赖后,就可以调用工具包中提供的API来完成JWT令牌的生成和校验
工具类:Jwts
JWT工具类
public class JwtUtils { private static String signKey = "itheima";//签名密钥 private static Long expire = 43200000L; //有效时间 /** * 生成JWT令牌 * @param claims JWT第二部分负载 payload 中存储的内容 * @return */ public static String generateJwt(Map<String, Object> claims){ String jwt = Jwts.builder() .addClaims(claims)//自定义信息(有效载荷) .signWith(SignatureAlgorithm.HS256, signKey)//签名算法(头部) .setExpiration(new Date(System.currentTimeMillis() + expire))//过期时间 .compact(); return jwt; } /** * 解析JWT令牌 * @param jwt JWT令牌 * @return JWT第二部分负载 payload 中存储的内容 */ public static Claims parseJWT(String jwt){ Claims claims = Jwts.parser() .setSigningKey(signKey)//指定签名密钥 .parseClaimsJws(jwt)//指定令牌Token .getBody(); return claims; } }
登录成功,生成JWT令牌并返回
@RestController @Slf4j public class LoginController { //依赖业务层对象 @Autowired private EmpService empService; @PostMapping("/login") public Result login(@RequestBody Emp emp) { //调用业务层:登录功能 Emp loginEmp = empService.login(emp); //判断:登录用户是否存在 if(loginEmp !=null ){ //自定义信息 Map<String , Object> claims = new HashMap<>(); claims.put("id", loginEmp.getId()); claims.put("username",loginEmp.getUsername()); claims.put("name",loginEmp.getName()); //使用JWT工具类,生成身份令牌 String token = JwtUtils.generateJwt(claims); return Result.success(token); } return Result.error("用户名或密码错误"); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。