过滤器,白名单+接口token验证

1、过滤器实现

package com.zrar.arask.cs.filter;

import com.zrar.arask.cs.util.JWTUtil;
import com.zrar.easyweb.core.util.StringUtil;
import com.zrar.easyweb.jose.jwt.SignedJWT;
import com.zrar.easyweb.util.GsonUtil;
import com.zrar.easyweb.web.core.bean.JsonResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * 消息服务令牌校验拦截器
 */
public class MessageServiceFilter implements Filter{

	private Logger logger = LoggerFactory.getLogger(MessageServiceFilter.class);
	// 服务Urls
	private String[] serviceUrls = {};
	// 是否启用时间限制
	private boolean enableTimeLimit = false;
	// 时效长(默认15分钟)
	public static final AtomicLong TIME_LIMIT_APP_SERVICE = new AtomicLong(15 * 60 * 1000);

	// 无效密钥
	public static final int CODE_TOKEN_INVALID = 40001;
	// 密钥格式错误
	public static final int CODE_TOKEN_FORMAT_ERROR = 40002;
	// 缺失token信息
	public static final int CODE_TOKEN_MISSING = 41001;
	// token超时
	public static final int CODE_TOKEN_TIMEOUT = 42001;


	@Override
	public void init(FilterConfig config) throws ServletException {
		String urls = StringUtil.null2Str(config.getInitParameter("serviceUrls"));
		// 参数不为空,初始化服务路径信息
		if (urls.length() > 0) {
			serviceUrls = urls.split(",");
		}

		// 是否启用token时限
		String enableTimeLimit = StringUtil.null2Str(config.getInitParameter("enableTimeLimit"));
		this.enableTimeLimit = enableTimeLimit.equals("true") || enableTimeLimit.equals("1");
		if (logger.isInfoEnabled()) {
			logger.info("Service Token 时效控制 {}", this.enableTimeLimit ? "启用" : "未启用");
		}

		// 时效长
		String timeLimit = StringUtil.null2Str(config.getInitParameter("timeLimit"));
		if (StringUtil.isNotNull(timeLimit)) {
			if (StringUtil.isNumeric(timeLimit)) {
				int min = Integer.parseInt(timeLimit);
				TIME_LIMIT_APP_SERVICE.set(min * 60 * 1000);
				if (logger.isInfoEnabled()) {
					logger.info("Service Token 时效长度 {} 分钟", TIME_LIMIT_APP_SERVICE.get() / 60 / 1000);
				}
			} else {
				logger.error("web.xml > MessageServiceFilter [ timeLimit ] 参数必须为数字");
			}
		}
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {

		// 请求地址
		HttpServletRequest req = ((HttpServletRequest) request);
		String contextPath = req.getSession().getServletContext().getContextPath();
		String visitURL = req.getRequestURI();

		// 验证该地址是否需要验证
		boolean flag = this.isValidateUrl(visitURL, contextPath);
		if (flag == true) {
			//白名单
			chain.doFilter(request, response);
			return;
		}

		// 令牌信息
		String stoken = StringUtil.null2Str(request.getParameter("stoken"));
		// 没有令牌信息,拒绝服务
		if (StringUtil.isNull(stoken)) {
			this.forbidden(response, CODE_TOKEN_MISSING, "没有发现令牌");
			return;
		}

		// 默认令牌验证不通过
		boolean result = false;
		SignedJWT jwt = null;
		try {
			// 验证令牌有效性
			jwt = JWTUtil.verifyToken(stoken);
			result = jwt.verify(JWTUtil.getJWTVerifier(JWTUtil.getJWTSecret()));

			// 如果启用了时限,检查时限
			if (result == true && enableTimeLimit == true) {
				Date expirationTime = jwt.getBaseClaimsSet().getExpirationTime();
				Date now = new Date();
				boolean isInTime = now.before(expirationTime);
				// 已经超过时限
				if (isInTime == false) {
					if (logger.isInfoEnabled()) {
						logger.info("Service Token 已失效");
					}
					forbidden(response, CODE_TOKEN_TIMEOUT, "令牌已失效");
					return;
				}
			}
			if (logger.isInfoEnabled()) {
				logger.info("Service Token Check :[{}] > {}", result, stoken);
			}
		} catch (Exception e) {
			if (logger.isInfoEnabled()) {
				logger.info("Service Token Check :[格式不正确] > {}", stoken);
			}
			forbidden(response, CODE_TOKEN_FORMAT_ERROR,"令牌格式不正确");
			return;
		}
		// 验证通过,继续服务
		if (result == true) {
			// 设置服务检查通过变量,便于在session验证时通过该请求
			request.setAttribute("app_service_auth_result", 1);
			chain.doFilter(request, response);
		} else {
			// 验证不通过,拒绝服务
			forbidden(response, CODE_TOKEN_INVALID, "无效令牌");
			return;
		}
	}

	@Override
	public void destroy() {
	}

	/**
	 * 拒绝服务
	 *
	 * @param response
	 * @throws IOException
	 */
	private void forbidden(ServletResponse response,int code, String message) throws IOException {
		JsonResult result =new JsonResult();
		result.setMsg(message);
		result.setCode(code);
		response.setCharacterEncoding("UTF-8");
		response.setContentType("application/json");
		PrintWriter out = response.getWriter();
		out.write(GsonUtil.bean2json(result));
		out.flush();
		out.close();
	}

	/**
	 * 是否属于验证的URL地址
	 *
	 * @param currentRequestURL
	 * @param
	 * @param
	 * @return
	 */
	private boolean isValidateUrl(String currentRequestURL,String contextPath) {
		for (String url : this.serviceUrls) {
			Pattern p = Pattern.compile(contextPath + url);
			Matcher matcher = p.matcher(currentRequestURL);
			boolean matches = matcher.matches();
			if (matches) {
				return true;
			}
		}
		return false;
	}
}

2、过滤器配置,xml

 <!-- MESSAGE QUERY -->
    <filter>
        <filter-name>MessageServiceFilter</filter-name>
        <filter-class>com.zrar.arask.cs.filter.MessageServiceFilter</filter-class>
        <init-param>
            <param-name>serviceUrls</param-name>
            <param-value>
                /custom/config,/custom/checkState,/custom/idleGroup,/custom/groupInfos,/message/sendMessage
            </param-value>
        </init-param>
        <init-param>
            <param-name>enableTimeLimit</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>timeLimit</param-name>
            <param-value>1</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>MessageServiceFilter</filter-name>
        <url-pattern>/message/*</url-pattern>
    </filter-mapping>
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值