springboot拦截器实现权限认证 axios中get或post请求变成OPTIONS(遇到的Request Method: OPTIONS已解决)handler instanceof Hand - Go语言中文社区

springboot拦截器实现权限认证 axios中get或post请求变成OPTIONS(遇到的Request Method: OPTIONS已解决)handler instanceof Hand


参考博客:
axios中Post请求变成OPTIONS的几种解决方案

一、拦截器引入前

1.首先登录:
Login.vue

axios.post(url,{"userName":this.userName,"password":this.password})
         .then(response=>{
                if(response.data.code==0) {
                  //console.log(response.data.token);
                  window.localStorage.setItem("token",response.data.token);
                  //路由跳转 登录成功后 跳转
                  this.$router.replace('/phoneBook')
                }else {
                  this.errorInfo = response.data.msg;
                }

              }).catch(error=>{
                this.errorInfo=error;
})

2.登录成功后跳转至电话簿列表页面:
PhoneBook.vue

export default {
    name: "PhoneBook",
    methods: {
      getPhoneBooks() {
        let url  = getServerUrl("phoneBook/loadAll")
        axios.get(url)
          .then(response=>{
            console.log(response)
          }).catch(error=>{
            console.log(error)
        })
      }
    },
    mounted() {
      this.getPhoneBooks(); //加载所有电话簿信息
    }
  }

发起loadAll请求:

	/**
     * 查询所有电话簿信息  正常情况下要把token带过来才允许请求此方法
     * @return
     * @throws Exception
     */
    @RequestMapping("/loadAll")
    public R loadAll()throws Exception{
        return R.ok("电话簿信息");
    }

在这里插入图片描述
很显然,下面的请求是没有携带token的
在这里插入图片描述
因此这很不合理,所以下面引入拦截器

二、拦截器的引入

1.SysInterceptor实现HandlerInterceptor接口

public class SysInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String contextPath = request.getRequestURI();  //完整的请求地址
        System.out.println("路径:"+contextPath);
        String token = request.getHeader("token"); //从请求中取出token
        if(handler instanceof HandlerMethod){
            if(StringUtil.isEmpty(token)){
                System.out.println("签名验证不存在");//即token 不存在
                print(response, R.error(SystemConstant.JWT_ERRCODE_NULL,"签名验证不存在"));
                return false;
            }else {
                CheckResult checkResult = JwtUtils.validateJWT(token);
                if(checkResult.isSuccess()){
                    System.out.println("签名验证通过");
                    return true;
                }else {
                    switch (checkResult.getErrCode()){
                        case SystemConstant.JWT_ERRCODE_FAIL:
                            System.out.println("签名验证不通过");
                            print(response,R.error(SystemConstant.JWT_ERRCODE_NULL,"签名验证不通过"));
                            break;
                        case SystemConstant.JWT_ERRCODE_EXPIRE:
                            System.out.println("签名验证已过期");
                            print(response,R.error(SystemConstant.JWT_ERRCODE_EXPIRE,"签名验证已过期"));
                            break;
                    }
                    return false;
                }

            }
        }
        return false;
    }
    private void print(HttpServletResponse response, Object message){
        try {
            response.setStatus(HttpStatus.OK.value());
            response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
            response.setHeader("Cache-Control", "no-cache, must-revalidate");
            PrintWriter writer = response.getWriter();
            writer.write(message.toString());
            writer.flush();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

JwtUtils在另一篇博客里面。
2.配置类里面配置拦截器

/**
    解决跨域问题 配置类
 */
@Configuration
public class WebAppConfigurer implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowCredentials(true)
                .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE","OPTIONS")
                .maxAge(3600);
    }

    /** 这里配置把拦截器添上
     * 配置不需要拦截的请求
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        String[] patterns = new String[] {"/login","/*.html","/image"};
        registry.addInterceptor(new SysInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns(patterns);
    }
}

3.首先测试,前端请求时不加token的情况
果然报错 说 签名验证不存在,因为前端发起请求时还未携带token呢!
在这里插入图片描述
下面 在前端请求时加上token:

export default {
    name: "PhoneBook",
    methods: {
      getPhoneBooks() {
        let token = window.localStorage.getItem("token")
        axios.defaults.headers.common['token']=token
        let url  = getServerUrl("phoneBook/loadAll")
        axios.get(url)
          .then(response=>{
            console.log(response)
          }).catch(error=>{
            console.log(error)
        })
      }
    },
    mounted() {
      this.getPhoneBooks(); //加载所有电话簿信息
    }
  }

3.下面报错了,让我们一探究竟
报错一:request.getHeader(“token”); //从请求中取出token为啥是空?
在这里插入图片描述

报错二:if语句里面的 handler instanceof HandlerMethod 为啥是false?

三.报错原因:

原来,我们在使用axios时,遇到了Request Method: OPTIONS

每个接口都调了两次,刚开始没太注意感觉两次请求是一摸一样的,仔细看了一圈,发现第一次调用的 Request Method: OPTIONS ,第二次调用的 Request Method: GET

至于为啥调用接口两次,参考这个博客:
使用axios时遇到的Request Method: OPTIONS

下面演示:

1.点击登录后 正常取出了localStorage里面的token:
在这里插入图片描述
2.点击OK
然后在请求 phoneBook/loadAll 之前 下面进入了拦截器:
在这里插入图片描述
很明显,上图中显示的 是第一次请求的OPTIONS 我们 返回true
然后我们将此次请求放行
3.下面来到第二次请求:
在这里插入图片描述
继续往下走:

在这里插入图片描述
token终于取到了,
在这里插入图片描述

四、小结:

主要就是下面代码:

 /*
每个接口都调了两次,刚开始没太注意感觉两次请求是一摸一样的,
 仔细看了一圈,发现第一次调用的 Request Method: OPTIONS ,第二次调用的 Request Method: POST或是GET 这里是GET
 所以下面必须加上这句 处理一下第一次请求的OPTIONS,否则我们就无法从request里面取出token了
  */
 if(request.getMethod().equals("OPTIONS")){
     response.setStatus(HttpServletResponse.SC_OK);
     return true;
 }
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_37767455/article/details/104052560
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢