前言
當用戶訪問我們的某些接口時,我們會去校驗用戶是否登錄或者是用戶是否有權限,比如我們一些管理員的功能就是不提供用戶使用的。
這一系列的校驗權限是很常用的,所以我們可以去配置SpringMVC攔截器,當用戶訪問我們的接口時,會自動的校驗權限。
1.在SpringMVC中配置上我們的攔截器以及攔截的路徑
/* 當面路徑下的所有路徑,不包含子文件夾
/** 指的是所有路徑以及里面的子路徑
/ web項目的根目錄請求

2.配置我們的攔截器
首先在我們要在存放攔截器的路徑下創建一個java類,隨后使該類實現接口(HandlerInterceptor)並實現接口中的三個方法
2.1 preHandle() 攔截目標執行前,執行該方法。該方法有返回值(Boolean),若返回true則放行執行目標,若返回false則攔截不放行目標。
2.2 postHandle() 攔截目標執行后,執行該方法
2.3 afterCompletion() 攔截目標執行所有后,執行該方法
問題一:在攔截器的配置上,當我們需要注意攔截的時候別攔截到登錄功能,當我們在進行管理員登錄的時候,調用了管理員登錄的接口。在調用的時候我們就被攔截器攔截了,此時我們還沒登錄就被攔截報錯了。

所以我們應該想辦法解決攔截登錄的循環。
方法1:在springmvc配置文件中,編輯攔截器使之忽略攔截該路徑

方法2:在攔截器中加上邏輯判斷,當攔截到的目標,是對應類中的對應方法時,放行
//解析HandlerMethod String methodName = handlerMethod.getMethod().getName(); String className = handlerMethod.getBean().getClass().getSimpleName(); if(StringUtils.equals(className,"UserManageController") && StringUtils.equals(methodName,"login")){ //如果是攔截到登錄請求,不打印參數,因為參數里面有密碼,全部會打印到日志中,防止日志泄露 log.info("權限攔截器攔截到請求,className:{},methodName:{}",className,methodName); return true; } |
問題二: 在攔截器中我們統一設置了返回格式為Json,但是在我們產品的圖片上傳中有涉及到富文本上傳,富文本的上傳
返回值為Map形式,所以我們還需改進攔截器
解決方法:在返回值處細化返回內容。加入if判斷
if(user ==null){ if(StringUtils.equals(className,"ProductManageController") && StringUtils.equals(methodName,"richtextImgUpload")){ Map resultMap = Maps.newHashMap(); resultMap.put("success",false); resultMap.put("msg","請登錄管理員"); out.print(JsonUtil.obj2String(resultMap)); }else { out.print(JsonUtil.obj2String(ServerResponse.createByErrorMessage("攔截器攔截,用戶未登錄"))); } }else{ if(StringUtils.equals(className,"ProductManageController") && StringUtils.equals(methodName,"richtextImgUpload")){ Map resultMap = Maps.newHashMap(); resultMap.put("success",false); resultMap.put("msg","無權限操作"); out.print(JsonUtil.obj2String(resultMap)); }else { out.print(JsonUtil.obj2String(ServerResponse.createByErrorMessage("攔截器攔截,無權限操作"))); }
} |
注意:在做完攔截器后,修改原先Controller中的代碼時,需注意保留圖片上傳到FTPServer中的功能,
攔截器代碼:
@Slf4j public class AuthorityInterceptor implements HandlerInterceptor {
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { log.info("preHandle"); //請求中Controller中的方法名 HandlerMethod handlerMethod = (HandlerMethod) handler;
//解析HandlerMethod String className = handlerMethod.getBean().getClass().getSimpleName();//請求目標類名 String methodName = handlerMethod.getMethod().getName();//請求目標方法名
//解析參數,具體的參數key以及value是什么,打印日志 StringBuffer requestParamBuffer = new StringBuffer(); Map paramMap = request.getParameterMap();//獲取請求參數Map
//遍歷Map,並且拼接成字符串 Iterator iterator = paramMap.entrySet().iterator(); while (iterator.hasNext()){ Map.Entry entry = (Map.Entry)iterator.next(); String mapkey = (String)entry.getKey(); String mapValue = StringUtils.EMPTY;
//request這個參數的map(ParameterMap),里面的value返回的是一個String[] Object obj = entry.getValue(); if(obj instanceof String[]){ String[] strs = (String[])obj; mapValue = Arrays.toString(strs); } requestParamBuffer.append(mapkey).append("=").append(mapValue);
}
//放行管理員登錄接口,避免登錄循環 if(StringUtils.equals(className,"UserManageController") && StringUtils.equals(methodName,"login")){ //如果是攔截到登錄請求,不打印參數,因為參數里面有密碼,全部會打印到日志中,防止日志泄露 log.info("權限攔截器攔截到請求,className:{},methodName:{}",className,methodName); return true; }
//從Cookie中獲取到登錄的Token,然后去Redis中獲取出來登錄的用戶 User user = null; String loginToken = CookieUtil.readLoginToken(request);
if(StringUtils.isNotEmpty(loginToken)){ String userJsonStr = RedisShardedPoolUtil.get(loginToken); user = JsonUtil.string2Obj(userJsonStr,User.class); }
//判斷用戶是否登錄 || 是否為管理員 if(user == null || (user.getRole().intValue() != Const.Role.ROLE_ADMIN) ){ //返回false即不會調用controller里的方法 //以下要更改返回值,首先重置response。 response.reset();//這里要添加reset,否則報異常 getWriter() has already been called for this response. response.setCharacterEncoding("UTF-8");//由於response重置了,所以要重新設置編碼,否則會亂碼 response.setContentType("application/json;charset=UTF-8");//由於response重置了,所以要重新設置返回值的類型,因為全部是json接口。
PrintWriter out = response.getWriter();
if(user ==null){ out.print(JsonUtil.obj2String(ServerResponse.createByErrorMessage("攔截器攔截,用戶未登錄"))); }else{ out.print(JsonUtil.obj2String(ServerResponse.createByErrorMessage("攔截器攔截,無權限操作"))); } out.flush(); out.close();//這里要關閉流
return false; } return true; }
@Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { log.info("postHandle"); }
@Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { log.info("afterCompletion"); } } |