排查问题
由于认证是手动实现的,所以需要在filter中检测token是否合法,如果不合法就直接在filter中返回错误信息(json)
package com.carenmg.shangpu.filter;
import com.carenmg.shangpu.pojo.Admin;
import com.carenmg.shangpu.pojo.bo.JsonData;
import com.carenmg.shangpu.service.AdminService;
import com.sun.xml.internal.xsom.impl.Ref;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.rmi.server.ExportException;
import java.util.*;
@WebFilter(urlPatterns = {"/api/*"})
@Component
public class TokenFilter implements Filter {
@Autowired
private AdminService adminService;
private static final Set<String> ALLOWED_PATHS = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList("", "/login")));
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init filter");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("doFilter");
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//返回可以跨域的配置
response.setHeader("Access-Control-Allow-Origin","*");
response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
response.addHeader("Access-Control-Max-Age", "1800");//30 min
//is login request?
StringBuffer requestURL = request.getRequestURL();
if (requestURL.toString().contains("/login") && request.getMethod().equals("POST")) {
filterChain.doFilter(request, response);
} else {
//查找用户,存入session
try {
String token = request.getHeader("token");
if (ObjectUtils.isEmpty(token)) {
throw new Exception("请求失败,请登录后重试");
}
Admin admin = adminService.findByToken(token);
if (ObjectUtils.isEmpty(admin)) {
throw new Exception("登录信息已过期,请重新登录");
}
HttpSession session = request.getSession();
session.setAttribute("user", admin);
filterChain.doFilter(request, response);
} catch (Exception e) {
//need login first
response.setHeader("Content-Type", "application/json;charset=UTF-8");
response.getWriter().write("{\"code\":1,\"msg\":\""+e.getMessage()+"\"}");
}
}
}
}
但是在login的时候无论怎样都提示跨域问题
各种google、百度都没有解决问题,最后仔细观察发现这里有个提示has been blocked by CORS policy: Request header field token is not allowed by Access-Control-Allow-Headers in preflight response.
,由于对跨域学习不够透彻,其实在配置response.setHeader("Access-Control-Allow-Headers", "x-requested-with,token");
的是时候以为这样配置就可以了,但是由于请求中携带了token(过期的,存储在localStorage里面,每次请求都携带token),所以跨域失败了。
springboot配置跨域
- 在controller中配置跨域,可以直接设置注解@CrossOrigin;
@RestController("apiGroup")
@RequestMapping("api/group")
@CrossOrigin(origins = "http://localhost:8080")
public class GroupController {
//...
}
- 在Application中配置@Bean
@MapperScan("com.carenmg.shangpu.mapper")
@SpringBootApplication
public class ShangpuApplication {
public static void main(String[] args) {
SpringApplication.run(ShangpuApplication.class, args);
}
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/*").allowedOrigins("*").allowedMethods("POST","GET","PUT","DELETE");
}
};
}
}
- 在filter中配置(前面的)
- 单独的Component
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/greeting-javaconfig").allowedOrigins("http://localhost:8080");
}
};
}