Springboot前后端分离项目配置跨域实现过程解析
项目登录流程如下
用户进入前端登录界面,输入账号密码等,输入完成之后前端发送请求到后端(拦截器不会拦截登录请求),后端验证账号密码等成功之后生成Token并存储到数据库,数据库中包含该Token过期时间,然后返回生成的Token到前端。
前端收到Token,表示登录成功,把这个Token存储本地。然后跳转到用户中心页面,用户中心页面在ajax的请求头中带上Token,跟随请求用户数据接口一起带到后端。
后端通过拦截器拦截到这个请求,去判断这个Token是否有效,有效就放过去做他该做的事情,无效就抛出异常。
跨域配置
先说一下这个前后分离的项目,已经配置过跨域这些问题。我这里后端WebMvcConfig配置的方式如下:
importcom.zdyl.devicemanagement.interceptor.AccessInterceptor;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.web.cors.CorsConfiguration;
importorg.springframework.web.cors.UrlBasedCorsConfigurationSource;
importorg.springframework.web.filter.CorsFilter;
importorg.springframework.web.servlet.config.annotation.CorsRegistry;
importorg.springframework.web.servlet.config.annotation.InterceptorRegistry;
importorg.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;
importjavax.annotation.Resource;
importjava.util.ArrayList;
importjava.util.List;
@Configuration
publicclassWebMvcConfigimplementsWebMvcConfigurer{
@Resource
privateWebServerConfigwebServerConfig;
@Bean
publicAccessInterceptorgetAccessInterceptor(){
returnnewAccessInterceptor();
}
@Override
publicvoidaddInterceptors(InterceptorRegistryregistry){
ListexcludeUrl=newArrayList<>();
excludeUrl.add("/error");
excludeUrl.add("/v1/zdyl/downloadFile");
excludeUrl.add("/v1/zdyl/lcoStation/qrcode/**");
excludeUrl.add("/devicemanagement/images/**/*");
excludeUrl.add("/upgrade/**");
excludeUrl.add("/v1/zdyl/login/**");
excludeUrl.add("/NewsImage/**");
excludeUrl.add("/v1/zdyl/equipment/alarm/toExcel/test");
excludeUrl.add("/v1/zdyl/deviceMonitoring/get/alarm/toExcel/**");
registry.addInterceptor(getAccessInterceptor()).addPathPatterns("/**")
.excludePathPatterns(excludeUrl);
}
@Override
publicvoidaddResourceHandlers(ResourceHandlerRegistryregistry){
Listlocations=newArrayList();
locations.add("classpath:/META-INF/resources/");
locations.add("classpath:/resources/");
locations.add("classpath:/public/");
locations.add("file:"+webServerConfig.getUploadFileLocation());
locations.add("file:"+webServerConfig.getPicpath());
locations.add("file:"+webServerConfig.getProjectsource());
String[]myArray=newString[locations.size()];
registry.addResourceHandler("/**").addResourceLocations(locations.toArray(myArray));
}
@Bean
publicCorsFiltercorsFilter(){
UrlBasedCorsConfigurationSourcesource=newUrlBasedCorsConfigurationSource();
CorsConfigurationconfig=newCorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**",config);
returnnewCorsFilter(source);
}
@Override
publicvoidaddCorsMappings(CorsRegistryregistry){
registry.addMapping("/**")
.allowedHeaders("*")
.allowCredentials(true)
.allowedOrigins("*")
.allowedMethods("POST","GET","DELETE","PUT","OPTIONS")
.maxAge(3600);
}
}
前端每次发送请求也都有在ajax里面设置xhrFields:{withCredentials:true}属性。
拦截器代码
importcom.alibaba.fastjson.JSON;
importcom.alibaba.fastjson.JSONObject;
importcom.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
importcom.baomidou.mybatisplus.core.toolkit.StringUtils;
importcom.zdyl.devicemanagement.common.exception.RRException;
importcom.zdyl.devicemanagement.common.utils.AccountNumber;
importcom.zdyl.devicemanagement.common.utils.RedisSavePrefix;
importcom.zdyl.devicemanagement.common.utils.RedisUtils;
importcom.zdyl.devicemanagement.common.utils.SystemConstants;
importcom.zdyl.devicemanagement.entity.LcoUsers;
importcom.zdyl.devicemanagement.entity.Login;
importcom.zdyl.devicemanagement.service.LcoUsersService;
importlombok.extern.slf4j.Slf4j;
importorg.springframework.web.bind.annotation.RequestMethod;
importorg.springframework.web.servlet.handler.HandlerInterceptorAdapter;
importjavax.annotation.Resource;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importjava.util.Date;
@Slf4j
publicclassAccessInterceptorextendsHandlerInterceptorAdapter{
@Resource
privateRedisUtilsredisUtils;
@Resource
privateLcoUsersServicelcoUsersService;
@Override
publicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{
log.info("------------------------AccessInterceptor-------------------------");
if(request.getMethod().equals(RequestMethod.OPTIONS.name())){
returnsuper.preHandle(request,response,handler);
}
//获取请求token,如果token不存在,直接返回401
Stringtoken=getRequestToken(request);
StringloginId=getRequestloginId(request);
if(StringUtils.isEmpty(token)){
thrownewRRException("token为空",401);
}
if(StringUtils.isEmpty(loginId)){
thrownewRRException("loginId为空",401);
}
Objectusers=redisUtils.getObject(redisUtils.getKey(RedisSavePrefix.Login,loginId),AccountNumber.loginDataBase);
if(users==null){
thrownewRRException("用户尚未登录",401);
}
LoginloginUser=JSONObject.parseObject(JSON.toJSONString(users),Login.class);
if(!loginUser.getToken().equals(token)){
thrownewRRException("token不匹配",401);
}
DateloginTime=loginUser.getLoginTime();
longexitTime=loginTime.getTime()/1000+7200;
longtime=newDate().getTime();
longnowTime=newDate().getTime()/1000;
if(nowTime>exitTime){
thrownewRRException("token已过期!",401);
}
QueryWrapperlcoUsersQueryWrapper=newQueryWrapper<>();
lcoUsersQueryWrapper.eq("phone",loginUser.getLoginID());
LcoUserslcoUsers=lcoUsersService.getOne(lcoUsersQueryWrapper);
request.setAttribute(SystemConstants.CURRENTUSER,lcoUsers);
returnsuper.preHandle(request,response,handler);
}
/**
*获取请求的token
*/
privateStringgetRequestToken(HttpServletRequesthttpRequest){
//从header中获取token
Stringhost=httpRequest.getHeader("token");
//如果header中不存在token,则从参数中获取token
if(StringUtils.isEmpty(host)){
host=httpRequest.getParameter("token");
}
//if(StringUtils.isEmpty(host)){
//Cookie[]cks=httpRequest.getCookies();
//for(Cookiecookie:cks){
//if(cookie.getName().equals("yzjjwt")){
//host=cookie.getValue();
//returnhost;
//}
//}
//}
returnhost;
}
/**
*获取请求的loginId
*/
privateStringgetRequestloginId(HttpServletRequesthttpRequest){
//从header中获取token
StringloginId=httpRequest.getHeader("loginId");
//如果header中不存在token,则从参数中获取token
if(StringUtils.isEmpty(loginId)){
loginId=httpRequest.getParameter("loginId");
}
//if(StringUtils.isEmpty(loginId)){
//Cookie[]cks=httpRequest.getCookies();
//for(Cookiecookie:cks){
//if(cookie.getName().equals("yzjjwt")){
//loginId=cookie.getValue();
//returnloginId;
//}
//}
//}
returnloginId;
}
/**
*对跨域提供支持
*/
protectedbooleanaddCors(ServletRequestrequest,ServletResponseresponse)throwsException{
HttpServletRequesthttpServletRequest=(HttpServletRequest)request;
HttpServletResponsehttpServletResponse=(HttpServletResponse)response;
httpServletResponse.setHeader("Access-control-Allow-Origin",httpServletRequest.getHeader("Origin"));
httpServletResponse.setHeader("Access-Control-Allow-Methods","GET,POST,OPTIONS,PUT,DELETE");
httpServletResponse.setHeader("Access-Control-Allow-Headers",httpServletRequest.getHeader("Access-Control-Request-Headers"));
//跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态
if(httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())){
httpServletResponse.setStatus(HttpStatus.OK.value());
returnfalse;
}
returnsuper.preHandle(request,response);
}
}
自定义异常RRException代码
/**
*自定义异常
*/
publicclassRRExceptionextendsRuntimeException{
privatestaticfinallongserialVersionUID=1L;
privateStringmessage;
privateStringcode="INVALID";
privateintstatus=0;
publicRRException(Stringmsg){
super(msg);
this.message=msg;
}
publicRRException(Stringmsg,Throwablee){
super(msg,e);
this.message=msg;
}
publicRRException(Stringmsg,Stringcode){
super(msg);
this.message=msg;
this.code=code;
}
publicRRException(Stringmsg,intstatus){
super(msg);
this.message=msg;
this.status=status;
}
publicRRException(Stringmsg,Stringcode,Throwablee){
super(msg,e);
this.message=msg;
this.code=code;
}
publicStringgetMsg(){
returnmessage;
}
publicvoidsetMsg(Stringmsg){
this.message=msg;
}
publicStringgetCode(){
returncode;
}
publicvoidsetCode(Stringcode){
this.code=code;
}
publicintgetStatus(){
returnstatus;
}
publicvoidsetStatus(intstatus){
this.status=status;
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。