• 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);
        }
    
    
    } 
  • 相关阅读:
    回头再看libpcap
    lex error
    perl 的威力
    什么叫回流和重绘?
    HTTP协议与FTP协议的区别【转】
    Linux操作系统Redhat系列与Debian系列 【转】
    dock是什么? docker就是集装箱原理【转】
    光端机的作用【转】
    c++ -- call_once用法
    c++ -- thread详细解析
  • 原文地址:https://www.cnblogs.com/huangjinyong/p/9228894.html
Copyright © 2020-2023  润新知