实现说明
整体流程:
- 服务提供者启动时会注册到 nacos,并启用自定义的
authfilter - 客户端调用服务前,通过
rpccontext设置鉴权信息(token 和应用名) - 服务端的
authfilter会拦截请求,验证鉴权信息 - 验证通过则继续调用,否则抛出异常
- 服务提供者启动时会注册到 nacos,并启用自定义的
关键实现点:
- 使用
@activate注解指定过滤器在服务端生效 - 通过 spi 机制注册过滤器
- 在
invoke方法中实现鉴权逻辑 - 利用
rpccontext传递和获取调用上下文信息
- 使用
动态配置:
- 进阶实现中添加了 nacos 配置中心客户端
- 可以动态获取和更新鉴权规则,无需重启服务
使用时,需要先启动 nacos 服务器,然后分别启动服务提供者和消费者,即可看到鉴权效果。你可以根据实际业务需求修改validatetoken和hasmethodpermission方法中的鉴权逻辑。
1.自定义鉴权过滤器实现
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. 从上下文获取调用信息
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. 打印调用信息
system.out.println("收到调用请求 - 方法: " + methodname + ", 客户端ip: " + clientip + ", 应用名: " + appname);
// 3. 执行鉴权逻辑
if (!validatetoken(token, appname)) {
throw new rpcexception("鉴权失败: 无效的token或应用名");
}
// 4. 检查方法级权限
if (!hasmethodpermission(appname, methodname)) {
throw new rpcexception("权限不足: 应用" + appname + "没有调用" + methodname + "方法的权限");
}
// 5. 鉴权通过,继续执行调用
return invoker.invoke(invocation);
}
/**
* 验证token有效性
*/
private boolean validatetoken(string token, string appname) {
// 实际项目中,这里应该从nacos配置中心或数据库获取有效token列表
// 简单示例:验证token格式和应用名
if (token == null || appname == null) {
return false;
}
// 从nacos获取配置的有效应用和token映射关系
// 这里简化处理,实际应通过nacosconfigservice获取
return "valid_token_123".equals(token) && "authorized_app".equals(appname);
}
/**
* 检查是否有方法调用权限
*/
private boolean hasmethodpermission(string appname, string methodname) {
// 实际项目中,这里应该从nacos配置中心获取应用与方法的权限映射
// 简单示例:只有特定应用可以调用敏感方法
if ("deleteuser".equals(methodname) && !"admin_app".equals(appname)) {
return false;
}
return true;
}
}2.创建 spi 配置文件,让 dubbo 能够发现我们的过滤器:
# 注册自定义鉴权过滤器 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.服务接口和实现
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 -> {
// 调用前设置鉴权信息
rpccontext.getcontext()
.setattachment("auth_token", "valid_token_123")
.setattachment("app_name", "authorized_app");
// 调用普通方法
string userinfo = userservice.getuserinfo(1l);
system.out.println("调用结果: " + userinfo);
// 尝试调用需要管理员权限的方法
try {
string deleteresult = userservice.deleteuser(1l);
system.out.println("删除结果: " + deleteresult);
} catch (exception e) {
system.out.println("调用deleteuser方法失败: " + e.getmessage());
}
};
}
}从 nacos 配置中心获取鉴权规则
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);
// 监听鉴权规则配置变化
string dataid = "dubbo-auth-rules";
string group = "default_group";
configservice.addlistener(dataid, group, new listener() {
@override
public void receiveconfiginfo(string configinfo) {
system.out.println("收到新的鉴权规则配置: " + configinfo);
// 更新本地缓存的鉴权规则
authrulecache.updaterules(configinfo);
}
@override
public executor getexecutor() {
return null;
}
});
// 初始化加载配置
string config = configservice.getconfig(dataid, group, 5000);
if (config != null) {
authrulecache.updaterules(config);
}
return configservice;
}
}
// 鉴权规则缓存类
class authrulecache {
private static string authrules;
public static void updaterules(string rules) {
authrules = rules;
// 这里可以解析规则并存储到内存中
}
public static string getauthrules() {
return authrules;
}
}到此这篇关于基于 spring boot + nacos + dubbo 的完整自定义鉴权过滤器实现方案的文章就介绍到这了,更多相关springboot nacos dubbo自定义鉴权过滤器内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论