网页中ajax请求的referrer的值是当前
域名。
所以对于一些简单的安全验证可以通过这样的方式来做。
下面是我的实现。
class="java">
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;
}