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){ List locations=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; } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。