Java項目接口權限校驗的靈活實現

引言

在Java Web開發中,接口權限校驗是保護系統資源安全的關鍵機制。本文將介紹一種靈活、可配置的接口權限校驗方案,通過注解驅動和攔截器實現,既能保證安全性,又能靈活控制哪些接口需要校驗。

設計思路

實現方案的核心設計要點:

  1. 注解驅動:使用自定義注解標記需要權限校驗的接口
  2. 攔截器機制:在請求處理前進行統一權限校驗
  3. 靈活配置:支持方法級和類級配置,可動態調整
  4. 權限緩存:提高權限驗證效率

在這里插入圖片描述

實現步驟

1. 定義權限校驗注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PermissionCheck {/*** 權限標識,支持多個權限(滿足任意一個即可)*/String[] value() default {};/*** 是否開啟權限校驗(默認開啟)*/boolean enabled() default true;/*** 邏輯關系:AND-需滿足所有權限,OR-滿足任意權限*/Logical logical() default Logical.OR;
}public enum Logical {AND, OR
}

2. 實現權限校驗攔截器

@Component
public class PermissionInterceptor implements HandlerInterceptor {@Autowiredprivate PermissionService permissionService;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 如果不是Controller方法直接放行if (!(handler instanceof HandlerMethod)) {return true;}HandlerMethod handlerMethod = (HandlerMethod) handler;Method method = handlerMethod.getMethod();// 獲取方法上的注解PermissionCheck methodAnnotation = method.getAnnotation(PermissionCheck.class);// 獲取類上的注解PermissionCheck classAnnotation = method.getDeclaringClass().getAnnotation(PermissionCheck.class);// 1. 如果方法上明確關閉權限校驗if (methodAnnotation != null && !methodAnnotation.enabled()) {return true;}// 2. 如果類上關閉權限校驗且方法未指定if (classAnnotation != null && !classAnnotation.enabled() && (methodAnnotation == null || methodAnnotation.enabled())) {return true;}// 3. 獲取當前用戶權限User currentUser = getCurrentUser(request);if (currentUser == null) {response.sendError(HttpStatus.UNAUTHORIZED.value(), "用戶未登錄");return false;}// 4. 獲取需要的權限Set<String> requiredPermissions = getRequiredPermissions(methodAnnotation, classAnnotation);// 5. 無需權限校驗if (requiredPermissions.isEmpty()) {return true;}// 6. 檢查權限boolean hasPermission = checkPermissions(currentUser, requiredPermissions, methodAnnotation != null ? methodAnnotation.logical() : (classAnnotation != null ? classAnnotation.logical() : Logical.OR));if (!hasPermission) {response.sendError(HttpStatus.FORBIDDEN.value(), "權限不足");return false;}return true;}private Set<String> getRequiredPermissions(PermissionCheck methodAnnotation, PermissionCheck classAnnotation) {Set<String> permissions = new HashSet<>();// 方法注解優先if (methodAnnotation != null && methodAnnotation.value().length > 0) {Collections.addAll(permissions, methodAnnotation.value());return permissions;}// 類注解if (classAnnotation != null && classAnnotation.value().length > 0) {Collections.addAll(permissions, classAnnotation.value());}return permissions;}private boolean checkPermissions(User user, Set<String> requiredPermissions, Logical logical) {// 獲取用戶實際權限(可從緩存中獲取)Set<String> userPermissions = permissionService.getUserPermissions(user.getId());if (logical == Logical.AND) {return userPermissions.containsAll(requiredPermissions);} else {return requiredPermissions.stream().anyMatch(userPermissions::contains);}}
}

3. 注冊攔截器

@Configuration
public class WebConfig implements WebMvcConfigurer {@Autowiredprivate PermissionInterceptor permissionInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(permissionInterceptor).addPathPatterns("/api/**")  // 攔截API路徑.excludePathPatterns("/api/public/**"); // 排除公共接口}
}

4. 權限服務實現

@Service
public class PermissionServiceImpl implements PermissionService {@Autowiredprivate PermissionMapper permissionMapper;@Autowiredprivate CacheManager cacheManager;@Overridepublic Set<String> getUserPermissions(Long userId) {// 從緩存獲取Cache cache = cacheManager.getCache("userPermissions");Cache.ValueWrapper wrapper = cache.get(userId);if (wrapper != null) {return (Set<String>) wrapper.get();}// 從數據庫查詢Set<String> permissions = permissionMapper.selectPermissionsByUserId(userId);// 放入緩存cache.put(userId, permissions);return permissions;}
}

使用示例

1. 類級別權限控制

@RestController
@RequestMapping("/users")
@PermissionCheck(value = {"USER_MANAGE"}, logical = Logical.AND)
public class UserController {// 需要USER_MANAGE權限@GetMappingpublic List<User> listUsers() {// ...}// 不需要權限校驗(覆蓋類級別設置)@PermissionCheck(enabled = false)@GetMapping("/public")public User getPublicUser() {// ...}
}

2. 方法級別權限控制

@RestController
@RequestMapping("/products")
public class ProductController {// 需要PRODUCT_READ權限@PermissionCheck("PRODUCT_READ")@GetMappingpublic List<Product> listProducts() {// ...}// 需要同時具備PRODUCT_WRITE和PRODUCT_MANAGE權限@PermissionCheck(value = {"PRODUCT_WRITE", "PRODUCT_MANAGE"}, logical = Logical.AND)@PostMappingpublic Product createProduct(@RequestBody Product product) {// ...}
}

3. 公共接口(無需權限)

@RestController
@RequestMapping("/public")
public class PublicController {// 無需任何權限校驗@GetMapping("/info")public SystemInfo getSystemInfo() {// ...}
}

進階優化

1. 動態權限配置

可將權限配置存儲在數據庫中,實現動態管理:

CREATE TABLE api_permission (id BIGINT PRIMARY KEY AUTO_INCREMENT,api_path VARCHAR(255) NOT NULL,http_method VARCHAR(10) NOT NULL,permission_code VARCHAR(50) NOT NULL,enabled BOOLEAN DEFAULT true,UNIQUE KEY uni_api_method (api_path, http_method)
);

在攔截器中增加數據庫權限檢查邏輯:

// 在PermissionInterceptor中增加
private boolean checkDynamicPermission(String path, String method) {List<String> requiredPermissions = permissionService.getPermissionsForApi(path, method);if (requiredPermissions.isEmpty()) {return true; // 無配置表示不需要權限}// 檢查用戶權限...
}

2. 權限緩存策略

使用Redis緩存用戶權限數據,提高性能:

@Configuration
public class RedisConfig {@Beanpublic RedisCacheManager cacheManager(RedisConnectionFactory factory) {RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(30))  // 30分鐘過期.disableCachingNullValues();return RedisCacheManager.builder(factory).cacheDefaults(config).build();}
}@Service
public class RedisPermissionService implements PermissionService {@Autowiredprivate RedisTemplate<String, Set<String>> redisTemplate;@Overridepublic Set<String> getUserPermissions(Long userId) {String key = "user:permissions:" + userId;Set<String> permissions = redisTemplate.opsForSet().members(key);if (permissions == null || permissions.isEmpty()) {// 從數據庫加載permissions = permissionMapper.selectPermissionsByUserId(userId);if (!permissions.isEmpty()) {redisTemplate.opsForSet().add(key, permissions.toArray(new String[0]));redisTemplate.expire(key, 30, TimeUnit.MINUTES);}}return permissions;}
}

方案對比

實現方式優點缺點適用場景
攔截器+注解靈活、非侵入、配置簡單無法動態修改中小型項目
動態數據庫配置可動態調整、集中管理增加數據庫訪問、實現復雜大型復雜系統
AOP實現解耦徹底、可復用性高配置復雜、學習曲線陡峭需要高度解耦的系統

總結

本文介紹了一種基于注解和攔截器的接口權限校驗方案,具有以下特點:

  1. 靈活配置:通過注解控制每個接口的權限要求
  2. 非侵入式:不影響業務邏輯代碼
  3. 層次分明:支持類級別和方法級別的權限控制
  4. 易于擴展:可結合數據庫實現動態權限管理
  5. 性能優化:通過緩存減少權限查詢開銷

通過合理的權限校驗實現,可以大大提高系統的安全性,同時保持代碼的整潔和可維護性。根據項目需求,可以選擇合適的實現方式和優化策略。

提示:在實際項目中,建議結合Spring Security或Shiro等安全框架,可以更全面地解決認證授權問題。本文方案適用于需要輕量級權限控制的場景。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/93357.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/93357.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/93357.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

瀚高DB兼容MySQL if函數

文章目錄環境癥狀問題原因解決方案環境 系統平臺&#xff1a;Linux x86-64 Red Hat Enterprise Linux 7 版本&#xff1a;4.5 癥狀 MySQL if函數在瀚高DB當中沒有&#xff0c;源應用在用到if函數時&#xff0c;就會報if函數不存在的錯誤信息。為此&#xff0c;我們需要根據業…

基于深度學習的胸部 X 光圖像肺炎分類系統(六)

目錄 結果指標解讀 一、為什么選擇這些指標&#xff1f; 二、各指標的定義和解讀 1. 準確率&#xff08;Accuracy&#xff09; 2. 損失&#xff08;Loss&#xff09; 3. 精確率&#xff08;Precision&#xff09; 4. 召回率&#xff08;Recall&#xff09; 三、這些指標…

區塊鏈性能優化策略:從理論到實踐

目錄 區塊鏈性能優化策略:從理論到實踐 1. 引言:區塊鏈性能的挑戰 2. 性能評估指標 2.1 核心性能指標 2.2 性能瓶頸分析 3. 分層優化策略 3.1 網絡層優化 3.1.1 Gossip協議改進 3.1.2 網絡分片 3.2 共識層優化 3.2.1 PBFT優化 3.3 數據層優化 3.3.1 狀態樹優化 3.3.2 區塊數據…

【VLLM】open-webui部署模型全流程

目錄 前言 一、租用服務器到服務器連接VScode全流程(可選) 二、下載模型到本地服務器 2.1 進入魔塔社區官網 2.2 選擇下載模型 2.3 執行下載 三、部署VLLM 3.1 參考vllm官網文檔 3.2 查看硬件要求 3.3 安裝vLLM框架 3.4 啟動模型服務 方法1:直接啟動下載的本地模…

辦公自動化入門:如何高效將圖片整合為PDF文檔

將多張圖片合并到一個PDF文件中可以幫助保持特定的順序和布局&#xff0c;同時確保圖像的質量不會因為格式轉換而下降。它是免費&#xff0c;不限次數&#xff0c;批量導入也毫無壓力。操作堪比發朋友圈&#xff1a;拖圖進來 → 選個紙張尺寸 → 點擊轉換 → 指定保存路徑&…

使用寶塔面板搭建 PHP 環境開發一個簡單的 PHP 例子

目錄一、引言二、準備工作2.1 服務器選擇2.2 下載安裝寶塔面板三、使用寶塔面板搭建 PHP 環境3.1 登錄寶塔面板3.2 選擇 Web Server3.3 安裝 PHP3.4 安裝 MySQL 數據庫四、開發一個簡單的 PHP 例子4.1 創建 PHP 文件4.2 編寫 PHP 代碼4.3 設置站點4.4 訪問 PHP 頁面五、常見問題…

AWS WebRTC:我們的業務模式

拉流、卡錄基本流程 設備端&#xff08;攝像機&#xff09; 與 App端 是通過 AWS KVS WebRTC 信令服務進行“點對點連接”的&#xff0c;真正的媒體數據&#xff08;音視頻&#xff09;是通過 WebRTC 的 ICE 通道&#xff08;P2P 或 TURN&#xff09;直接傳輸的&#xff0c;而不…

使用Python,OpenCV,K-Means聚類查找圖像中最主要的顏色

使用Python&#xff0c;OpenCV&#xff0c;K-Means聚類查找圖像中最主要的顏色 分別把跑圖聚類選取1, 2, 3&#xff0c;4, 5, 6, 7&#xff0c;8, 9種主要顏色并繪制colormap顏色圖; 效果圖 分別把跑圖聚類選取3&#xff0c;4, 5&#xff0c;7&#xff0c;9種主要顏色并繪制…

DBAPI 實現分頁查詢的兩種方法

DBAPI 實現分頁查詢的兩種方法 背景 在進行分頁查詢時&#xff0c;用戶通常需要傳入當前頁碼 pageNo 和每頁顯示的條數 pageSize 參數。根據這兩個參數&#xff0c;我們可以從數據庫中查詢出當前頁的數據。以 MySQL 為例&#xff0c;分頁查詢的 SQL 語句如下&#xff1a; se…

第五天上課 SSLPolicy策略和Network Discovery技術

SSL Policy場景1:擁有自家服務器的私鑰&#xff0c;解密訪問自家服務器的ssl流量場景2: 內部用戶訪問互聯網的ssl流量&#xff0c;需要解密并重簽名Correlation and Compliance相關性與合規性配置相關性與合規性策略&#xff0c;在10.1.1.0/24網絡中&#xff0c;當通過Network …

進階07:C#與通用OPC UA通信范例

本節目標&#xff1a; 1&#xff09;安裝軟件&#xff0c;搭建虛擬OPC UA服務器&#xff1b; 2&#xff09;使用UaExpert&#xff0c;讀取OPC UA服務器中的變量&#xff1b; 3&#xff09;編寫Winform程序&#xff0c;讀寫服務器中變量值&#xff0c;創建訂閱觸發事件&#…

大模型微調學習筆記(基于訊飛星辰MaaS速學版)

文章目錄參考資料說明大模型微調入門微調簡介微調步驟數據準備模型選擇訓練方式效果評估模型部署大模型微調&#xff08;基于訊飛星辰Maas&#xff09;構建數據集方法1&#xff1a;預置數據集方法2&#xff1a;創建數據集數據輔助工具數據集劃分模型微調數據配置參數配置模型部…

[CSS]讓overflow不用按shift可以滾輪水平滾動(純CSS)

前言 我不爽前端無法直接滾輪橫向滾動很久了 明明瀏覽器可以直接判斷 x滾動且y不滾動的時候滾輪事件可以直接操作橫向滾動 這個是我探究出來的方法,尤其適合這種很多很多小tag的情況解析 原理是將豎向排列的overflow旋轉成橫向,實際操作的還是豎向overflow.繼而實現鼠標滾輪不用…

截稿倒計時 TrustCom‘25大會即將召開

會議資訊IEEE TrustCom-2025&#xff08;第24屆IEEE計算與通信領域信任、安全與隱私國際會議&#xff09;是一個展示可信計算、通信、網絡和機器學習領域前沿成果的學術平臺。會議聚焦計算機系統、網絡及人工智能在信任、安全、隱私、可靠性、可依賴性、生存性、可用性和容錯性…

Day4.AndroidAudio初始化

1.AudioServer初始化 AudioServer 是 Android 音頻系統的核心服務&#xff0c;負責管理音頻硬件資源、音頻策略調度、跨進程音頻通信等核心功能。它由 Init 進程啟動&#xff0c;是系統核心服務之一&#xff0c;直接影響音頻播放、錄音、音效處理等功能的正常運行。 1.1AudioSe…

OSPF 協議(多區域)

1. OSPF 單區域存在的問題① LSDB龐大&#xff0c;占用內存大&#xff0c;SPF計算開銷大&#xff1b;② LSA洪泛范圍大&#xff0c;拓撲變化影響范圍大&#xff1b;③ 路由不能被匯總&#xff0c;路由表龐大&#xff0c;查找路由開銷大。2. OSPF 多區域優點① 每個區域獨立存儲…

R 語言繪制六種精美熱圖:轉錄組數據可視化實踐(基于 pheatmap 包)

在轉錄組 Bulk 測序數據分析中&#xff0c;熱圖是展示基因表達模式、樣本聚類關系的核心可視化工具。一張高質量的熱圖不僅能清晰呈現數據特征&#xff0c;更能提升研究成果的展示效果。本文基于 R 語言的pheatmap包&#xff0c;整理了六種適用于不同場景的熱圖繪制方法&#x…

圖片PDF識別工具:掃描PDF文件批量OCR區域圖識別改名,識別大量PDF區域內容一次性改名

以下是使用“咕嘎批量OCR識別圖片PDF多區域內容重命名導出表格系統”進行操作的具體步驟&#xff1a;1. 打開工具并獲取區域坐標打開軟件后&#xff0c;選擇“PDF識別模式”。導入一個PDF文件作為樣本&#xff0c;框選需要提取文字的區域&#xff0c;并保存區域坐標。如果有多個…

中國汽車能源消耗量(2010-2024年)

1419中國汽車能源消耗量&#xff08;2010-2024年&#xff09;發文主題分布數據來源中華人民共和國工業和信息化部-中國汽車能源消耗量查詢中國汽車能源消耗量查詢 (miit.gov.cn)時間跨度2010-2024年數據范圍全國汽車企業數據指標本數據集包含包含傳統汽車能源消耗量數據以及新能…

Python 實現服務器自動故障處理工具:從監控到自愈的完整方案

在服務器運維過程中,80% 的故障都是重復性的簡單問題(如磁盤空間不足、內存泄漏、服務進程掛掉等)。本文將介紹如何使用 Python 開發一款輕量級自動故障處理工具,通過狀態監控、異常診斷、自動修復三個核心模塊,實現服務器常見故障的無人值守處理。 核心依賴庫 psutil:跨…