HandlerInterceptor 拦截器有三个方法:preHandle、postHandle、afterCompletion。
package org.springframework.web.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
public interface HandlerInterceptor {
boolean preHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
void postHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3, ModelAndView var4) throws Exception;
void afterCompletion(HttpServletRequest var1, HttpServletResponse var2, Object var3, Exception var4) throws Exception;
}
- preHandle:处理器的预处理,返回true表示流程继续,或者返回结果或者移交给下一个拦截器;返回false表示不会继续处理(流程中断),而是直接response。不会继续调用postHandle和afterCompletion方法。
- postHandle:后处理回调方法,发生在视图渲染之前。参数ModelAndView可以为空,不为空时会对数据进行处理或者视图渲染。
- afterCompletion:整个请求处理完毕回调方法,即在视图渲染完毕时回调。
HandlerInterceptor实现类的执行过程
preHandler() -> Controller -> postHandler() -> model渲染-> afterCompletion()
实战
AdvertiserAuthInterceptor 拦截器,拦截注解@AdvertiserAuthRequired
@Slf4j
@Component
public class AdvertiserAuthInterceptor implements HandlerInterceptor
{
@Resource
private TokenService tokenService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
boolean assignableFrom = handler.getClass().isAssignableFrom(HandlerMethod.class);
log.debug("apply auth interceptor in method", handler.getClass().toString());
if (assignableFrom) {
AdvertiserAuthRequired auth = ((HandlerMethod) handler).getMethodAnnotation(AdvertiserAuthRequired.class);
if (auth == null) {
log.info("The method is not intercepted by AdvertiserRequired");
return true;
} else {
try {
String method = request.getMethod();
String channel = "";
String advertiserId = "";
if (method.equals(HttpMethod.GET.toString()))
{
channel = request.getParameter("channel");
advertiserId = request.getParameter("advertiser_id");
}
else if (method.equals(HttpMethod.POST.toString()) || method.equals(HttpMethod.PUT.toString()))
{
BodyCachingRequestWrapper wrapper = (BodyCachingRequestWrapper) request;
String body = wrapper.getBody();
JsonElement element = JsonParser.parseString(body);
JsonObject object = element.getAsJsonObject();
channel = object.get("channel").getAsString();
advertiserId = object.get("advertiser_id").getAsString();
}
if (!StringUtils.hasLength(advertiserId) || !StringUtils.hasLength(channel))
{
log.info("Required advertiser_id and channel missing");
EbAuthUtil.setFailResponse(response, EbErrorCode.AD_INPUT_MISSING);
return false;
}
EbUser subject = EbAuthUtil.getSubject(request);
String accessToken = tokenService.retrieveAccessToken(subject, advertiserId, AdChannel.valueOf(channel));
return EbAuthUtil.setRequestHeader(request, response, EbConstants.EB_AK, accessToken);
}
catch (EbException ex)
{
log.info("Couldn't find advertiserId and channel info in request body");
return EbAuthUtil.setFailResponse(response, ex.getErrorCode(), ex.getMsg(), ex.getDetail());
}
catch (RuntimeException ex)
{
log.info("Failed to retrieve active accessToken");
return EbAuthUtil.setFailResponse(response, EbErrorCode.UNKNOWN_ERROR.getErrorCode(), EbErrorCode.UNKNOWN_ERROR.getErrorMsg(),
ex.getMessage());
}
}
}
return true;
}
}
注解@AdvertiserAuthRequired
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AdvertiserAuthRequired
{
}
AuthInterceptor拦截@AuthRequired
@Component
@Slf4j
public class AuthInterceptor implements HandlerInterceptor
{
public static String API_KEY;
public static byte[] API_KEY_SECURE_BYTES;
private final String AUTH_HEADER = "Authorization";
private final String TOKEN_PREFIX = "Bearer";
@Value("${jwt.key}")
public void setApiKey(String key)
{
API_KEY = key;
API_KEY_SECURE_BYTES = Base64.getUrlEncoder().encode(API_KEY.getBytes());
}
private Gson gson = new GsonBuilder().create();
@Resource
private EbUserMapper userMapper;
@Resource
private EbTeamMapper teamMapper;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
{
boolean assignableFrom = handler.getClass().isAssignableFrom(HandlerMethod.class);
log.debug("apply auth interceptor in method", handler.getClass().toString());
if (assignableFrom)
{
AuthRequired auth = ((HandlerMethod) handler).getMethodAnnotation(AuthRequired.class);
if (auth == null)
{
log.info("The method is not intercepted by AuthRequired");
return true;
}
else
{
String jwtToken = request.getHeader(AUTH_HEADER);
if (!StringUtils.hasLength(jwtToken) || !jwtToken.startsWith(TOKEN_PREFIX))
{
log.info("The request doesn't include Bearer token");
return EbAuthUtil.setFailResponse(response, EbErrorCode.JWT_TOKEN_INVALID);
}
try
{
jwtToken = jwtToken.substring(TOKEN_PREFIX.length() + 1);
String email = SecurityUtil.parseJwt(jwtToken);
//获取用户信息
LambdaQueryWrapper<EbUser> queryWrapper = new LambdaQueryWrapper<>();
EbUser ebUser = userMapper.selectOne(queryWrapper.eq(EbUser::getEmail, email));
if (ebUser == null || ebUser.isDeleted())
{
log.info("User with email {} already been deleted or not existed", email);
return EbAuthUtil.setFailResponse(response, EbErrorCode.USER_NOT_EXIST);
}
if (ebUser.getEbRole().role != EbRole.COMPANY_ADMIN.role) {
EbTeam team = teamMapper.selectById(ebUser.getTeamId());
if (team == null || team.getTeamStatus().getValue() == EbStatus.UNABLE.status)
{
log.info("Team {} is disabled now, no permission", email);
return EbAuthUtil.setFailResponse(response, EbErrorCode.TEAM_DISABLED);
}
}
if (ebUser.getUserStatus().getValue() == EbStatus.UNABLE.status)
{
log.info("User {} is disabled now, no permission", email);
return EbAuthUtil.setFailResponse(response, EbErrorCode.USER_DISABLED);
}
String requesterStr = gson.toJson(ebUser);
if (EbRole.TEAM_LEADER.equals(auth.roleRequired()))
{
if (ebUser.getEbRole().role == EbRole.NORMAL_USER.role)
{
return EbAuthUtil.setFailResponse(response, EbErrorCode.USER_AUTHORIZATION_ERROR);
}
}
else if (EbRole.COMPANY_ADMIN.equals(auth.roleRequired()))
{
if (ebUser.getEbRole().role != EbRole.COMPANY_ADMIN.role)
{
return EbAuthUtil.setFailResponse(response, EbErrorCode.USER_AUTHORIZATION_ERROR);
}
}
return EbAuthUtil.setRequestHeader(request, response, EbConstants.EB_REQUESTER, requesterStr);
}
catch (ExpiredJwtException ex)
{
log.info("Jwt token expired {}", jwtToken);
return EbAuthUtil.setFailResponse(response, EbErrorCode.JWT_TOKEN_EXPIRE);
}
catch (RuntimeException ex)
{
log.info("Jwt token is invalid {}", jwtToken);
return EbAuthUtil.setFailResponse(response, EbErrorCode.JWT_TOKEN_INVALID);
}
}
}
return true;
}
}
注解@AuthRequired
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthRequired
{
String permRequired() default "";
EbRole roleRequired() default EbRole.NORMAL_USER;
}
配置类
@Configuration
public class WebInterceptorConfig extends WebMvcConfigurationSupport
{
@Resource
private AuthInterceptor authInterceptor;
@Resource
private AdvertiserAuthInterceptor advertiserAuthInterceptor;
protected void addInterceptors(InterceptorRegistry registry)
{
registry.addInterceptor(authInterceptor).addPathPatterns("/ebcc/**");
registry.addInterceptor(authInterceptor).addPathPatterns("/ebuc/**");
registry.addInterceptor(authInterceptor).addPathPatterns("/msg-center/**");
registry.addInterceptor(authInterceptor).addPathPatterns("/ebad/**");
registry.addInterceptor(advertiserAuthInterceptor).addPathPatterns("/ebad/**");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html").addResourceLocations(
"classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
super.addResourceHandlers(registry);
}