vue发送请求时总多出一个options请求,该请求拥有独立的sessionid,干扰后台过滤器的登录验证。
浏览器在跨域请求时会自动预发送一个 options 请求确认站点是否允许跨域访问。这个功能是浏览器内置的,js无权干预。这个问题干扰后端在过滤器里验证session中是否有当前登录人信息的逻辑。先来看下浏览器自动发送options的问题,如下图。
在这里插入图片描述
因为这个请求采用了独立的sessionid,所以后端采用通过将登录信息存入Session的方式便会出现问题,过滤器拦截到这个请求后,根据该sessionid无法获取到登录人信息,从而当作未登录处理,系统退出。所以,如果一定要以传统session方式存储登录人信息的话,必须在过滤器中放行 options 请求。

本人只是为了教学需要整合了下前后端分离框架和传统的session模型。关于登录信息保持,真实的系统如果采用有状态的方案往往采用redis+token,而采用jwt的无状态方案更是大势所趋。所以本文的问题并太不具备普遍性,仅供学习参考。

以下是关键代码。

前端发起请求的拦截器代码:

// response拦截器

service.interceptors.response.use(

response => {

// return response.data

console.info(response);

// code为非200是抛错 可结合自己业务进行修改

if(response.data.restCode != 200){

  Message({

    message: '登录状态已过期,请重新登录',

    type: 'warning'

  })

  //清空当前登录信息

  sessionStorage.removeItem("loginInfo");

  //退出

  router.push('/login')

}else{

  return response.data

}

}

后端过滤器代码:

public class AuthFilter implements Filter {

private static final Set<String> ALLOWED_PATHS = Collections.unmodifiableSet(new HashSet<>(
        Arrays.asList("/admin/login")));

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) servletRequest;
    HttpServletResponse resp = (HttpServletResponse) servletResponse;

    String path = req.getRequestURI().substring(req.getContextPath().length()).replaceAll("[/]+$", "");

    System.out.println("path:" + path);

    String sessionId = req.getSession().getId();
    System.out.println("sessionId:" + sessionId + "  req.method:" + req.getMethod());
    //filterChain.doFilter(servletRequest, servletResponse);

    //放行options请求, 因为浏览器的跨域验证,通过options请求发送
    if(req.getMethod().equals("OPTIONS")){
        filterChain.doFilter(servletRequest, servletResponse);
        return;
    }

    boolean allowedPath = ALLOWED_PATHS.contains(path);

    if (allowedPath) {
        System.out.println("这里是不需要处理的url进入的方法");
        filterChain.doFilter(servletRequest, servletResponse);
    }
    else {
        System.out.println("这里是需要处理的url进入的方法");
        Object currentUser = req.getSession().getAttribute("currentUser");
        if(currentUser != null){
            filterChain.doFilter(servletRequest, servletResponse);
        }else{
            resp.setCharacterEncoding("UTF-8");
            resp.addHeader("Access-Control-Allow-Origin", "http://localhost:8080");
            resp.addHeader("Access-Control-Allow-Credentials","true");
            resp.setContentType("application/json; charset=utf-8");
            PrintWriter out = resp.getWriter();
            JSONObject res = new JSONObject();
            res.put("code", -101);
            res.put("restInfo", "登录已过期,请重写登录");
            out.append(res.toString());
            out = resp.getWriter();
        }
    }
}

}

Logo

前往低代码交流专区

更多推荐