Springboot前后端分离项目配置跨域实现过程解析

网友投稿 553 2022-11-28


Springboot前后端分离项目配置跨域实现过程解析

项目登录流程如下

用户进入前端登录界面,输入账号密码等,输入完成之后前端发送请求到后端(拦截器不会拦截登录请求),后端验证账号密码等成功之后生成Token并存储到数据库,数据库中包含该Token过期时间,然后返回生成的Token到前端。

前端收到Token,表示登录成功,把这个Token存储本地。然后跳转到用户中心页面,用户中心页面在ajax的请求头中带上Token,跟随请求用户数据接口一起带到后端。

后端通过拦截器拦截到这个请求,去判断这个Token是否有效,有效就放过去做他该做的事情,无效就抛出异常。

跨域配置

先说一下这个前后分离的项目,已经配置过跨域这些问题。我这里后端WebMvcConfig配置的方式如下:

import com.zdyl.devicemanagement.interceptor.AccessInterceptor;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.web.cors.CorsConfiguration;

import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import org.springframework.web.filter.CorsFilter;

import org.springframework.web.servlet.config.annotation.CorsRegistry;

import org.springframework.web.servlet.config.annotation.InterceptorRegistry;

import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.annotation.Resource;

import java.util.ArrayList;

import java.util.List;

@Configuration

public class WebMvcConfig implements WebMvcConfigurer {

@Resource

private WebServerConfig webServerConfig;

@Bean

public AccessInterceptor getAccessInterceptor() {

return new AccessInterceptor();

}

@Override

public void addInterceptors(InterceptorRegistry registry) {

List excludeUrl = new ArrayList<>();

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

public void addResourceHandlers(ResourceHandlerRegistry registry) {

List locations = new ArrayList();

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 = new String[locations.size()];

registry.addResourceHandler("/**").addResourceLocations(locations.toArray(myArray));

}

@Bean

public CorsFilter corsFilter() {

UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

CorsConfiguration config = new CorsConfiguration();

config.setAllowCredentials(true);

config.addAllowedOrigin("*");

config.addxwdnorAllowedHeader("*");

config.addAllowedMethod("*");

source.registerCorsConfiguration("/**", config);

return new CorsFilter(source);

}

@Override

public void addCorsMappings(CorsRegistry registry) {

registry.addMapping("/**")

.allowedHeaders("*")

.allowCredentials(true)

.allowedOrigins("*")

.allowedMethods("POST", "GET", "DELETE", "PUT", "OPTIONS")

.maxAge(3600);

}

}

前端每次发送请求也都有在ajax里面设置xhrFields:{withCredentials: true}属性。

拦截器代码

import com.alibaba.fastjson.JSON;

import com.alibaba.fastjson.JSONObject;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;

import com.zdyl.devicemanagement.common.exception.RRException;

import com.zdyl.devicemanagement.common.utils.AccountNumber;

import com.zdyl.devicemanagement.common.utils.RedisSavePrefix;

import com.zdyl.devicemanagement.common.utils.RedisUtils;

import com.zdyl.devicemanagement.common.utils.SystemConstants;

import com.zdyl.devicemanagement.entity.LcoUsers;

import com.zdyl.devicemanagement.entity.Login;

import com.zdyl.devicemanagement.service.LcoUsersService;

import lombok.extern.slf4j.Slf4j;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.annotation.Resource;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.util.Date;

@Slf4j

public class AccessInterceptor extends HandlerInterceptorAdapter {

@Resource

private RedisUtils redisUtils;

@Resource

private LcoUsersService lcoUsersService;

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

log.info("------------------------AccessInterceptor-------------------------");

if (request.getMethod().equals(RequestMethod.OPTIONS.name())) {

return super.preHandle(request, response, handler);

}

//获取请求token,如果token不存在,直接返回401

String token = getRequestToken(request);

String loginId = getRequestloginId(request);

if (StringUtils.isEmpty(token)) {

throw new RRException("token为空", 401);

}

if (StringUtils.isEmpty(loginId)) {

throw new RRException("loginId为空", 401);

}

Object users = redisUtils.getObject(redisUtils.getKey(RedisSavePrefix.Login, loginId), AccountNumber.loginDataBase);

if (users == null) {

throw new RRException("用户尚未登录", 401);

}

Login loginUser = JSONObject.parseObject(JSON.toJSONString(users), Login.class);

if (!loginUser.getToken().equals(token)) {

throw new RRException("token不匹配", 401);

}

Date loginTime = loginUser.getLoginTime();

long exitTime = loginTime.getTime() / 1000 + 7200;

long time = new Date().getTime();

long nowTime = new Date().getTime() / 1000;

if (nowTime > exitTime) {

throw new RRException("token已过期!", 401);

}

QueryWrapper lcoUsersQueryWrapper = new QueryWrapper<>();

lcoUsersQueryWrapper.eq("phone", loginUser.getLoginID());

LcoUsers lcoUsers = lcoUsersService.getOne(lcoUsersQueryWrapper);

request.setAttribute(SystemConstants.CURRENTUSER, lcoUsers);

return super.preHandle(request, response, handler);

}

/**

* 获取请求的token

*/

private String getRequestToken(HttpServletRequest httpRequest) {

//从header中获取token

String host = httpRequest.getHeader("token");

//如果header中不存在token,则从参数中获取token

if (StringUtils.isEmpty(host)) {

host = httpRequest.getParameter("token");

}

// if (StringUtils.isEmpty(host)) {

// Cookie[] cks = httpRequest.getCookies();

// for (Cookie cookie : cks) {

// if (cookie.getName().equals("yzjjwt")) {

// host = cookie.getValue();

// return host;

// }

// }

// }

return host;

}

/**

* 获取请求的loginId

*/

private String getRequestloginId(HttpServletRequest httpRequest) {

//从header中获取token

String loginId = httpRequest.getHeader("loginId");

//如果header中不存在token,则从参数中获取token

if (StringUtils.isEmpty(loginId)) {

loginId = httpRequest.getParameter("loginId");

}

// if (StringUtils.isEmpty(loginId)) {

// Cookie[] cks = httpRequest.getCookies();

// for (Cookie cookie : cks) {

// if (cookie.getName().equals("yzjjwt")) {

// loginId = cookie.getValue();

// return loginId;

// }

// }

// }

return loginId;

}

/**

* 对跨域提供支持

*/

protected boolean addCors(ServletRequest request, ServletResponse response) throws Exception {

HttpServletRequest httpServletRequest = (HttpServletRequest) request;

HttpServletResponse httpServletResponse = (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());

return false;

}

return super.preHandle(request, response);

}

}

自定义异常RRException代码

/**

* 自定义异常

*/

public class RRException extends RuntimeException {

private static final long serialVersionUID = 1L;

private String message;

private String code = "INVALID";

private int status = 0;

public RRException(String msg) {

super(msg);

this.message = msg;

}

public RRException(String msg, Throwable e) {

super(msg, e);

this.message = msg;

}

public RRException(String msg, String code) {

super(msg);

this.message = msg;

this.code = code;

}

public RRException(String msg, int status) {

super(msg);

this.message = msg;

this.status = status;

}

public RRException(String msg, String code, Throwable e) {

super(msg, e);

this.message = msg;

this.code = code;

}

public String getMsg() {

return message;

}

public void setMsg(String msg) {

this.message = msg;

}

public String getCode() {

return code;

}

public void setCode(String code) {

this.code = code;

}

public int getStatus() {

return status;

}

public void setStatus(int status) {

this.status = status;

}

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Springboot整合多数据源代码示例详解
下一篇:基于springboot设置Https请求过程解析
相关文章

 发表评论

暂时没有评论,来抢沙发吧~