目录
一、需求
为了防止刷接口行为,我们要加上访问功能接口时需要登录并且限制登录时长的拦截器
二、代码实现
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.qt.intelliteach5g.controller.sso.RequestSsoController;
import com.qt.intelliteach5g.util.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import redis.clients.jedis.JedisCluster;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
@Configuration
public class AdminInterceptor extends HandlerInterceptorAdapter {
@Autowired
RedisService redisService;
private long timestampRang=600;//单位秒
public final static String ADMIN_LOGIN_TOKEN_PREFIX = "manager:";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
//时间戳判定,防止重放攻击
String timestamp = InterceptorUtil.getTimestampFromRequest(request);
if (timestamp==null||timestamp.isEmpty()) {
InterceptorUtil.responseResult(response,"请加入时间戳",-1);
return false;
}
long requestTimestamp = Long.valueOf(timestamp);
long nowTimestamp=new Date().getTime();
if (Math.abs(nowTimestamp-requestTimestamp)>timestampRang*1000) {
InterceptorUtil.responseResult(response,"请求时间戳与后台时间戳相差超过10分钟,拒绝访问",-1);
return false;
}
//token鉴定
String tokenKey= ADMIN_LOGIN_TOKEN_PREFIX+InterceptorUtil.getTokenFromRequest(request);
String resultString = (String) redisService.get(tokenKey);
if (resultString==null) {
InterceptorUtil.responseResult(response,"token无效",-999);
return false;
}else {
redisService.set(resultString, 1800);
request.setAttribute("loginUserId",this.getUserIdFromRequest(resultString));
}
/鉴权
//获取当前用户拥有的权限
// long loginUserId = (long) request.getAttribute("loginUserId");
// List<Integer> userHavePermissionList = menuDao.queryByAdminUserId(loginUserId);
// //获取当前请求地址需要的权限
// List<Integer> requestNeedPermissionList = this.getRequestNeedPermissionList((HandlerMethod) o);
// //鉴权比较
// if (!userHavePermissionList.containsAll(requestNeedPermissionList)) {
// InterceptorUtil.responseResult(response,"无权限操作该接口",-998);
// return false;
// }
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
public String getUserIdFromRequest(String resultString) {
JSONObject jsonObject = JSON.parseObject(resultString);
String content = jsonObject.getString("content");
return JSON.parseObject(content).getString("id");
}
// public List<Integer> getRequestNeedPermissionList(HandlerMethod handlerMethod) {
// List<Integer> needPermissionList = new ArrayList<>();
// NeedPermissionIdArray needPermissionIdArrayAnnotation = handlerMethod.getMethod().getAnnotation(NeedPermissionIdArray.class);
// if (needPermissionIdArrayAnnotation!=null) {
// int[] value = needPermissionIdArrayAnnotation.value();
// for (int i : value) {
// needPermissionList.add(i);
// }
// }
// return needPermissionList;
// }
}
2)在springboot中,指定interceptor:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@EnableWebMvc
public class MyInterceptorConfig implements WebMvcConfigurer {
@Autowired
private AdminInterceptor interceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
System.out.println("执行了拦截器");
registry.addInterceptor(interceptor)
//添加需要验证登录用户操作权限的请求
.addPathPatterns("/manger/**")
//排除不需要验证登录用户操作权限的请求
.excludePathPatterns("/user/**");
}
3)interceptor的时间戳和token的HTTP工具类
import com.qt.intelliteach5g.util.JSONUtil;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
public class InterceptorUtil {
public static String getTokenFromRequest(HttpServletRequest request) {
String token=null;
token = request.getHeader("token");
if (token == null || token.isEmpty()) {
token = request.getParameter("token");
}
// if (token == null || token.isEmpty()) {
// Cookie[] cookies = request.getCookies();
// for (Cookie cookie : cookies) {
// if (cookie.getName().equals("token")) {
// token=cookie.getName();
// }
// }
// }
return token;
}
public static String getTimestampFromRequest(HttpServletRequest request) {
String token=null;
token = request.getHeader("timestamp");
if (token == null || token.isEmpty()) {
token = request.getParameter("timestamp");
}
// if (token == null || token.isEmpty()) {
// Cookie[] cookies = request.getCookies();
// for (Cookie cookie : cookies) {
// if (cookie.getName().equals("timestamp")) {
// token=cookie.getName();
// }
// }
// }
return token;
}
public static void responseResult(HttpServletResponse httpServletResponse, String message, int code) throws IOException {
httpServletResponse.setContentType("text/html; charset=utf-8");
PrintWriter writer = httpServletResponse.getWriter();
writer.write(JSONUtil.toErrorJson(code,message));
writer.flush();
writer.close();
}
public static String getRobotIdFromRequest(HttpServletRequest request) {
return request.getHeader("robotId");
}
public static String getRequestBody(HttpServletRequest request) {
String body= null;
try {
BufferedReader streamReader = new BufferedReader( new InputStreamReader(request.getInputStream(), "UTF-8"));
StringBuilder responseStrBuilder = new StringBuilder();
String inputStr;
while ((inputStr = streamReader.readLine()) != null)
responseStrBuilder.append(inputStr);
body=responseStrBuilder.toString();
} catch (Exception e) {
e.printStackTrace();
}
return body;
}
}
三、拦截器运行流程
1)首先需要登录获取token和当前的时间时间戳
2)访问接口的时候需要加上从登录上那获取到的token和时间戳作为参数传过去,这样才能有效的访问功能。
接口例子:http://localhost:8080/manger/permission/getAllPermissions?timestamp=1586307386000&token=3cb58179-9a6a-43e8-98b2-2e6e0680d8e5
说明:接口拦截器拦截的是/manger/**下的所有路径,我们想要访问就需要在接口上加上token和timestamp时间戳参数即可正常访问。