# 前后端分离 token 验证
jwt token 常在请求头中进行传递,前端可以保存在 cookie 中,然后前端发送请求的时候从 cookie 中取出,放在请求头中发送请求,后端可以直接从请求中 request.getHead("token")
获取到 token
前后端分离不代表就不能用 session 验证是否登录,但是会出现分布式 session 共享问题。
面试题常考:详细介绍一下 JWT,除了 JWT 方式外,还有什么鉴权方式?JWT 方式鉴权和 Session-Cookie 方式鉴权方式的对比及优缺点?前后端分离就不能使用 Session-Cookie 吗?
token 验证完整流程
详细流程如图所示
细节①:当访问需要登录之后才有的接口时候,需要走拦截器,判断是否携带了 token,是否登录,如果未携带不放行,并让此登录
细节②:由于用户访问用户相关 api 的时候会一直走 token,可能会出现登录的时候 token 未失效但是后面一直在逛购物车,逛订单首页,然后 token 失效了,所系需要进行刷新 token
细节③:绝大部分接口是不需要知道 id 是谁的,因此直接通过前端传递的信息就够用了,不需要纠结 id 到底从哪里获得
细节④:可以在工具类里面实现静态方法,根据 HTTP 请求里面的 token,获取到用户信息,这样就可以写业务的时候直接调用,然后获得用户的信息,即使前端没有传递。
优化:可以在登录的时候,在生成 token 以后,把用户信息存放到 redis 中,这样注入 HttpSeveletRequest
, 然后获取 token,就可以直接查 redis,获取详细的用户信息,减少数据库查询
至于 id,交给前端传递了!
交给前端,是因为大部分业务和用户 id 没有关系,而真正需要用户 id 进行认证鉴权的时候,到时候在专门取出 id 即可!
注销就把 token 给失效掉就 ok 了
过滤器( Filter
):当你有一堆东西的时候,你只希望选择符合你要求的某一些东西。定义这些要求的工具,就是过滤器。
拦截器( Interceptor
):在一个流程正在进行的时候,你希望干预它的进展,甚至终止它进行,这是拦截器做的事情。
监听器( Listener
):当一个事件发生的时候,你希望获得这个事件发生的详细信息,而并不想干预这个事件本身的进程,这就要用到监听器。
import javax.servlet.http.HttpServletRequest; | |
import javax.servlet.http.HttpServletResponse; | |
import org.springframework.web.servlet.ModelAndView; | |
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; | |
public class OldLoginInterceptor extends HandlerInterceptorAdapter { | |
@Override | |
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) | |
throws Exception { | |
System.out.println("\n-------- OldLoginInterceptor.preHandle --- "); | |
System.out.println("Request URL: " + request.getRequestURL()); | |
System.out.println("Sorry! This URL is no longer used, Redirect to /admin/login"); | |
response.sendRedirect(request.getContextPath() + "/admin/login"); | |
return false; | |
} | |
@Override | |
public void postHandle(HttpServletRequest request, HttpServletResponse response, // | |
Object handler, ModelAndView modelAndView) throws Exception { | |
// This code will never be run. | |
System.out.println("\n-------- OldLoginInterceptor.postHandle --- "); | |
} | |
@Override | |
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, // | |
Object handler, Exception ex) throws Exception { | |
// This code will never be run. | |
System.out.println("\n-------- QueryStringInterceptor.afterCompletion --- "); | |
} | |
} |
// 要在主启动类中加 @ServletComponentScan 注解进行扫描 | |
@WebFilter(filterName = "MyFilterWithAnnotation", urlPatterns = "/api/*") | |
public class MyFilterWithAnnotation implements Filter { | |
...... | |
} |
# 前后端不分离
一般使用 request.getSession().getAttribute()
操作相关的 session 进行验证
# 参考文章
spring boot 过滤器和拦截器
spring boot 过滤器和拦截器 —Java Guide
# 在 controller 层获取用户信息的四种方法
- 前后端使用 session 完成认证,可以增加一个 HttpServletRequest 参数,获得 session,取得 id
- 前后端使用 token 完成认证,可以增加一个 HttpServletRequest 参数,解析 token,取得 id
- 使用 ThreadLocal,在过滤器 / 拦截器的时候,解析 id,并且放到 ThreadLocal 里面,然后可以在 controller 直接调用
- 使用安全框架完成调用,shiro/spring security