欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Springboot 如何实现filter拦截token验证和跨域

程序员文章站 2022-03-13 11:34:52
springboot filter拦截token验证和跨域背景web验证授权合法的一般分为下面几种 使用session作为验证合法用户访问的验证方式 使用自己实现的token 使用o...

springboot filter拦截token验证和跨域

背景

web验证授权合法的一般分为下面几种

  • 使用session作为验证合法用户访问的验证方式
  • 使用自己实现的token
  • 使用oca标准

在使用api接口授权验证时,token是自定义的方式实现起来不需要引入其他东西,关键是简单实用。

合法登陆后一般使用用户uid+盐值+时间戳使用多层对称加密生成token并放入分布式缓存中设置固定的过期时间长(和session的方式有些相同),这样当用户访问时使用token可以解密获取它的uid并据此验证其是否是合法的用户。

#springboot中实现filter

  • 一种是注解filter
  • 一种是显示的硬编码注册filter

先有filter

import javax.servlet.annotation.webfilter;
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.stereotype.component;
import springfox.documentation.spring.web.json.json;
import com.alibaba.fastjson.json; 
import java.io.ioexception;
import java.io.outputstreamwriter;
import java.io.printwriter;
import java.io.unsupportedencodingexception;
import javax.servlet.filter;
import javax.servlet.filterchain;
import javax.servlet.filterconfig;
import javax.servlet.servletexception;
import javax.servlet.servletrequest;
import javax.servlet.servletresponse;
import javax.servlet.http.httpservletrequest;
import javax.servlet.http.httpservletresponse;
/***************
 * token验证拦截
 * @author bamboo zjcjava@163.com
 * @time 2017-08-01
 */
@component
//@webfilter(urlpatterns = { "/api/v/*" }, filtername = "tokenauthorfilter")
public class tokenauthorfilter implements filter {
 private static logger logger = loggerfactory
   .getlogger(tokenauthorfilter.class);
 @override
 public void destroy() {
 }
 @override
 public void dofilter(servletrequest request, servletresponse response,
   filterchain chain) throws ioexception, servletexception {
  httpservletrequest req = (httpservletrequest) request;
  httpservletresponse rep = (httpservletresponse) response;
  //设置允许跨域的配置
  // 这里填写你允许进行跨域的主机ip(正式上线时可以动态配置具体允许的域名和ip)
  rep.setheader("access-control-allow-origin", "*");
  // 允许的访问方法
  rep.setheader("access-control-allow-methods","post, get, put, options, delete, patch");
  // access-control-max-age 用于 cors 相关配置的缓存
  rep.setheader("access-control-max-age", "3600");
  rep.setheader("access-control-allow-headers","token,origin, x-requested-with, content-type, accept");
  response.setcharacterencoding("utf-8");
  response.setcontenttype("application/json; charset=utf-8");
  string token = req.getheader("token");//header方式
  resultinfo resultinfo = new resultinfo();
  boolean isfilter = false;  
   
  string method = ((httpservletrequest) request).getmethod();
  if (method.equals("options")) {
   rep.setstatus(httpservletresponse.sc_ok);
  }else{
      
   if (null == token || token.isempty()) {
    resultinfo.setcode(constant.un_authorized);
    resultinfo.setmsg("用户授权认证没有通过!客户端请求参数中无token信息");
   } else {
    if (tokenutil.volidatetoken(token)) {
     resultinfo.setcode(constant.success);
     resultinfo.setmsg("用户授权认证通过!");
     isfilter = true;
    } else {
     resultinfo.setcode(constant.un_authorized);
     resultinfo.setmsg("用户授权认证没有通过!客户端请求参数token信息无效");
    }
   }
   if (resultinfo.getcode() == constant.un_authorized) {// 验证失败
    printwriter writer = null;
    outputstreamwriter osw = null;
    try {
     osw = new outputstreamwriter(response.getoutputstream(),
       "utf-8");
     writer = new printwriter(osw, true);
     string jsonstr = json.tojsonstring(resultinfo);
     writer.write(jsonstr);
     writer.flush();
     writer.close();
     osw.close();
    } catch (unsupportedencodingexception e) {
     logger.error("过滤器返回信息失败:" + e.getmessage(), e);
    } catch (ioexception e) {
     logger.error("过滤器返回信息失败:" + e.getmessage(), e);
    } finally {
     if (null != writer) {
      writer.close();
     }
     if (null != osw) {
      osw.close();
     }
    }
    return;
   }
   
   if (isfilter) {
   logger.info("token filter过滤ok!");
   chain.dofilter(request, response);
   }
  } 
 }
 @override
 public void init(filterconfig arg0) throws servletexception {
 }
}

注解配置filter

加上如下配置则启动时会根据注解加载此filter

@webfilter(urlpatterns = { “/api/*” }, filtername = “tokenauthorfilter”)

硬编码注册filter

在application.java中加入如下代码

    //注册filter
    @bean  
    public filterregistrationbean  filterregistrationbean() {  
        filterregistrationbean registrationbean = new filterregistrationbean();  
        tokenauthorfilter tokenauthorfilter = new tokenauthorfilter();  
        registrationbean.setfilter(tokenauthorfilter);  
        list<string> urlpatterns = new arraylist<string>();  
        urlpatterns.add("/api/*");
        registrationbean.seturlpatterns(urlpatterns);  
        return registrationbean;  
    }  

以上两种方式都可以实现filter

跨域说明

springboot可以设置全局跨域,但是对于filter中的拦截地址并不其中作用,因此需要在dofilter中再次设置一次

区局设置跨域方式如下

方式1.在application.java中加入如下代码

 //跨域设置
 private corsconfiguration buildconfig() {  
        corsconfiguration corsconfiguration = new corsconfiguration();  
        corsconfiguration.addallowedorigin("*");  
        corsconfiguration.addallowedheader("*");  
        corsconfiguration.addallowedmethod("*");         
        return corsconfiguration;  
    }  
      
    /** 
     * 跨域过滤器 
     * @return 
     */  
    @bean  
    public corsfilter corsfilter() {  
        urlbasedcorsconfigurationsource source = new urlbasedcorsconfigurationsource();  
        source.registercorsconfiguration("/**", buildconfig()); // 4  
        return new corsfilter(source);  
    }  

方式2.配置注解

必须集成webmvcconfigureradapter类

/**********
 * 跨域 cors:使用 方法3
 * 方法:
 1服务端设置respone header头中access-control-allow-origin
 2配合前台使用jsonp
 3继承webmvcconfigureradapter 添加配置类
 http://blog.csdn.net/hanghangde/article/details/53946366
 * @author xialeme
 *
 */
@configuration  
public class corsconfig extends webmvcconfigureradapter{  
  
   /* @override  
    public void addcorsmappings(corsregistry registry) {  
        registry.addmapping("/**")  
                .allowedorigins("*")  
                .allowcredentials(true)  
                .allowedmethods("get", "post", "delete", "put")  
                .maxage(3600);  
    }  */
  
 private corsconfiguration buildconfig() {
        corsconfiguration corsconfiguration = new corsconfiguration();
        corsconfiguration.addallowedorigin("*"); // 1
        corsconfiguration.addallowedheader("*"); // 2
        corsconfiguration.addallowedmethod("*"); // 3
        return corsconfiguration;
    }
    @bean
    public corsfilter corsfilter() {
        urlbasedcorsconfigurationsource source = new urlbasedcorsconfigurationsource();
        source.registercorsconfiguration("/**", buildconfig()); // 4
        return new corsfilter(source);
    }     
} 

springboot配置filter & 允许跨域请求

1.filter类

加注解:

@webfilter(filtername = "authfilter", urlpatterns = "/*")

代码如下:

package com.activiti.filter; 
import javax.servlet.*;
import javax.servlet.annotation.webfilter;
import javax.servlet.http.httpservletrequest;
import javax.servlet.http.httpservletresponse;
import java.io.ioexception;
 
// renwenqiang
@webfilter(filtername = "authfilter", urlpatterns = "/*")
public class systemfilter implements filter {
 
    public void dofilter(servletrequest servletrequest, servletresponse servletresponse, filterchain filterchain) throws ioexception,
            servletexception {
        httpservletrequest request = (httpservletrequest) servletrequest;
        httpservletresponse response = (httpservletresponse) servletresponse;
        response.setheader("access-control-allow-origin","*");
        system.out.println(request.getrequesturl());
        filterchain.dofilter(request, servletresponse);
    }
 
    @override
    public void destroy() { 
    }
 
    @override
    public void init(filterconfig arg0) throws servletexception { 
    }
}

2.启动类

加注解:

@servletcomponentscan(basepackages = {"com.activiti.filter"})

代码如下:

package com; 
import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.springbootapplication;
import org.springframework.boot.web.servlet.servletcomponentscan;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.componentscan;
import org.springframework.orm.jpa.vendor.hibernatejpasessionfactorybean;
import org.springframework.scheduling.annotation.enablescheduling;
 
@springbootapplication(exclude = {
        org.springframework.boot.autoconfigure.security.securityautoconfiguration.class,
        org.activiti.spring.boot.securityautoconfiguration.class })
@servletcomponentscan(basepackages = {"com.activiti.filter"})
public class demoactiviti0108application {
    
    @bean
    public hibernatejpasessionfactorybean sessionfactory() {
        return new hibernatejpasessionfactorybean();
    }
 
    public static void main(string[] args) {
        springapplication.run(demoactiviti0108application.class, args);
    } 
}

3.jquery ajax请求代码实例:

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
</head>
<body>
<div id="app">
<hr>
<h2>模型列表</h2>
<a href="#" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  id="huizhi">绘制流程</a>
<hr>
<table border="1">
    <tr>
        <td>id</td>
        <td>deploymentid</td>
        <td>name</td>
        <td>category</td>
        <td>optional</td>
    </tr>
    <tr v-for="item in models">
        <td>{{ item.id }}</td>
        <td>{{ item.deploymentid }}</td>
        <td>{{ item.name }}</td>
        <td>{{ item.category }}</td>
        <td>
            <a href="#" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow" >编辑</a>&nbsp;&nbsp;
            <a href="#" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow" >发布</a>&nbsp;&nbsp;
            <a href="#" rel="external nofollow"  rel="external nofollow"  rel="external nofollow"  rel="external nofollow" >删除</a>
        </td>
    </tr>
</table>
</div>
 
    <script src="https://cdn.bootcss.com/jquery/2.2.2/jquery.js"></script>
    <script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script>
    <script>
    new vue({
      el: '#app',
      data: {
        models: []
      },
      created: function () {
        $.ajax({
            type: 'get',
            url: 'http://localhost:8081/activiti/model/all',
            beforesend: function() {
                console.log('beforesend');
            },
            data:{},
            datatype: "json",
            xhrfields: {
                withcredentials: false
            },
            crossdomain: true,
            async: true,
            //jsonpcallback: "jsonpcallback",//服务端用于接收callback调用的function名的参数  
        }).done((data) => {
            console.log('done');
            console.log(data);
            this.models = data;
        }).fail((error) => {
            console.log('fail');
            console.log('error');
        });
      }
    })        
    </script> 
</body>
</html>

大功告成 回家睡觉 嘻嘻嘻~

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。