頂部引入標簽庫:
<%@taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
在需要面對不同權限的用戶展示不同數據處添加:
<security:authorize access="hasAnyRole('ROLE_PRODUCT', 'ROLE_ADMIN')"> <li id="system-setting"><a href="${pageContext.request.contextPath}/product/findAll"> <i class="fa fa-circle-o"></i> 產品管理 </a></li> </security:authorize> <security:authorize access="hasAnyRole('ROLE_ORDER', 'ROLE_ADMIN')"> <li id="system-setting"><a href="${pageContext.request.contextPath}/order/findAll"> <i class="fa fa-circle-o"></i> 訂單管理 </a></li> </security:authorize>
經過上面的操作,僅僅是對不同權限的用戶顯示不同的按鈕,實際上權限並沒有控制住,用戶可以通過地址欄手動輸入需要訪問的地址,從而訪問不在他權限范圍內的數據
總結:頁面動態菜單的展示只是為了用戶體驗,並未真正控制權限!
授權操作:
SpringSecurity可以通過注解的方式來控制類或者方法的訪問權限。需要開啟對應的注解支持,若注解放在controller類中,對應注解支持應該放在mvc配置文件中,因為controller類是由mvc配置文件掃描並創建的(子容器),同理,若注解放在service類中,對應注解支持應該放在spring(applicationContext或spring-security[父容器])配置文件中,與此同理的有spring聲明式事務控制。建議放在service類中,因為父容器不會被http請求訪問到,相對更安全一些,http請求只會訪問子容器,再由子容器訪問父容器,注意:父容器不能訪問子容器
開啟授權的注解支持:這里演示三類注解,但實際開發中,用一類即可!
<!-- 開啟權限控制的注解支持 secured-annotations:SpringSecurity內部的權限控制注解開關 pre-post-annotations:spring指定的權限控制注解開關 jsr250-annotations:開啟jsr250-api的注解,需要jsr250-api的jar包--> <security:global-method-security secured-annotations="enabled" pre-post-annotations="enabled" jsr250-annotations="enabled"/>
jsr250-api的支持
<dependency> <groupId>javax.annotation</groupId> <artifactId>jsr250-api</artifactId> <version>1.0</version> </dependency>
在注解支持對應類或者方法上添加注解:
@Controller // @Secured({"ROLE_PRODUCT", "ROLE_ADMIN"}) // SpringSecurity內部制定的注解 // @RolesAllowed({"ROLE_PRODUCT", "ROLE_ADMIN"}) // jsr250注解 @PreAuthorize("hasAnyRole('ROLE_PRODUCT', 'ROLE_ADMIN')") // spring的el表達式注解 @RequestMapping("/product") public class ProductController { @RequestMapping("/findAll") public String findAll(){ return "product-list"; } }
@Controller @RequestMapping("/order") public class OrderController { @Secured({"ROLE_ORDER", "ROLE_ADMIN"}) @RequestMapping("/findAll") public String findAll(){ return "order-list"; } }
權限不足異常處理:每次權限不足都出現403頁面,着實難堪!
方式一:在 spring-security.xml配置文件中處理(只能處理403異常,其他異常無法處理)
<security:http auto-config="true" use-expressions="true"> <!--省略其它配置--> <!-- 處理403異常 --> <security:access-denied-handler error-page="/403.jsp"/> </security:http>
方式二:在 web.xml中處理
<error-page> <error-code>403</error-code> <location>/403.jsp</location> </error-page>
<error-page> <error-code>404</error-code> <location>/404.jsp</location> </error-page>
方式三:編寫異常處理器(建議使用)
springmvc傳統方式:
@Component public class HandlerControllerException implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { ModelAndView mv = new ModelAndView(); if (e instanceof AccessDeniedException) { mv.setViewName("redirect:/403.jsp"); } else { mv.setViewName("redirect:/500.jsp"); } return mv; } }
更簡便方式:
@ControllerAdvice public class HandlerControllerAdvice { // 只有出現AccessDeniedException異常才跳轉403.jsp頁面 @ExceptionHandler(AccessDeniedException.class) public String handlerException(){ return "redirect:/403.jsp"; } @ExceptionHandler(RuntimeException.class) public String runtimeHandlerException(){ return "redirect:/500.jsp"; } @ExceptionHandler(Exception.class) public ModelAndView customException(Exception e) { ModelAndView mv = new ModelAndView(); mv.addObject("message", e.getMessage()); mv.setViewName("error"); return mv; } }
在該類中,可以定義多個方法,不同的方法處理不同的異常,例如專門處理空指針的方法、專門處理數組越界的方法...,也可以直接像上面最后的代碼一樣,在一個方法中處理所有的異常信息。
@ExceptionHandler 注解用來指明異常的處理類型,即如果這里指定為 NullpointerException,則數組越界異常就不會進到這個方法中來。