服务器之家

服务器之家 > 正文

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

时间:2021-11-16 13:18     来源/作者:牧竹子

Springboot filter拦截token验证和跨域

背景

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

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

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

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

#springboot中实现filter

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

先有filter

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
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

?
1
@WebFilter(urlPatterns = { “/api/*” }, filterName = “tokenAuthorFilter”)

硬编码注册filter

在application.java中加入如下代码

?
1
2
3
4
5
6
7
8
9
10
11
//注册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中加入如下代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//跨域设置
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类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**********
 * 跨域 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类

加注解:

?
1
@WebFilter(filterName = "authFilter", urlPatterns = "/*")

代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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.启动类

加注解:

?
1
@ServletComponentScan(basePackages = {"com.activiti.filter"})

代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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请求代码实例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<!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>

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

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

原文链接:https://blog.csdn.net/zjcjava/article/details/78237164

相关文章

热门资讯

yue是什么意思 网络流行语yue了是什么梗
yue是什么意思 网络流行语yue了是什么梗 2020-10-11
背刺什么意思 网络词语背刺是什么梗
背刺什么意思 网络词语背刺是什么梗 2020-05-22
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
2021年耽改剧名单 2021要播出的59部耽改剧列表
2021年耽改剧名单 2021要播出的59部耽改剧列表 2021-03-05
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总 2020-11-13
返回顶部