springboot + 攔截器 + 注解 實現自定義權限驗證
最近用到一種前端模板技術:jtwig,在權限控制上沒有用springSecurity。因此用攔截器和注解結合實現了權限控制。
1.1 定義權限常量 PermissionConstants.java
public class PermissionConstants { /** * 管理員-產品列表查詢 */ public static final String ADMIN_PRODUCT_LIST = "admin_product_list"; /** * 管理員-產品詳情 */ public static final String ADMIN_PRODUCT_DETAIL = "admin_product_detail"; }
- 權限也可以不定義為常量,看項目情況
1.2 定義權限的注解 RequiredPermission.java
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface RequiredPermission { String value(); }
- ElementType.TYPE,ElementType.METHOD表示注解可以標記類和方法
1.3 權限攔截器 SecurityInterceptor.java
public class SecurityInterceptor implements HandlerInterceptor { @Autowired private AdminUserService adminUserService; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 驗證權限 if (this.hasPermission(handler)) { return true; } // null == request.getHeader("x-requested-with") TODO 暫時用這個來判斷是否為ajax請求 // 如果沒有權限 則拋403異常 springboot會處理,跳轉到 /error/403 頁面 response.sendError(HttpStatus.FORBIDDEN.value(), "無權限"); return false; } /** * 是否有權限 * * @param handler * @return */ private boolean hasPermission(Object handler) { if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; // 獲取方法上的注解 RequiredPermission requiredPermission = handlerMethod.getMethod().getAnnotation(RequiredPermission.class); // 如果方法上的注解為空 則獲取類的注解 if (requiredPermission == null) { requiredPermission = handlerMethod.getMethod().getDeclaringClass().getAnnotation(RequiredPermission.class); } // 如果標記了注解,則判斷權限 if (requiredPermission != null && StringUtils.isNotBlank(requiredPermission.value())) { // redis或數據庫 中獲取該用戶的權限信息 並判斷是否有權限 Set<String> permissionSet = adminUserService.getPermissionSet(); if (CollectionUtils.isEmpty(permissionSet) ){ return false; } return permissionSet.contains(requiredPermission.value()); } } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // TODO } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // TODO } }
1.4 攔截器注入的配置 MVCConfig.java
@Configuration public class MVCConfig extends WebMvcConfigurerAdapter { @Bean public SecurityInterceptor securityInterceptor() { return new SecurityInterceptor(); } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(securityInterceptor()).excludePathPatterns("/static/*") .excludePathPatterns("/error").addPathPatterns("/**"); } }
- springboot中注入攔截器
1.5 ProductController.java
@Controller @RequestMapping("/product") // @PermissionConstants.ADMIN_PRODUCT_MANAGEMENT public class ProductController { /** * 產品列表 * * @return */ @RequestMapping("/list") @RequiredPermission(PermissionConstants.ADMIN_PRODUCT_LIST) // 權限注解 public String list() { // 省略產品列表查詢邏輯 return "/product/list"; } /** * 產品詳情 * * @return */ @RequestMapping("/detail") @RequiredPermission(PermissionConstants.ADMIN_PRODUCT_DETAIL) // 權限注解 public String detail() { // 省略查詢產品詳情的邏輯 return "/product/edit"; } /** * 刪除產品 * * @return */ @RequestMapping("/delete") public String delete() { // 省略刪除產品的邏輯 return "/product/list"; } }
- 如果沒有標記權限注解,則不會驗證該請求的權限,如/product/delete 請求
