背景
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); } }
