当前位置:首页 » JAVA技术教程

基于AOP的ajax的referrer判断

2018-03-15 17:41 本站整理 浏览(4)

网页中ajax请求的referrer的值是当前域名。
所以对于一些简单的安全验证可以通过这样的方式来做。
下面是我的实现。

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 用于ajax请求时,通过referrer对请求合法性做验证的注解
 * 注解的controller方法中必须包含HttpServletRequest和HttpServletResponse参数且参数被放置与参数列表最后request在前response在后
 * @author zhongjun.huang
 *
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface AjaxReferrerAuthentication {

	String hostString() default "hstong.com";
}

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.xxx.h5.support.annotation.AjaxReferrerAuthentication;
import com.xxx.h5.vo.MessageEntity;

@Aspect
@Component
public class AjaxReferrerAspect {

	private final Logger logger = LoggerFactory.getLogger(getClass());

	@Around(value = "execution(public * com.xxx.h5.controller..*(..)) && args(..,request,response) && @annotation(ajaxReferrer)")
	public MessageEntity authenticationReferrer(ProceedingJoinPoint jp,
			HttpServletRequest request, HttpServletResponse response, AjaxReferrerAuthentication ajaxReferrer) {

		// 由于Http规范以前对referrer写错,所以对两种写法都兼容下
		String referrer = StringUtils.isNotEmpty(request.getHeader("referer")) ? request.getHeader("referer")
				: request.getHeader("referrer"),
				errMsg = "";
		URL referrerURL = null;
		MessageEntity me = null;
		try {

			referrerURL = new URL(referrer);
		} catch (MalformedURLException e) {

			logger.info("验证referrer时,解析referrer地址异常");
			logger.info(jp.getClass() + "=>方法=>" + jp.getSignature() + "参数=>"
					+ Stream.of(jp.getArgs())
					.map(String::valueOf)
					.collect(Collectors.joining(",")));
			logger.error(e.getMessage());
			return me;
		}

		// 使用AjaxReferrerAuthentication注解的controller方法只给ajax请求,所以如果是从我们自己的页面过来的ajax请求一定是带上referrer的
		if (StringUtils.isEmpty(referrer)) {

			errMsg = "非法请求";
		} else if (!referrerURL.getHost().endsWith(ajaxReferrer.hostString())) {

			errMsg = "非法请求";
		}
		if (StringUtils.isNotEmpty(errMsg)) {

			try {
				response.sendError(HttpServletResponse.SC_FORBIDDEN);
			} catch (IOException e) {

				logger.info("验证referrer时,返回Http状态时异常(IO异常)");
				logger.info(jp.getClass() + "=>方法=>" + jp.getSignature() + "参数=>"
						+ Stream.of(jp.getArgs())
						.map(String::valueOf)
						.collect(Collectors.joining(",")));
				logger.error(e.getMessage());
			}
			return me;
		}
		try {
			me = (MessageEntity) jp.proceed();
		} catch (Throwable e) {

			logger.info("验证referrer后,执行切点方法时异常");
			logger.info(jp.getClass() + "=>方法=>" + jp.getSignature() + "参数=>"
					+ Stream.of(jp.getArgs())
					.map(String::valueOf)
					.collect(Collectors.joining(",")));
			logger.error(e.getMessage());
		}
		return me;
	}