使用filter进行登录的拦截,统一验证用户登录信息是否有效

1需求

在用户进行所有的操作之前都要验证当前用户是否登录有效,如果每个方法调用前都去验证显得比较蠢,于是使用filter在接口之前统一拦截验证;

2.方案的选择

简单的来说就是实现用户的登录。刚开始我是采用session和cookie进行用户登录的,可是涉及到跨域的问题。其实我在网上查了下,前端可以实现跨域的请求带上cookie。可是人家前端不改!!!!!!!!微笑。非得要用在请求中带入token,后端自己验证token是否有效的流程!再次告诉自己微笑。

刚开始我采用的是intercepter,拦截器,但是不行,后文会有介绍。于是采用了filter,过滤器。

3.实现

1.首先在web.xml文件中配置拦截路径

  <!-- 使用filter实现登录控制  -->
  <filter>
    <filter-name>SessionFilter</filter-name>
    <filter-class>com.aaa.bbb.controller.login.LoginInterceptor</filter-class>
    <init-param>
    <param-name>ignores</param-name>
    <param-value>/api/web/login,api/web/sso_login,/web/*</param-value>
    </init-param>

  </filter>
  <filter-mapping>
    <filter-name>SessionFilter</filter-name>
    <url-pattern>/api/web/*</url-pattern>
    <!-- <url-pattern>/api/no/*</url-pattern> -->
  </filter-mapping>

<param-name>ignores</param-name>
    <param-value>/api/web/login,api/web/sso_login,/web/*</param-value>

这里是不进行拦截的路径,会在com.aaa.bbb.controller.login.LoginInterceptor 中进行过滤

<url-pattern>/api/web/*</url-pattern> 进行拦截的路径

2.拦截器

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

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;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.CrossOrigin;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jf.cloud.config.StaticMapUserInfo;
import com.mysql.fabric.xmlrpc.base.Data;

/**
 * @Description
 * @Author
 * @Date 2018年11月2日
 */
@CrossOrigin(origins = "*", maxAge = 3600)
public class LoginInterceptor  implements Filter{
    
    
     private String excludedPage;
     private String[] excludedPages;
    
     //sso的访问地址
     @Value("${ssoURL}")
     String ssoURL;
        

     //定义filter不拦截的路径
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
         //此处的ignores就是在web.xml定义的名称一样。
         excludedPage = filterConfig.getInitParameter("ignores");
        
         if (excludedPage != null && excludedPage.length() > 0){
             excludedPages = excludedPage.split(",");
             }
        
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        
        //解决跨域问题,统一处理
        HttpServletResponse resp = (HttpServletResponse) response;
        resp.setHeader("Access-Control-Allow-Origin", "*");
        resp.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        resp.setHeader("Access-Control-Max-Age", "3600");
        resp.addHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
       
        
        //由于httprequest的getReader只能使用一次,这里将reader流保存下来
        BodyReaderHttpServletRequestWrapper requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) request);
        //排除不使用filter的路径
        for (String page : excludedPages) {
            String url = ((HttpServletRequest) request).getServletPath();
            if (url.equals(page)) {
                chain.doFilter(requestWrapper, resp);
                return;
            }

        }
        
    
        //读取http request 请求体总body的数据
         BufferedReader br = null;
            StringBuilder sb = new StringBuilder("");
            try
            {
              
                br =  requestWrapper.getReader();
                String str;
                while ((str = br.readLine()) != null)
                {
                    sb.append(str);
                }
                br.close();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            finally
            {
                if (null != br)
                {
                    try
                    {
                        br.close();
                    }
                    catch (IOException e)
                    {
                        e.printStackTrace();
                    }
                }
            }
          
                    
    
        //判断是否已经登录            
        String data = sb.toString();
        
        //验证用户登录格式
        if(data.equals("")){
            resp.setCharacterEncoding("UTF-8");  
            resp.setContentType("application/json; charset=utf-8");
            PrintWriter out = null ;
            JSONObject res = new JSONObject();
            res.put("result",false);
            res.put("code","400");
            res.put("message","验证格式未正确输入");
            out = resp.getWriter();
            out.append(res.toString());
            return ;
        }
        
        JSONObject jvo  = JSONObject.parseObject(data).getJSONObject("vertification");
        
        //拿到用户登录的token
        String token = jvo.getString("tokenID");
        //type用于区分是手机登录还是电脑登录,走不同的验证
        String type = jvo.getString("type");
        
        if(type.equals("pc")){//web的验证
            
            if(StaticMapUserInfo.getUserInfoMap().containsKey(token)){//如果用户已经登录
                
                //判断用户登录信息是否失效
                Date lastTime = (Date) StaticMapUserInfo.getUserInfoMap().get(token+"_time");
                Date now = new Date();
                if((now.getTime()-lastTime.getTime())<60*2*1000*60){//2小时登录有效
                    StaticMapUserInfo.getUserInfoMap().put(token+"_time", now);
                    chain.doFilter(requestWrapper, resp);
                }else{//用户登录失效
                    //移除用户登录信息
                    StaticMapUserInfo.getUserInfoMap().remove(token);
                    StaticMapUserInfo.getUserInfoMap().remove(token+"_time");
                    
                    //提示用户登录
                    resp.setCharacterEncoding("UTF-8");  
                    resp.setContentType("application/json; charset=utf-8");
                    PrintWriter out = null ;
                    JSONObject res = new JSONObject();
                    res.put("result",false);
                    res.put("code","414");
                    res.put("message","当前用户登录已经失效,请重新登录");
                    out = resp.getWriter();
                    out.append(res.toString());
                }
                
                
                
            }else{
                resp.setCharacterEncoding("UTF-8");  
                resp.setContentType("application/json; charset=utf-8");
                PrintWriter out = null ;
                JSONObject res = new JSONObject();
                res.put("result",false);
                res.put("code","400");
                res.put("message","当前用户未登录,请登录");
                out = resp.getWriter();
                out.append(res.toString());
              
            }
            
            
        }else if(type.equals("app")){//手机的验证
            
            //封装sso token验证的参数
            Map<String, Object> param = new HashMap<String, Object>();
            //拿到用户登录的token
            Map<String, String> tokenmap = new HashMap<String, String>();
            tokenmap.put("TokenID", token);
            param.put("Method", "aaa.ssouserauth");
            param.put("Version","3.1");
            param.put("Certification", tokenmap);
            
            JSON json = (JSON) JSONObject.toJSON(param);
            
            
            //访问sso的登录,并返回登陆结果
            JSONObject rso = SSOLoginController.sendPost(ssoURL,json);
            if (rso.getBooleanValue("Result")) {//用户登录成功
                chain.doFilter(requestWrapper, resp);
            }else{
                resp.setCharacterEncoding("UTF-8");  
                resp.setContentType("application/json; charset=utf-8");
                PrintWriter out = null ;
                JSONObject res = new JSONObject();
                res.put("result",false);
                res.put("code","400");
                res.put("message",rso.getString("Message"));
                out = resp.getWriter();
                out.append(res.toString());
            }
            
            
            
            
        }else{
            resp.setCharacterEncoding("UTF-8");  
            resp.setContentType("application/json; charset=utf-8");
            PrintWriter out = null ;
            JSONObject res = new JSONObject();
            res.put("result",false);
            res.put("code","400");
            res.put("message","验证类型错误");
            out = resp.getWriter();
            out.append(res.toString());
          
        }
        
        

        
        
    
        

}
        
    

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        
    }
    
}


    

 //sso的访问地址
     @Value("${ssoURL}")
     String ssoURL;

其他系统的sso验证地址

//解决跨域问题,统一处理
        HttpServletResponse resp = (HttpServletResponse) response;
        resp.setHeader("Access-Control-Allow-Origin", "*");
        resp.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        resp.setHeader("Access-Control-Max-Age", "3600");
        resp.addHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");

这里对response最跨域的处理,必须加上

/**
 * @Description
 * @Author
 * @Date 2018年11月5日
 */

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class BodyReaderHttpServletRequestWrapper
        extends
            HttpServletRequestWrapper {
    

    private final byte[] body;

    public BodyReaderHttpServletRequestWrapper(HttpServletRequest request)
            throws IOException {
        
        super(request);
        body = toByteArray(request.getInputStream());
    }

    private byte[] toByteArray(InputStream in) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024 * 4];
        int n = 0;
        while ((n = in.read(buffer)) != -1) {
            out.write(buffer, 0, n);
        }
        return out.toByteArray();
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
        return new ServletInputStream() {

            @Override
            public int read() throws IOException {
                return bais.read();
            }
        };
    }
}

//由于httprequest的getReader只能使用一次,这里将reader流保存下来
        BodyReaderHttpServletRequestWrapper requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) request);
   否则会报错   

getReader() has already been called for this request

import java.util.HashMap;
import java.util.Map;

/**
 * @Description 存储用户登录信息
 * @Author zengzhiqiang
 * @Date 2018年11月5日
 */

public class StaticMapUserInfo {
    
    public static  Map<String, Object> userInfoMap ;
    
    
    
    
    public static Map<String, Object> getUserInfoMap() {
        
        if(userInfoMap==null){
            userInfoMap = new HashMap<String, Object>();
        }
        return userInfoMap;
    }
    
    
    public static void setUserInfoMap(Map<String, Object> userInfoMap) {
        StaticMapUserInfo.userInfoMap = userInfoMap;
    }

    
}

这里使用了一个单列的map代替redis的存储作用

 /**
     * 向指定的 URL发送远程POST方法的请求
     *
     * @param url发送请求的  URL
     * @param json请求参数,
     * @return 所代表远程资源的响应结果
     */
    public static JSONObject sendPost(String url, JSON json) {
        PrintWriter out = null;
        BufferedReader in = null;
        JSONObject jsonObject = null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestMethod("POST");
            // 发送POST请求必须设置下面的属性
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            //设置请求属性
            conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
            conn.connect();
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            // 发送请求参数
            out.print(JSON.toJSONString(json));
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line = "";
            while ((line = in.readLine()) != null) {
                result += line;
            }
            //将返回结果转换为字符串
            jsonObject = JSONObject.parseObject(result);
        } catch (Exception e) {
            throw new RuntimeException("远程通路异常" + e.toString());
        }
        // 使用finally块来关闭输出流、输入流
        finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return jsonObject;
    }

验证其他系统的token在本系统的使用

3.入参

 如果使用interceper,程序运行不会报错,但是会出现错误

Failed to read HTTP message Required request body is missing:

会解析不到处理后的request body,这可能会与标签 @requestbody,有关

结束!

=======================================

看云,看雨,看天,看未知的秋天 ----记录

猜你喜欢

转载自blog.csdn.net/zzqtty/article/details/83857989