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> <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>
大功告成 回家睡觉 嘻嘻嘻~
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。