• 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<String> 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<String> locations = new ArrayList<String>();
    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.addAllowedHeader("*");
    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<LcoUsers> 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;
        }
    }
  • 相关阅读:
    面试题之发散思维能力:如何用非常规方法求1+2+···+n
    优秀Python学习资源收集汇总(强烈推荐)
    JavaScript简洁继承机制实现(不使用prototype和new)
    JsRender for index 循环索引使用说明
    JsRender for object 语法说明
    pasteimg浏览器中粘贴图片jQuery插件
    西安电子科技大学泄漏信息
    移动端二维码弹出框,自适应屏幕尺寸
    服务器端json数据文件分割合并解决方案
    html中a标签href属性的一个坑
  • 原文地址:https://www.cnblogs.com/wiliamzhao/p/13037552.html
Copyright © 2020-2023  润新知