前言:使用dubbo做为通信组件,如果接口需要鉴权,和日志记录需要怎样处理;
1 鉴权:
1.1 在bootstrap.yml 中定义过滤器:
dubbo.provider.filter: 过滤器的名字:
1.2 resources 目录下创建配置文件:
1) resources 创建目录:/META-INF/dubbo
2) 创建文件名字为org.apache.dubbo.rpc.Filter 的纯文本文件:
3) 定义过滤器:
过滤器名字=过滤器路径地址
4)服务提供端:DubboTokenFilter:
package org.lgx.bluegrass.bluegrasses.dubbofilter;
import org.apache.dubbo.rpc.*;
import org.apache.dubbo.rpc.filter.TokenFilter;
import org.lgx.bluegrass.api.common.dto.ResponseDTO;
import org.lgx.bluegrass.bluegrasses.util.ApplicationContextUtils;
import org.lgx.bluegrass.bluegrasses.util.RedisUtil;
import org.springframework.util.StringUtils;
/**
* @Description TODO
* @Date 2023/3/7 15:38
* @Author lgx
* @Version 1.0
*/
public class DubboTokenFilter extends TokenFilter {
private RedisUtil redisUtil;
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
String isNeedToken = invoker.getUrl().getParameter(Constants.TOKEN_KEY);
// 是否需要进行token 验证
if (StringUtils.hasText(isNeedToken)) {
// 获取消费端传入的token
String clientToken1 = invocation.getAttachment("dubbo_accesstoken");
// 获取服务端的token
String serverToken = getServerToken();
// token验证并且统一封装返回结果
if (!serverToken.equals(clientToken1)) {
// token 异常则直接封装ResponseDTO 并返回
return AsyncRpcResult.newDefaultAsyncResult(ResponseDTO.defaultResponse("token illegal"), invocation);
// 也可以抛出异常
// Class<?> serviceType = invoker.getInterface();
// throw new RpcException("Invalid token! Forbid invoke remote service " + serviceType + " method " + invocation.getMethodName() + "() from consumer " + RpcContext.getContext().getRemoteHost() + " to provider " + RpcContext.getContext().getLocalHost());
}
}
return invoker.invoke(invocation);
}
// 从redis 中获取token 业务自行实现
private String getServerToken() {
if (null == redisUtil) {
redisUtil = (RedisUtil) ApplicationContextUtils.getBean("redisUtil");
}
String accessToken = redisUtil.get("dubbo_accesstoken");
return "1234";
}
}
ResponseDTO 封装类:
// loomback 插件
@Data
@Accessors(chain = true)
public class ResponseDTO<T> implements Serializable {
private static final long serialVersionUID = 3918877423924837166L;
private int code = 200;
private T body;
private String msg;
private boolean redirect = true;
private List<ResponseMessage> messages;
private List<String> message = new ArrayList<>();
private int errNum;
private String errorMsg;
private Object errorObject;
private boolean success = true;
public static <T> ResponseDTO defaultResponse(T t) {
return new ResponseDTO().setCode(BizHttpStatus.HTTP_STATUS_200.getStatus()).setBody(t);
}
}
RedisUtil 封装类:stringRedisTemplate bean 自行配置实现
@Component
public class RedisUtil {
@Autowired
@Qualifier("stringRedisTemplate")
private StringRedisTemplate redisTemplate;
public void setRedisTemplate(StringRedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
public StringRedisTemplate getRedisTemplate() {
return this.redisTemplate;
}
/**
* 获取指定 key 的值
*
* @param key
* @return
*/
public String get(String key) {
return redisTemplate.opsForValue().get(key);
}
/**
* 设置指定 key 的值
*
* @param key
* @param value
*/
public void set(String key, String value) {
redisTemplate.opsForValue().set(key, value);
}
}
服务业务类提供者:
DubboTestServiceImpl:
import org.apache.dubbo.config.annotation.DubboService;
import org.lgx.bluegrass.api.common.dto.ResponseDTO;
import org.lgx.bluegrass.api.service.DubboTestService;
/**
* @Description TODO
* @Date 2023/2/23 15:50
* @Author lgx
* @Version 1.0
*/
// dubbo 服务暴露标识,token = "1234" 定义token验证标识
@DubboService(token = "1234")
public class DubboTestServiceImpl implements DubboTestService {
@Override
public ResponseDTO test(String token) {
return ResponseDTO.defaultResponse("hello es"+ token);
}
}
服务定义:DubboThreeService:
public interface DubboThreeService {
ResponseDTO testOne(String token);
}
5) 消费端:同服务提供端1),2),3),相同 ,定义好过滤器
定义消费端token 填充:
DubboTokenFilter
public class DubboTokenFilter implements Filter {
private RedisUtil redisUtil;
@Override
public Result invoke(Invoker<?> invoker, Invocation inv) throws RpcException {
if (null == redisUtil) {
Object obj = ApplicationContextUtils.getBean("redisUtil");
if (null != obj){
redisUtil = (RedisUtil) obj;
}
}
String isNeedToken = invoker.getUrl().getParameter(Constants.TOKEN_KEY);
// 是否需要进行token 验证
if (StringUtils.hasText(isNeedToken)) {
// Constants.TOKEN_KEY, "1234", 便于跳过duboo 内置的token 验证
// "1234" 对应服务提供端业务实现类中定义的token @DubboService(token = "1234")
inv.setAttachment(Constants.TOKEN_KEY, "1234");
// 设置本次真正需要验证的token
inv.setAttachment("dubbo_accesstoken", "1234qazwsxedc");
}
// 远程接口调用
return invoker.invoke(inv);
}
}
6 ) 消费端测试:
@RestController
public class DubboRpcController {
@DubboReference
private DubboTestService dubboTestService;
@RequestMapping(value = "/dubbo-test", method = RequestMethod.GET)
public String index(@RequestParam("token") String token) {
return dubboTestService.test(token).toString();
}
}
2 日志记录:
DubboAccessLogFilter:
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.ConfigUtils;
import org.apache.dubbo.rpc.*;
import org.apache.dubbo.rpc.support.AccessLogData;
import java.util.Date;
/**
* @Description TODO
* @Date 2023/3/8 16:48
* @Author lgx
* @Version 1.0
*/
public class DubboAccessLogFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(DubboAccessLogFilter.class);
@Override
public Result invoke(Invoker<?> invoker, Invocation inv) throws RpcException {
try {
// 是否需要对改接口进行日志记录
String accessLogKey = invoker.getUrl().getParameter("accesslog");
if (ConfigUtils.isNotEmpty(accessLogKey)) {
// 请求的数据
AccessLogData logData = this.buildAccessLogData(invoker, inv);
// save log
saveLog(logData);
}
} catch (Throwable var5) {
logger.warn("Exception in AccessLogFilter of service(" + invoker + " -> " + inv + ")", var5);
}
return invoker.invoke(inv);
}
// 自行实现数据的保存
private void saveLog(AccessLogData logData) {
}
private AccessLogData buildAccessLogData(Invoker<?> invoker, Invocation inv) {
AccessLogData logData = AccessLogData.newLogData();
logData.setServiceName(invoker.getInterface().getName());
logData.setMethodName(inv.getMethodName());
logData.setVersion(invoker.getUrl().getParameter("version"));
logData.setGroup(invoker.getUrl().getParameter("group"));
logData.setInvocationTime(new Date());
logData.setTypes(inv.getParameterTypes());
logData.setArguments(inv.getArguments());
return logData;
}
}
服务业务提供端:
// accesslog 日志记录标识
@DubboService(accesslog = "123")
public class DubboTestServiceTwoImpl implements DubboTestTwoService {
@Override
public ResponseDTO sayHello() {
Map<String,Object> result = new HashMap<>(1<<2);
result.put("data","Hello !");
result.put("success",true);
result.put("code",200);
return ResponseDTO.defaultResponse(result);
}
}
3 数据统一封装:
AppendedFilter:
import org.apache.dubbo.rpc.*;
import org.lgx.bluegrass.api.common.dto.ResponseDTO;
/**
* @Description TODO
* @Date 2023/3/7 11:00
* @Author lgx
* @Version 1.0
*/
public class AppendedFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
Result result = invoker.invoke(invocation);
Result appResponse = ((AsyncRpcResult) result).getAppResponse();
Object data = appResponse.getValue();
if (data instanceof ResponseDTO) {
return result;
}
// 统一进行ResponseDTO 格式数据封装返回
appResponse.setValue(ResponseDTO.defaultResponse(data));
return result;
}
}
参考:
1 调用拦截扩展;