一些场景中,我们要对websocket客户端的ip进行校验,如果是黑名单,或者不被允许的则不应该让他访问业务系统。
笔者本地使用了两个Websocket技术原型,一个基于Netty封装的Websocket框架:YeautyYE/netty-websocket-spring-boot-starter
另外一个是基于JSR-356 Java Api for websocket实现的框架,实现的客户端很多,比如tomcat,spring也有对应的支持。
表达式获得方法
因为使用Ognl解析对象时,会把对象数据放入一棵树,在任意调试窗口监控可以查看到类及属性的层次关系。
比如查询Ip地址,我们这里选择的树路径是
#root->channel->remoteAddress
他返回的对象时InetSocketAddress的实例,得到这个对象后,你可以调用
.getAddress().getHostAddress()
方法获得最终的ip真实地址,当然你也可以使用其他表达式来获得
#root.channel.remoteAddress.holder.addr.holder.hostName
#root.channel.remoteAddress.holder.addr.hostName
这些表达式需要你自己去评估计算。
netty-websocket-spring-boot-starter
封装代码如下:
import lombok.extern.slf4j.Slf4j;
import ognl.DefaultMemberAccess;
import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
import org.yeauty.pojo.Session;
@Slf4j
public final class NettyWebsocketHelper {
private NettyWebsocketHelper() {
}
private static OgnlContext context = new OgnlContext();
/**
* set DefaultMemberAccess with allowed access into the context
*/
static {
context.setMemberAccess(new DefaultMemberAccess(true));
}
public static String getRemoteAddress(final Session session) {
//.getAddress().getHostAddress()
//.holder.addr.hostName
//.holder.addr.holder.address
//.holder.addr.holder.hostName
//return (String) eval(session,"#root.channel.remoteAddress");
return eval(session, "#root.channel.remoteAddress.getAddress().getHostAddress()", String.class);
}
public static <T> T eval(final Object source, final String expression, Class<T> targetClass) {
try {
return (T) Ognl.getValue(expression, context, source);
} catch (OgnlException e) {
log.error("评估表达式出错:{}", e);
throw new IllegalAccessError("expression invalid");
}
}
public static Object eval(final Object source, final String expression) {
Object value = null;
try {
value = Ognl.getValue(expression, context, source);
log.info("return value :{}, class.name:{}", value, value.getClass().getName());
} catch (OgnlException e) {
log.error("评估表达式出错:{}", e);
}
return value;
}
}
使用方法:
/***
* 登录ws服务器
* @param session
* @param appId
* @param apiKey
* @throws InterruptedException
*/
private void onLogin(Session session, String appId, String apiKey) {
String remoteAddress = NettyWebsocketHelper.getRemoteAddress(session);
ApiService service = apiService.getService(appId, apiKey);
if (Objects.isNull(service)) {
session.sendText("appid无效");
session.close();
return;
}
final String serviceType = service.getServiceType();
final Integer serviceId = service.getId();
log.info("远程IP:{}正在尝试登录到api服务器", remoteAddress);
if (!checkWhiteList(serviceId, remoteAddress)) {
session.sendText("禁止调用API接口的IP:".concat(remoteAddress));
session.close();
return;
}
}
调用结果
2020-1-15日更新:
参考:https://stackoverflow.com/questions/22690907/client-socket-get-ip-java
/***
* 登录ws服务器
* @param session
* @param appId
* @param apiKey
* @throws InterruptedException
*/
private void onLogin(Session session, String appId, String apiKey) {
String ip = resolveRemoteIp(session.remoteAddress());
log.info("远程IP地址:{}",ip);
}
String resolveRemoteIp(SocketAddress socketAddress)
{
if (socketAddress instanceof InetSocketAddress) {
InetAddress inetAddress = ((InetSocketAddress)socketAddress).getAddress();
if (inetAddress instanceof Inet4Address) {
log.info("IPv4:{}",inetAddress);
return inetAddress.getHostAddress();
}else if (inetAddress instanceof Inet6Address) {
log.info("IPv6:{}",inetAddress);
}else {
log.error("Not an IP address.");
return null;
}
} else {
log.error("Not an internet protocol socket.");
}
return null;
}
JSR356
标签:return,String,remoteAddress,IP,session,log,websocket,holder,客户端 From: https://blog.51cto.com/u_296714/5754711