基于Spring Boot + Nacos + Dubbo自定義鑒權過濾器實現(xiàn)方案解析
實現(xiàn)說明
整體流程:
- 服務提供者啟動時會注冊到 Nacos,并啟用自定義的
AuthFilter - 客戶端調(diào)用服務前,通過
RpcContext設置鑒權信息(token 和應用名) - 服務端的
AuthFilter會攔截請求,驗證鑒權信息 - 驗證通過則繼續(xù)調(diào)用,否則拋出異常
- 服務提供者啟動時會注冊到 Nacos,并啟用自定義的
關鍵實現(xiàn)點:
- 使用
@Activate注解指定過濾器在服務端生效 - 通過 SPI 機制注冊過濾器
- 在
invoke方法中實現(xiàn)鑒權邏輯 - 利用
RpcContext傳遞和獲取調(diào)用上下文信息
- 使用
動態(tài)配置:
- 進階實現(xiàn)中添加了 Nacos 配置中心客戶端
- 可以動態(tài)獲取和更新鑒權規(guī)則,無需重啟服務
使用時,需要先啟動 Nacos 服務器,然后分別啟動服務提供者和消費者,即可看到鑒權效果。你可以根據(jù)實際業(yè)務需求修改validateToken和hasMethodPermission方法中的鑒權邏輯。
1.自定義鑒權過濾器實現(xiàn)
package com.example.dubbo.filter;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
import org.springframework.stereotype.Component;
/**
* 基于Dubbo SPI的自定義鑒權過濾器
*/
@Activate(group = CommonConstants.PROVIDER, order = 100) // 僅在服務端生效
@Component
public class AuthFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
// 1. 從上下文獲取調(diào)用信息
RpcContext context = RpcContext.getContext();
String token = context.getAttachment("auth_token");
String appName = context.getAttachment("app_name");
String clientIp = context.getRemoteHost();
String methodName = invocation.getMethodName();
// 2. 打印調(diào)用信息
System.out.println("收到調(diào)用請求 - 方法: " + methodName + ", 客戶端IP: " + clientIp + ", 應用名: " + appName);
// 3. 執(zhí)行鑒權邏輯
if (!validateToken(token, appName)) {
throw new RpcException("鑒權失敗: 無效的token或應用名");
}
// 4. 檢查方法級權限
if (!hasMethodPermission(appName, methodName)) {
throw new RpcException("權限不足: 應用" + appName + "沒有調(diào)用" + methodName + "方法的權限");
}
// 5. 鑒權通過,繼續(xù)執(zhí)行調(diào)用
return invoker.invoke(invocation);
}
/**
* 驗證token有效性
*/
private boolean validateToken(String token, String appName) {
// 實際項目中,這里應該從Nacos配置中心或數(shù)據(jù)庫獲取有效token列表
// 簡單示例:驗證token格式和應用名
if (token == null || appName == null) {
return false;
}
// 從Nacos獲取配置的有效應用和token映射關系
// 這里簡化處理,實際應通過NacosConfigService獲取
return "valid_token_123".equals(token) && "authorized_app".equals(appName);
}
/**
* 檢查是否有方法調(diào)用權限
*/
private boolean hasMethodPermission(String appName, String methodName) {
// 實際項目中,這里應該從Nacos配置中心獲取應用與方法的權限映射
// 簡單示例:只有特定應用可以調(diào)用敏感方法
if ("deleteUser".equals(methodName) && !"admin_app".equals(appName)) {
return false;
}
return true;
}
}2.創(chuàng)建 SPI 配置文件,讓 Dubbo 能夠發(fā)現(xiàn)我們的過濾器:
# 注冊自定義鑒權過濾器 authFilter=com.example.dubbo.filter.AuthFilter
3.服務提供者配置
application.yml
spring:
application:
name: dubbo-auth-provider
dubbo:
application:
name: dubbo-auth-provider
registry:
address: nacos://127.0.0.1:8848 # Nacos注冊中心地址
username: nacos # Nacos用戶名
password: nacos # Nacos密碼
protocol:
name: dubbo
port: 20880
provider:
filter: authFilter # 啟用自定義鑒權過濾器
timeout: 3000
# Nacos配置中心
nacos:
config:
server-addr: 127.0.0.1:8848
namespace: public4.服務接口和實現(xiàn)
package com.example.dubbo.service;
public interface UserService {
String getUserInfo(Long id);
String deleteUser(Long id);
}
package com.example.dubbo.service.impl;
import com.example.dubbo.service.UserService;
import org.apache.dubbo.config.annotation.DubboService;
@DubboService(interfaceClass = UserService.class)
public class UserServiceImpl implements UserService {
@Override
public String getUserInfo(Long id) {
return "User info for id: " + id + ", name: testUser";
}
@Override
public String deleteUser(Long id) {
return "User " + id + " deleted successfully";
}
}服務消費者配置和代碼
package com.example.dubbo.consumer;
import com.example.dubbo.service.UserService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.rpc.RpcContext;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class ConsumerApplication {
@DubboReference
private UserService userService;
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
@Bean
public ApplicationRunner runner() {
return args -> {
// 調(diào)用前設置鑒權信息
RpcContext.getContext()
.setAttachment("auth_token", "valid_token_123")
.setAttachment("app_name", "authorized_app");
// 調(diào)用普通方法
String userInfo = userService.getUserInfo(1L);
System.out.println("調(diào)用結(jié)果: " + userInfo);
// 嘗試調(diào)用需要管理員權限的方法
try {
String deleteResult = userService.deleteUser(1L);
System.out.println("刪除結(jié)果: " + deleteResult);
} catch (Exception e) {
System.out.println("調(diào)用deleteUser方法失敗: " + e.getMessage());
}
};
}
}從 Nacos 配置中心獲取鑒權規(guī)則
package com.example.dubbo.config;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
import java.util.concurrent.Executor;
@Configuration
public class NacosConfig {
@Value("${nacos.config.server-addr}")
private String serverAddr;
@Value("${nacos.config.namespace}")
private String namespace;
@Bean
public ConfigService configService() throws NacosException {
Properties properties = new Properties();
properties.put("serverAddr", serverAddr);
properties.put("namespace", namespace);
ConfigService configService = NacosFactory.createConfigService(properties);
// 監(jiān)聽鑒權規(guī)則配置變化
String dataId = "dubbo-auth-rules";
String group = "DEFAULT_GROUP";
configService.addListener(dataId, group, new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
System.out.println("收到新的鑒權規(guī)則配置: " + configInfo);
// 更新本地緩存的鑒權規(guī)則
AuthRuleCache.updateRules(configInfo);
}
@Override
public Executor getExecutor() {
return null;
}
});
// 初始化加載配置
String config = configService.getConfig(dataId, group, 5000);
if (config != null) {
AuthRuleCache.updateRules(config);
}
return configService;
}
}
// 鑒權規(guī)則緩存類
class AuthRuleCache {
private static String authRules;
public static void updateRules(String rules) {
authRules = rules;
// 這里可以解析規(guī)則并存儲到內(nèi)存中
}
public static String getAuthRules() {
return authRules;
}
}到此這篇關于基于 Spring Boot + Nacos + Dubbo 的完整自定義鑒權過濾器實現(xiàn)方案的文章就介紹到這了,更多相關springboot nacos dubbo自定義鑒權過濾器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
mybatis-plus 處理大數(shù)據(jù)插入太慢的解決
這篇文章主要介紹了mybatis-plus 處理大數(shù)據(jù)插入太慢的解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-12-12
淺析SpringBoot整合Mybatis如何實現(xiàn)二級緩存
二級緩存,是指多個Sqlsession之間共享數(shù)據(jù),但是也可以使用Redis這樣的緩存作為存儲點,但是不支持mybatisplus 里的方法,本文我們就來聊聊SpringBoot整合Mybatis實現(xiàn)二級緩存的相關方法吧2025-05-05
spring AOP的Around增強實現(xiàn)方法分析
這篇文章主要介紹了spring AOP的Around增強實現(xiàn)方法,結(jié)合實例形式分析了spring面向切面AOP的Around增強具體步驟與相關操作方法,需要的朋友可以參考下2020-01-01
Java實現(xiàn)創(chuàng)建Zip壓縮包并寫入文件
這篇文章主要為大家詳細介紹了Java實現(xiàn)創(chuàng)建Zip壓縮包并寫入文件,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-01-01

