一:认证
在了解JWT之前先来回顾一下传统session认证和基于token认证。
1.1 传统session认证
http协议是一种无状态协议,即浏览器发送请求到服务器,服务器是不知道这个请求是哪个用户发来的。为了让服务器知道请求是哪个用户发来的,需要让用户提供用户名和密码来进行认证。当浏览器第一次访问服务器(假设是登录接口),服务器验证用户名和密码之后,服务器会生成一个sessionid(只有第一次会生成,其它会使用同一个sessionid),并将该session和用户信息关联起来,然后将sessionid返回给浏览器,浏览器收到sessionid保存到Cookie中,当用户第二次访问服务器时就会携带Cookie值,服务器获取到Cookie值,进而获取到sessionid,根据sessionid获取关联的用户信息。
public User login(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {String username = request.getParameter("username");String password = request.getParameter("password");User user = userService.login(username, password);if (user == null) {throw new AuthenticationException("用户名或密码错误");}// 返回这次请求关联的当前会话,如果没有会话则创建一个新的// 需要在服务器端记录该sessionHttpSession session = request.getSession();session.setAttribute("user", user);// 让浏览器保存sessionid到cookie中// Cookie cookie = new Cookie("sessionid", session.getId());// cookie.setPath("/");// response.addCookie(cookie);return user;}public Object getUserInfo(HttpServletRequest request){// 从request中获取Cookie// 从Cookie中获取sessionid// 根据sessionid获取对应的Session对象// 从session中获取关联的用户信息HttpSession session = request.getSession();Object user = session.getAttribute("user");return user;}
session的缺点:
- Session: 每个用户经过我们的应用认证之后,我们的应用都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大。
- 扩展性: 用户认证之后,服务端做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。这也意味着限制了应用的扩展能力。即不能满足单点登陆
- CSRF: 因为是基于cookie来进行用户识别的, cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。
1.2 基于token认证
token原理:
- 使用用户名和密码请求登录接口
- 登录接口验证用户名和密码
- 登录接口生成一个uuid作为token,将用户信息作为值,然后保存到redis缓存中jedis.set(token, user);
- 登录接口返回用户信息和token
- 浏览器将token保存到本地
- 当请求其它接口时就携带token值
- 接口根据token去缓存检查,如果找到了就调用接口,如果找不到报token错误(一般通过拦截器来实现检查)
public String auth(String username, String password) throws AuthenticationException {User user = userService.login(username, password);if (user == null) {throw new AuthenticationException("用户名或密码错误");}String token = UUID.randomUUID().toString();