websocket中获取客户端通信的真实IP

一些场景中,我们要对websocket客户端的ip进行校验,如果是黑名单,或者不被允许的则不应该让他访问业务系统。

笔者本地使用了两个Websocket技术原型,一个基于Netty封装的Websocket框架:/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

原文地址:https://www.cnblogs.com/passedbylove/p/12177029.html