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 [email protected] * @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> <a href= "#" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" rel= "external nofollow" >發布</a> <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